using System; using System.Collections.Generic; using System.IO; using System.Linq; using Paca.Browser; using Paca.Browser.Tabs; using Paca.Tests.Infrastructure; using Xunit; namespace Paca.Tests.Browser; public class ChromeParityNavigationAndToolsTests { // ========================================================================= // 1. 소스 보기 (View Page Source in New Tab) // ========================================================================= [Fact] public void ViewSourceInNewTab_기존_탭을_보존하고_우측에_새_소스_탭을_생성한다() { var mgr = new TabManager(() => new TabItem()); var original = mgr.NewTab("https://github.com/Paca"); original.Title = "GitHub - Paca"; // 소스 보기 전용 탭 생성 헬퍼 var sourceTab = mgr.NewTabAfter(original, "view-source:" + original.Url, activate: true); sourceTab.Title = $"소스: {original.Title}"; Assert.Equal(2, mgr.Tabs.Count); Assert.Equal(original, mgr.Tabs[0]); Assert.Equal(sourceTab, mgr.Tabs[1]); Assert.Equal("view-source:https://github.com/Paca", sourceTab.Url); Assert.Equal("소스: GitHub - Paca", sourceTab.Title); Assert.Same(sourceTab, mgr.ActiveTab); } // ========================================================================= // 2. 인터넷 사용 기록 삭제 (Clear Browsing Data Filter & Range) // ========================================================================= [Fact] public void BrowsingDataCleaner_시간_범위별_기준시각을_정확히_산출한다() { var now = new DateTime(2026, 9, 9, 15, 0, 0, DateTimeKind.Utc); Assert.Equal(now.AddHours(-1), BrowsingDataCleaner.CalculateCutoff(ClearBrowsingTimeRange.LastHour, now)); Assert.Equal(now.AddHours(-24), BrowsingDataCleaner.CalculateCutoff(ClearBrowsingTimeRange.Last24Hours, now)); Assert.Equal(now.AddDays(-7), BrowsingDataCleaner.CalculateCutoff(ClearBrowsingTimeRange.Last7Days, now)); Assert.Equal(now.AddDays(-28), BrowsingDataCleaner.CalculateCutoff(ClearBrowsingTimeRange.Last4Weeks, now)); Assert.Null(BrowsingDataCleaner.CalculateCutoff(ClearBrowsingTimeRange.AllTime, now)); } [Fact] public void BrowsingDataCleaner_시간_범위_기준으로_방문_기록을_정밀_필터링하여_삭제한다() { var now = new DateTime(2026, 9, 9, 15, 0, 0, DateTimeKind.Utc); var history = new List { new("10분 전", "https://recent.com", now.AddMinutes(-10)), new("3시간 전", "https://earlier.com", now.AddHours(-3)), new("2일 전", "https://old.com", now.AddDays(-2)), new("한달 전", "https://ancient.com", now.AddDays(-30)) }; // 지난 1시간 삭제 -> 10분 전 기록만 삭제되고 나머지는 보존 var remainingAfter1Hour = BrowsingDataCleaner.FilterHistory(history, ClearBrowsingTimeRange.LastHour, now); Assert.Equal(3, remainingAfter1Hour.Count); Assert.DoesNotContain(remainingAfter1Hour, h => h.Url == "https://recent.com"); Assert.Contains(remainingAfter1Hour, h => h.Url == "https://earlier.com"); // 지난 24시간 삭제 -> 10분 전, 3시간 전 삭제, 2일 전/한달 전 보존 var remainingAfter24Hours = BrowsingDataCleaner.FilterHistory(history, ClearBrowsingTimeRange.Last24Hours, now); Assert.Equal(2, remainingAfter24Hours.Count); Assert.DoesNotContain(remainingAfter24Hours, h => h.Url == "https://earlier.com"); Assert.Contains(remainingAfter24Hours, h => h.Url == "https://old.com"); // 전체 기간 삭제 -> 모든 기록 제거 var remainingAfterAll = BrowsingDataCleaner.FilterHistory(history, ClearBrowsingTimeRange.AllTime, now); Assert.Empty(remainingAfterAll); } // ========================================================================= // 3. 주소창 QR 코드 생성기 (Chrome Parity URL QR Code Generator) // ========================================================================= [Fact] public void QrCodeSvgGenerator_유효한_URL_입력시_규격_SVG_마크업을_반환한다() { string testUrl = "https://github.com/Paca/browser"; string svg = QrCodeSvgGenerator.GenerateSvg(testUrl, size: 240); Assert.NotNull(svg); Assert.StartsWith("", svg.Trim()); Assert.Contains("width=\"240\"", svg); Assert.Contains("height=\"240\"", svg); Assert.Contains(" new TabItem()); var tab1 = tabMgr.NewTab("https://github.com"); tab1.Title = "GitHub"; var tab2 = tabMgr.NewTab("https://youtube.com"); tab2.Title = "YouTube"; var tasks = BrowserTaskManager.CollectTasks(tabMgr); // 최소 브라우저 메인 프로세스 1개 + 탭 2개 = 3개 태스크 Assert.True(tasks.Count >= 3); var mainProcess = tasks.FirstOrDefault(t => t.Type == BrowserTaskType.Browser); Assert.NotNull(mainProcess); Assert.Equal("브라우저 (Paca)", mainProcess!.Title); var tabTasks = tasks.Where(t => t.Type == BrowserTaskType.Tab).ToList(); Assert.Equal(2, tabTasks.Count); Assert.Contains(tabTasks, t => t.Title == "GitHub"); Assert.Contains(tabTasks, t => t.Title == "YouTube"); } [Fact] public void BrowserTaskManager_EndTask_호출시_해당_탭을_안전하게_종료한다() { var tabMgr = new TabManager(() => new TabItem()); var tab1 = tabMgr.NewTab("https://tab1.com"); var tab2 = tabMgr.NewTab("https://tab2.com"); var tasks = BrowserTaskManager.CollectTasks(tabMgr); var taskToKill = tasks.First(t => t.Title == "tab2.com" || t.Url == "https://tab2.com"); bool success = BrowserTaskManager.EndTask(taskToKill, tabMgr); Assert.True(success); Assert.Single(tabMgr.Tabs); Assert.Equal(tab1, tabMgr.Tabs[0]); } }