using System; using System.IO; using System.Linq; using Paca.Core.QuickActions; using Xunit; namespace Paca.Tests.App; public class QuickActionSpotlightTwoPhase20Tests { private static readonly string SolutionRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..")); [Theory] [InlineData("https://www.youtube.com/watch?v=dQw4w9WgXcQ", ClipboardIntentType.MediaDownload)] [InlineData("https://twitter.com/user/status/123456789", ClipboardIntentType.MediaDownload)] [InlineData("https://example.com/live/stream.m3u8", ClipboardIntentType.MediaDownload)] [InlineData("https://news.ycombinator.com", ClipboardIntentType.BrowseUrl)] [InlineData("125 * 40 - 15", ClipboardIntentType.Expression)] [InlineData("just regular plain text", ClipboardIntentType.None)] [InlineData(null, ClipboardIntentType.None)] public void Gate201_ClipboardDetector_AccuratelyClassifiesContent(string? text, ClipboardIntentType expected) { var detector = new QuickActionClipboardDetector(); var result = detector.DetectIntent(text); Assert.Equal(expected, result.IntentType); if (expected != ClipboardIntentType.None) { Assert.False(string.IsNullOrWhiteSpace(result.SuggestedActionTitle)); } } [Fact] public void Gate202_FavoritesManager_AddRemoveAndPersistFavorites() { string tempJson = Path.Combine(Path.GetTempPath(), $"paca_fav_test_{Guid.NewGuid():N}.json"); try { var manager = new QuickActionFavoritesManager(tempJson); Assert.False(manager.IsFavorite("browser.new_tab")); // 1. Toggle on bool added = manager.ToggleFavorite("browser.new_tab"); Assert.True(added); Assert.True(manager.IsFavorite("browser.new_tab")); Assert.Contains("browser.new_tab", manager.GetFavorites()); // 2. Reload from JSON disk var manager2 = new QuickActionFavoritesManager(tempJson); Assert.True(manager2.IsFavorite("browser.new_tab")); // 3. Toggle off bool removed = manager2.ToggleFavorite("browser.new_tab"); Assert.False(removed); Assert.False(manager2.IsFavorite("browser.new_tab")); Assert.DoesNotContain("browser.new_tab", manager2.GetFavorites()); } finally { if (File.Exists(tempJson)) File.Delete(tempJson); } } [Fact] public void Gate203_UserCustomActionStore_RegistersAndInstantiatesQuickActionItem() { string tempJson = Path.Combine(Path.GetTempPath(), $"paca_custom_test_{Guid.NewGuid():N}.json"); try { var store = new UserCustomActionStore(tempJson); var custom = new UserCustomAction( Id: "custom.my_intranet", Title: "사내 인트라넷 열기", Keywords: "intranet work 사내포털", TargetUrl: "https://intranet.company.internal", ShortcutHint: "Ctrl+Alt+I" ); store.AddOrUpdate(custom); Assert.Single(store.GetAll()); // Convert to QuickActionItem var catalog = new QuickActionCatalog(); store.InjectIntoCatalog(catalog); var injected = catalog.FindById("custom.my_intranet"); Assert.NotNull(injected); Assert.Equal("사내 인트라넷 열기", injected.Title); Assert.Equal(QuickActionCategory.Ecosystem, injected.Category); // Reload from disk var store2 = new UserCustomActionStore(tempJson); Assert.Single(store2.GetAll()); Assert.Equal("custom.my_intranet", store2.GetAll().First().Id); } finally { if (File.Exists(tempJson)) File.Delete(tempJson); } } [Theory] [InlineData(10, "방금 전")] [InlineData(300, "5분 전")] [InlineData(7200, "2시간 전")] [InlineData(90000, "어제")] public void Gate204_QuickActionTimeFormatter_RendersNaturalRelativeTime(int secondsAgo, string expectedKorean) { var now = DateTime.UtcNow; var past = now.AddSeconds(-secondsAgo); string formatted = QuickActionTimeFormatter.FormatRelativeTime(past, now, "ko"); Assert.Equal(expectedKorean, formatted); } [Fact] public void Gate205_LauncherWindowXaml_ContainsClipboardBannerAndFavoritesSupport() { string xamlPath = Path.Combine(SolutionRoot, "src", "Paca.App", "QuickActionLauncherWindow.xaml"); string xaml = File.ReadAllText(xamlPath); Assert.Contains("x:Name=\"ClipboardSuggestionBanner\"", xaml); Assert.Contains("x:Name=\"ClipboardBannerTitle\"", xaml); } [Fact] public void Gate206_LauncherWindowCs_WiresClipboardDetectionOnActivate() { string csPath = Path.Combine(SolutionRoot, "src", "Paca.App", "QuickActionLauncherWindow.xaml.cs"); string cs = File.ReadAllText(csPath); Assert.Contains("CheckClipboardIntent()", cs); Assert.Contains("QuickActionClipboardDetector", cs); } }