using System.Collections.ObjectModel; using System.IO; using Paca.App.Browser.Features; using Paca.App.Core; using Paca.App.ViewModels; using Paca.Browser; using Paca.Browser.Tabs; using Paca.Core.Config; using Paca.Core.Detection; namespace Paca.Tests.Infrastructure; /// /// 19차 핵심 시나리오 파이프라인 프레임워크: /// 다운로드 엔진, 탭 세션, 재생목록, 미디어 감지 파이프라인의 종단간 생명주기를 /// Fluent DSL로 간결하고 강력하게 테스트할 수 있는 프레임워크. /// public sealed class AppScenarioPipeline : IDisposable { public string TempDir { get; } public AppConfig Config { get; } public DownloadManager DownloadManager { get; } public MediaPlaylist Playlist { get; } public TabManager TabManager { get; } public List DetectedItems { get; } = new(); private AppScenarioPipeline() { TempDir = Path.Combine(Path.GetTempPath(), "VD_Test_" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(TempDir); Environment.SetEnvironmentVariable("VD_DATA_DIR", TempDir); Config = new AppConfig { OutputFolder = Path.Combine(TempDir, "downloads"), RestoreSession = true, PlaylistLoopMode = "all" }; Directory.CreateDirectory(Config.OutputFolder); DownloadManager = new DownloadManager( Config, _ => Task.FromResult(new List()), _ => { }); DownloadManager.ItemDetected += item => DetectedItems.Add(item); Playlist = new MediaPlaylist(); TabManager = new TabManager(() => new TabItem(), _ => { }); } public static AppScenarioPipeline Create() => new(); public AppScenarioPipeline SimulateMediaDetection(string url, MediaKind kind, string? pageUrl = null) { DownloadManager.OnDetected(new DetectionContext(url, pageUrl ?? "https://test.local", kind)); return this; } public AppScenarioPipeline AddPlaylistTrack(string url, string title, string kind) { Playlist.Add(new MediaTrack(url, title, kind, DateTime.UtcNow)); return this; } public AppScenarioPipeline SimulateNextTrack() { Playlist.Next(); return this; } public AppScenarioPipeline SimulateTrackPlayed(MediaTrack track) { Playlist.MarkPlayed(track); return this; } public AppScenarioPipeline OpenTab(string url) { TabManager.NewTab(url); return this; } public SessionSnapshot SaveSession() => TabManager.CaptureSession(); public AppScenarioPipeline RestoreSession(SessionSnapshot snapshot) { TabManager.RestoreSession(snapshot); return this; } public void AssertQueueCount(int count) { Xunit.Assert.Equal(count, DownloadManager.Items.Count); } public void AssertDetectedCount(int count) { Xunit.Assert.Equal(count, DetectedItems.Count); } public AppScenarioPipeline SetScheduleGate(Func gate) { DownloadManager.DownloadGate = gate; return this; } public AppScenarioPipeline SelectItems(Func predicate) { foreach (var item in DownloadManager.Items) { item.IsSelected = predicate(item); } return this; } public AppScenarioPipeline BatchPause() { foreach (var item in DownloadManager.Items.Where(i => i.IsSelected).ToList()) { DownloadManager.Pause(item); } return this; } public AppScenarioPipeline BatchResume() { foreach (var item in DownloadManager.Items.Where(i => i.IsSelected).ToList()) { DownloadManager.Resume(item); } return this; } public AppScenarioPipeline BatchCancel() { foreach (var item in DownloadManager.Items.Where(i => i.IsSelected).ToList()) { DownloadManager.Cancel(item); } return this; } public AppScenarioPipeline BatchDelete() { foreach (var item in DownloadManager.Items.Where(i => i.IsSelected).ToList()) { DownloadManager.Items.Remove(item); } return this; } public void AssertPlaylistCount(int count) { Xunit.Assert.Equal(count, Playlist.Tracks.Count); } public void AssertCurrentTrack(Func predicate) { Xunit.Assert.True(predicate(Playlist.Current), "현재 재생목록 트랙이 조건에 부합하지 않습니다."); } public void Dispose() { try { if (Directory.Exists(TempDir)) Directory.Delete(TempDir, recursive: true); } catch { } } }