using System; using System.Collections.Generic; using Paca.Browser.Tabs; using Xunit; namespace Paca.Tests.Browser; public class ChromeTabDiscardPolicyTests { [Fact] public void Policy_Evaluates_Eligible_Tabs_Correctly() { var policy = new ChromeTabDiscardPolicy(MemorySaverMode.Moderate); var activeTab = new DiscardableTabInfo("tab-1", "https://google.com", IsActive: true, IsPinned: false, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddHours(-1)); var pinnedTab = new DiscardableTabInfo("tab-2", "https://github.com", IsActive: false, IsPinned: true, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddHours(-1)); var audioTab = new DiscardableTabInfo("tab-3", "https://youtube.com", IsActive: false, IsPinned: false, IsAudioPlaying: true, LastAccessed: DateTime.UtcNow.AddHours(-1)); var idleTab = new DiscardableTabInfo("tab-4", "https://news.com", IsActive: false, IsPinned: false, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddMinutes(-35)); var recentTab = new DiscardableTabInfo("tab-5", "https://blog.com", IsActive: false, IsPinned: false, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddMinutes(-5)); // Active tab must never be discarded Assert.False(policy.CanDiscard(activeTab, DateTime.UtcNow)); // Pinned tab must never be discarded Assert.False(policy.CanDiscard(pinnedTab, DateTime.UtcNow)); // Audio playing tab must never be discarded Assert.False(policy.CanDiscard(audioTab, DateTime.UtcNow)); // Idle tab (>30 min) in Moderate mode can be discarded Assert.True(policy.CanDiscard(idleTab, DateTime.UtcNow)); // Recent tab (<30 min) in Moderate mode cannot be discarded Assert.False(policy.CanDiscard(recentTab, DateTime.UtcNow)); } [Fact] public void MemorySaverMode_Thresholds_Work_As_Expected() { var disabled = new ChromeTabDiscardPolicy(MemorySaverMode.Disabled); var aggressive = new ChromeTabDiscardPolicy(MemorySaverMode.Aggressive); // 5 min var conservative = new ChromeTabDiscardPolicy(MemorySaverMode.Conservative); // 2 hours var tenMinIdleTab = new DiscardableTabInfo("t-1", "https://site.org", IsActive: false, IsPinned: false, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddMinutes(-10)); Assert.False(disabled.CanDiscard(tenMinIdleTab, DateTime.UtcNow)); Assert.True(aggressive.CanDiscard(tenMinIdleTab, DateTime.UtcNow)); Assert.False(conservative.CanDiscard(tenMinIdleTab, DateTime.UtcNow)); } [Fact] public void DiscardManager_Tracks_Discarded_And_Reactivated_Tabs() { var manager = new ChromeTabDiscardManager(MemorySaverMode.Aggressive); var tab = new DiscardableTabInfo("t-1", "https://site.org", IsActive: false, IsPinned: false, IsAudioPlaying: false, LastAccessed: DateTime.UtcNow.AddMinutes(-10)); Assert.False(manager.IsDiscarded("t-1")); var discarded = manager.TryDiscard(tab, DateTime.UtcNow); Assert.True(discarded); Assert.True(manager.IsDiscarded("t-1")); Assert.Equal(1, manager.DiscardedCount); // Reactivating tab restores its active state var restored = manager.Reactivate("t-1"); Assert.True(restored); Assert.False(manager.IsDiscarded("t-1")); Assert.Equal(0, manager.DiscardedCount); } [Theory] [InlineData("chrome://discards", ChromeInternalAction.Discards)] [InlineData("paca://discards", ChromeInternalAction.Discards)] public void ChromeInternalUrlRouter_Routes_Discards(string url, ChromeInternalAction expected) { Assert.True(ChromeInternalUrlRouter.IsInternal(url)); Assert.Equal(expected, ChromeInternalUrlRouter.Route(url)); } [Fact] public void Omnibox_Suggests_Discard_Tabs_Action() { var actions = OmniboxActionEvaluator.GetMatchingActions("메모리 절약"); Assert.NotEmpty(actions); Assert.Contains(actions, a => a.ActionId == "action:discard-tabs"); } }