using System.Linq; using Paca.Mobile.Core; using Xunit; namespace Paca.Tests.Mobile; public sealed class MobileMenuContractGateTests { [Fact] public void MenuCoordinator_DomainContext_NormalizesHttpAndHttpsUrls() { // Assert domain extraction and security scheme var domain1 = MobileMenuCoordinator.FormatDomainContext("https://www.youtube.com/watch?v=12345"); Assert.Equal("youtube.com", domain1); Assert.True(MobileMenuCoordinator.IsSecureScheme("https://www.youtube.com/watch?v=12345")); var domain2 = MobileMenuCoordinator.FormatDomainContext("paca://newtab"); Assert.Equal("PACA 새 탭", domain2); Assert.False(MobileMenuCoordinator.IsSecureScheme("paca://newtab")); } [Fact] public void MenuCoordinator_QuickControls_EnforcesFourPillarsAndActiveStates() { var context = new MobileMenuContext( CurrentUrl: "https://example.com/article", CurrentTitle: "Sample Article", IsDesktopMode: true, ThemeMode: MobileThemeMode.Dark, IsBookmarked: true, SniffedVideoCount: 3, IsP2pConnected: true ); var items = MobileMenuCoordinator.BuildMenuItems(context); var quickItems = items.Where(i => i.Category == MobileMenuCategory.QuickControls).ToList(); // Miller's / Hick-Hyman Law: Exact 4 quick controls Assert.Equal(4, quickItems.Count); Assert.Contains(quickItems, i => i.ActionId == MobileMenuActionId.ToggleDesktopMode && i.IsActive); Assert.Contains(quickItems, i => i.ActionId == MobileMenuActionId.ToggleThemeMode); Assert.Contains(quickItems, i => i.ActionId == MobileMenuActionId.OpenInPrivateTab); Assert.Contains(quickItems, i => i.ActionId == MobileMenuActionId.ShareAndCopyLink); } [Fact] public void MenuCoordinator_BrowsingAndMedia_ContainsCoreActionsWithDynamicStatus() { var context = new MobileMenuContext( CurrentUrl: "https://example.com/video", CurrentTitle: "Sample Video", IsDesktopMode: false, ThemeMode: MobileThemeMode.Light, IsBookmarked: true, SniffedVideoCount: 2, IsP2pConnected: false ); var items = MobileMenuCoordinator.BuildMenuItems(context); var browsingItems = items.Where(i => i.Category == MobileMenuCategory.BrowsingAndMedia).ToList(); Assert.Equal(4, browsingItems.Count); var bookmarkItem = browsingItems.First(i => i.ActionId == MobileMenuActionId.ToggleBookmark); Assert.True(bookmarkItem.IsActive); Assert.Equal("북마크 해제", bookmarkItem.Title); var p2pItem = browsingItems.First(i => i.ActionId == MobileMenuActionId.SendTabToDesktopP2P); Assert.False(p2pItem.IsActive); Assert.Contains("오프라인", p2pItem.Subtitle); } [Fact] public void MenuCoordinator_IntelligenceAndSettings_ShowsSniffedBadgeAndSync() { var context = new MobileMenuContext( CurrentUrl: "https://example.com/stream", CurrentTitle: "Stream Page", IsDesktopMode: false, ThemeMode: MobileThemeMode.Dark, IsBookmarked: false, SniffedVideoCount: 5, IsP2pConnected: true ); var items = MobileMenuCoordinator.BuildMenuItems(context); var intelItems = items.Where(i => i.Category == MobileMenuCategory.IntelligenceAndSettings).ToList(); var snifferItem = intelItems.FirstOrDefault(i => i.ActionId == MobileMenuActionId.OpenVideoSnifferList); Assert.NotNull(snifferItem); Assert.Equal("5", snifferItem.BadgeText); var syncItem = intelItems.FirstOrDefault(i => i.ActionId == MobileMenuActionId.OpenSyncSettings); Assert.NotNull(syncItem); Assert.Contains("연결됨", syncItem.Subtitle); } [Fact] public void MenuCoordinator_AllItems_HaveNonEmptyAutomationNamesForAccessibility() { var context = new MobileMenuContext( CurrentUrl: "https://example.com", CurrentTitle: "Example", IsDesktopMode: false, ThemeMode: MobileThemeMode.Dark, IsBookmarked: false, SniffedVideoCount: 0, IsP2pConnected: true ); var items = MobileMenuCoordinator.BuildMenuItems(context); foreach (var item in items) { Assert.False(string.IsNullOrWhiteSpace(item.AutomationName), $"Item {item.ActionId} must have an AutomationName"); Assert.False(string.IsNullOrWhiteSpace(item.IconGlyph), $"Item {item.ActionId} must have an IconGlyph"); } } }