using System.IO; using System.Text.RegularExpressions; using Xunit; namespace Paca.Tests.Platform; /// /// Avalonia 크로스플랫폼 셸 회귀 방지 게이트 테스트 (Phase 5). /// AVLN5001 경고 회귀 방어, MVVM 데이터 바인딩 무결성, URL 분류 로직 검증. /// public class AvaloniaShellGateTests { private static string GetSolutionRoot() { var dir = AppContext.BaseDirectory; while (!string.IsNullOrEmpty(dir) && !File.Exists(Path.Combine(dir, "Paca.slnx")) && !File.Exists(Path.Combine(dir, "Paca.sln"))) { var parent = Directory.GetParent(dir); if (parent == null) break; dir = parent.FullName; } return dir ?? AppContext.BaseDirectory; } private static string AvaloniaProjectDir => Path.Combine(GetSolutionRoot(), "src", "Paca.Avalonia"); [Fact] public void Gate_MainWindow_Axaml_Complies_With_Modern_Avalonia_Standards() { var axamlPath = Path.Combine(AvaloniaProjectDir, "MainWindow.axaml"); Assert.True(File.Exists(axamlPath), $"MainWindow.axaml must exist at {axamlPath}"); var axamlContent = File.ReadAllText(axamlPath); // AVLN5001 방어: Obsolete Watermark 속성 사용 금지 Assert.DoesNotContain("Watermark=", axamlContent); // PlaceholderText 속성 사용 확인 Assert.Contains("PlaceholderText=", axamlContent); // 핵심 MVVM 바인딩 요소 존재 검증 Assert.Contains("{Binding Url", axamlContent); Assert.Contains("{Binding Status", axamlContent); Assert.Contains("{Binding Progress", axamlContent); Assert.Contains("{Binding DownloadCommand}", axamlContent); Assert.Contains("{Binding CancelCommand}", axamlContent); } [Fact] public void Gate_MainViewModel_Contains_All_Required_Contracts() { var vmPath = Path.Combine(AvaloniaProjectDir, "MainViewModel.cs"); Assert.True(File.Exists(vmPath), $"MainViewModel.cs must exist at {vmPath}"); var vmContent = File.ReadAllText(vmPath); // INotifyPropertyChanged 구현 및 RelayCommand 검증 Assert.Contains("INotifyPropertyChanged", vmContent); Assert.Contains("RelayCommand", vmContent); Assert.Contains("DownloadCommand", vmContent); Assert.Contains("CancelCommand", vmContent); Assert.Contains("DownloadByKindAsync", vmContent); Assert.Contains("Classify", vmContent); // 4대 스트림 타입 분기 검증 Assert.Contains("Kind.Social", vmContent); Assert.Contains("Kind.Hls", vmContent); Assert.Contains("Kind.Dash", vmContent); Assert.Contains("Kind.Direct", vmContent); } [Theory] [InlineData("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "Social")] [InlineData("https://youtu.be/dQw4w9WgXcQ", "Social")] [InlineData("https://instagram.com/reel/123456", "Social")] [InlineData("https://tiktok.com/@user/video/12345", "Social")] [InlineData("https://x.com/user/status/12345", "Social")] [InlineData("https://twitter.com/user/status/12345", "Social")] [InlineData("https://example.com/video/master.m3u8", "Hls")] [InlineData("https://example.com/stream/manifest.mpd", "Dash")] [InlineData("https://example.com/files/video.mp4", "Direct")] public void Gate_Url_Classification_Matches_Expected_Kind(string rawUrl, string expectedKind) { var uri = new Uri(rawUrl); var actualKind = Paca.Avalonia.MainViewModel.Classify(uri).ToString(); Assert.Equal(expectedKind, actualKind); } }