using VideoDownloader.App.Browser.Features; using VideoDownloader.Browser.Tabs; namespace VideoDownloader.Tests.Browser; // ── T2-2 탭 절전: 유휴 비활성 탭 자동 서스펜드 ── public class TabSuspendServiceTests { [Fact] public void 활성_탭은_절전하지_않는다() { var m = new TabManager(() => new TabItem()); var active = m.NewTab("https://a.com"); var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => throw new InvalidOperationException("suspend should not be called"), t => t == active); svc.SuspendIdleTabs(m.Tabs, active, now: active.LastActivated.AddMinutes(30)); Assert.False(active.IsSuspended); } [Fact] public void 유휴_비활성_탭은_절전한다() { var m = new TabManager(() => new TabItem()); var old = m.NewTab("https://a.com"); var active = m.NewTab("https://b.com"); var suspended = new List(); var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => { suspended.Add(t); return true; }, t => t != active); var now = old.LastActivated.AddMinutes(11); svc.SuspendIdleTabs(m.Tabs, active, now); Assert.Contains(old, suspended); Assert.DoesNotContain(active, suspended); } [Fact] public void 이미_절전된_탭은_중복_서스펜드_하지_않는다() { var m = new TabManager(() => new TabItem()); var old = m.NewTab("https://a.com"); var active = m.NewTab("https://b.com"); old.IsSuspended = true; var calls = 0; var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => { calls++; return true; }, t => t != active); svc.SuspendIdleTabs(m.Tabs, active, old.LastActivated.AddHours(1)); Assert.Equal(0, calls); } [Fact] public void 최근에_활성화된_탭은_절전하지_않는다() { var m = new TabManager(() => new TabItem()); var recent = m.NewTab("https://a.com"); var active = m.NewTab("https://b.com"); m.Activate(recent); // 방금 사용 var calls = 0; var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => { calls++; return true; }, t => t != active); svc.SuspendIdleTabs(m.Tabs, active, recent.LastActivated.AddMinutes(1)); Assert.Equal(0, calls); } } // ── T2-8 탭 검색(Ctrl+Shift+A): 열린+닫힌 탭 필터 ── public class TabSearchFilterTests { [Fact] public void 제목과_URL_부분일치로_필터링한다() { var m = new TabManager(() => new TabItem()); m.NewTab("https://youtube.com/watch?v=1"); m.Tabs[0].Title = "My Favorite Video"; m.NewTab("https://news.example.com"); m.Tabs[1].Title = "News"; var hits = TabSearchFilter.Search(m.Tabs, "favorite"); Assert.Single(hits); Assert.Equal("My Favorite Video", hits[0].Title); hits = TabSearchFilter.Search(m.Tabs, "youtube"); Assert.Single(hits); hits = TabSearchFilter.Search(m.Tabs, "EXAMPLE"); // 대소문자 무시 Assert.Single(hits); } [Fact] public void 닫힌_탭도_검색_대상에_포함된다() { var m = new TabManager(() => new TabItem()); var t = m.NewTab("https://github.com/x"); m.Tabs[0].Title = "GitHub Repo"; m.CloseTab(t); var hits = TabSearchFilter.Search(m.Tabs, m.ClosedStack, "github"); Assert.Single(hits); Assert.Equal("GitHub Repo", hits[0].Title); Assert.True(hits[0].IsClosed); } [Fact] public void 빈_질의는_빈_결과() { var m = new TabManager(() => new TabItem()); m.NewTab("https://a.com"); Assert.Empty(TabSearchFilter.Search(m.Tabs, "")); Assert.Empty(TabSearchFilter.Search(m.Tabs, " ")); } }