feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization

This commit is contained in:
Yun Chan 2026-09-14 00:39:44 +09:00
parent a88aafa1e5
commit 0e568f1f0a
975 changed files with 130593 additions and 16783 deletions

View file

@ -0,0 +1,118 @@
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");
}
}
}