internal static partial class Program { static async Task TestEntryUnknownActionAsync() { var entry = NewEntry(); var response = await entry.HandleCommandAsync("""{"action":"unknown.action"}"""); using var doc = JsonDocument.Parse(response); Assert(!doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=false."); Assert(doc.RootElement.GetProperty("error").GetString()!.Contains("Unknown action"), "Expected unknown action error."); } static async Task TestEntryInvalidJsonAsync() { var entry = NewEntry(); var response = await entry.HandleCommandAsync("{\"action\":\"fragments.list\""); using var doc = JsonDocument.Parse(response); Assert(!doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=false."); Assert(doc.RootElement.GetProperty("error").GetString()!.Contains("Invalid command JSON"), "Expected invalid JSON error."); } static async Task TestEntryGetMissingReturnsNullDataAsync() { var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "fragments.get", id = Guid.NewGuid().ToString(), }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true."); Assert(doc.RootElement.GetProperty("data").ValueKind == JsonValueKind.Null, "Expected data=null for missing fragment."); } static async Task TestEntryCreateMissingPayloadAsync() { var entry = NewEntry(); var response = await entry.HandleCommandAsync("""{"action":"fragments.create"}"""); using var doc = JsonDocument.Parse(response); Assert(!doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=false."); Assert(doc.RootElement.GetProperty("error").GetString()!.Contains("payload", StringComparison.OrdinalIgnoreCase), "Expected payload validation error."); } static async Task TestEntryEntriesSaveMergeAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-entry-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { var filePath = Path.Combine(root, "2026-02-22.md"); File.WriteAllText(filePath, """ Date: 2026-02-22 ## Summary old summary text """); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "entries.save", payload = new { filePath, mode = "Daily", content = """ Date: 2026-02-22 ## Summary new summary text ## Reflection new reflection text """ } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.save."); var saved = File.ReadAllText(filePath); Assert(saved.Contains("new summary text", StringComparison.Ordinal), "Expected merged file to contain new summary text."); Assert(!saved.Contains("old summary text", StringComparison.Ordinal), "Expected merged file to replace old summary section."); Assert(saved.Contains("new reflection text", StringComparison.Ordinal), "Expected merged file to contain new reflection section."); var fragmentSaveRequest = JsonSerializer.Serialize(new { action = "entries.save", payload = new { filePath, mode = "Fragment", content = "!NOTE\nfragment append text" } }); var fragmentResponse = await entry.HandleCommandAsync(fragmentSaveRequest); using var fragmentDoc = JsonDocument.Parse(fragmentResponse); Assert(fragmentDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.save fragment mode."); var appended = File.ReadAllText(filePath); Assert(appended.Contains("fragment append text", StringComparison.Ordinal), "Expected fragment append text in saved file."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntryEntriesLoadAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-entry-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { var filePath = Path.Combine(root, "2026-02-22.md"); var content = """ Date: 2026-02-22 ## Summary hello world """; File.WriteAllText(filePath, content); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "entries.load", payload = new { filePath } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.load."); var data = doc.RootElement.GetProperty("data"); var entryDto = data.GetProperty("Entry"); Assert(entryDto.GetProperty("Date").GetString() == "2026-02-22", "Expected parsed date from entries.load."); Assert(entryDto.GetProperty("RawContent").GetString() == content, "Expected raw content from entries.load."); Assert(data.GetProperty("FileName").GetString() == "2026-02-22.md", "Expected file name from entries.load."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntryEntriesListAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-entry-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { File.WriteAllText(Path.Combine(root, "2026-02-03.md"), "c"); File.WriteAllText(Path.Combine(root, "2026-02-01.md"), "a"); File.WriteAllText(Path.Combine(root, "ignore.txt"), "x"); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "entries.list", payload = new { dataDirectory = root } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.list."); var data = doc.RootElement.GetProperty("data"); Assert(data.ValueKind == JsonValueKind.Array, "Expected entries.list data array."); Assert(data.GetArrayLength() == 2, "Expected entries.list to return only markdown files."); Assert(data[0].GetProperty("FileName").GetString() == "2026-02-01.md", "Expected entries.list sort order by file name."); Assert(data[1].GetProperty("FileName").GetString() == "2026-02-03.md", "Expected entries.list sort order by file name."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntryTemplatesCrudExcludesFromEntriesListAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-template-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { File.WriteAllText(Path.Combine(root, "2026-02-03.md"), "daily entry"); var entry = NewEntry(); var saveRequest = JsonSerializer.Serialize(new { action = "templates.save", payload = new { name = "Weekly Review", content = "# Weekly Review\n\n## Wins\n- one", dataDirectory = root } }); var saveResponse = await entry.HandleCommandAsync(saveRequest); using var saveDoc = JsonDocument.Parse(saveResponse); Assert(saveDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for templates.save."); var templatePath = saveDoc.RootElement.GetProperty("data").GetProperty("FilePath").GetString() ?? ""; Assert(templatePath.EndsWith(".template.md", StringComparison.OrdinalIgnoreCase), "Template file should end with .template.md."); Assert(File.Exists(templatePath), "Template file should exist."); var listTemplatesRequest = JsonSerializer.Serialize(new { action = "templates.list", payload = new { dataDirectory = root } }); var listTemplatesResponse = await entry.HandleCommandAsync(listTemplatesRequest); using var listTemplatesDoc = JsonDocument.Parse(listTemplatesResponse); Assert(listTemplatesDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for templates.list."); var templateItems = listTemplatesDoc.RootElement.GetProperty("data"); Assert(templateItems.GetArrayLength() == 1, "Expected one template in templates.list."); Assert(templateItems[0].GetProperty("FileName").GetString() == "Weekly Review.template.md", "Template file name mismatch."); var listEntriesRequest = JsonSerializer.Serialize(new { action = "entries.list", payload = new { dataDirectory = root } }); var listEntriesResponse = await entry.HandleCommandAsync(listEntriesRequest); using var listEntriesDoc = JsonDocument.Parse(listEntriesResponse); Assert(listEntriesDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.list."); var entryItems = listEntriesDoc.RootElement.GetProperty("data"); Assert(entryItems.GetArrayLength() == 1, "Expected entries.list to exclude template files."); Assert(entryItems[0].GetProperty("FileName").GetString() == "2026-02-03.md", "Expected only daily entry file in entries.list."); var loadTemplateRequest = JsonSerializer.Serialize(new { action = "templates.load", payload = new { filePath = templatePath } }); var loadTemplateResponse = await entry.HandleCommandAsync(loadTemplateRequest); using var loadTemplateDoc = JsonDocument.Parse(loadTemplateResponse); Assert(loadTemplateDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for templates.load."); var content = loadTemplateDoc.RootElement.GetProperty("data").GetProperty("Content").GetString() ?? ""; Assert(content.Contains("## Wins", StringComparison.Ordinal), "Expected template content in templates.load result."); var deleteTemplateRequest = JsonSerializer.Serialize(new { action = "templates.delete", payload = new { filePath = templatePath } }); var deleteTemplateResponse = await entry.HandleCommandAsync(deleteTemplateRequest); using var deleteTemplateDoc = JsonDocument.Parse(deleteTemplateResponse); Assert(deleteTemplateDoc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for templates.delete."); Assert(deleteTemplateDoc.RootElement.GetProperty("data").GetBoolean(), "Expected templates.delete to return true."); Assert(!File.Exists(templatePath), "Template file should be deleted."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesMatchesRawContentAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { File.WriteAllText(Path.Combine(root, "2026-02-01.md"), "## Summary\nAlpha line\ncommon token"); File.WriteAllText(Path.Combine(root, "2026-02-02.md"), "## Summary\nbeta line\nCOMMON token"); File.WriteAllText(Path.Combine(root, "2026-02-03.md"), "## Summary\ngamma only"); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, query = "common token", } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for search.entries."); var data = doc.RootElement.GetProperty("data"); Assert(data.ValueKind == JsonValueKind.Array, "Expected data array from search.entries."); Assert(data.GetArrayLength() == 2, "Expected two entries matching query across raw content."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesWithoutQueryReturnsAllAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { File.WriteAllText(Path.Combine(root, "2026-02-01.md"), "one"); File.WriteAllText(Path.Combine(root, "2026-02-02.md"), "two"); File.WriteAllText(Path.Combine(root, "ignore.txt"), "not markdown"); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for search.entries without query."); var data = doc.RootElement.GetProperty("data"); Assert(data.ValueKind == JsonValueKind.Array, "Expected data array from search.entries."); Assert(data.GetArrayLength() == 2, "Expected all markdown files to be returned when query is omitted."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesDateRangeFilterAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { WriteSearchFixtureFiles(root); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, startDate = "2026-02-02", endDate = "2026-02-28", } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for date-range filtered search."); var data = doc.RootElement.GetProperty("data"); Assert(data.GetArrayLength() == 1, "Expected one result for filtered date range."); Assert(data[0].GetProperty("FileName").GetString() == "2026-02-05.md", "Date-range result mismatch."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesSectionFilterAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { WriteSearchFixtureFiles(root); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, query = "focus area", section = "Reflection", } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for section-scoped search."); var data = doc.RootElement.GetProperty("data"); Assert(data.GetArrayLength() == 1, "Expected one section-scoped result."); Assert(data[0].GetProperty("FileName").GetString() == "2026-02-01.md", "Section filter result mismatch."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesTagTypeFilterAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { WriteSearchFixtureFiles(root); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, tags = new[] { "stress" }, types = new[] { "!TRIGGER" }, } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for fragment tag/type filtered search."); var data = doc.RootElement.GetProperty("data"); Assert(data.GetArrayLength() == 1, "Expected one result for fragment tag/type filters."); Assert(data[0].GetProperty("FileName").GetString() == "2026-02-01.md", "Tag/type filter result mismatch."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesCheckboxFilterAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { WriteSearchFixtureFiles(root); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, @checked = new[] { "med taken" }, @unchecked = new[] { "drink water" }, } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for checkbox filtered search."); var data = doc.RootElement.GetProperty("data"); Assert(data.GetArrayLength() == 2, "Expected OR-style checkbox match across checked/unchecked filters."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntrySearchEntriesRejectsInvalidDateAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-search-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { WriteSearchFixtureFiles(root); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "search.entries", payload = new { dataDirectory = root, startDate = "2026/02/01", } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(!doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=false for invalid date format."); var error = doc.RootElement.GetProperty("error").GetString() ?? ""; Assert(error.Contains("invalid startdate value", StringComparison.OrdinalIgnoreCase), "Expected invalid startDate error."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static Task TestSidecarSearchCliFilteredAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-sidecar-cli-smoke", Guid.NewGuid().ToString("N")); var dataDir = Path.Combine(root, "data"); Directory.CreateDirectory(dataDir); try { WriteSearchFixtureFiles(dataDir); var cli = new SidecarCli(new VaultStorageService(new VaultCryptoService()), new EntrySearchService(), new JournalConfigService()); var (exitCode, stdout, stderr) = CaptureConsole(() => cli.RunSearchCommand( [ "common", "--data-dir", dataDir, "--start-date", "2026-02-01", "--end-date", "2026-02-28", "--tag", "stress", "--type", "!TRIGGER", "--checked", "med taken", "--section", "Summary" ])); Assert(exitCode == 0, "Expected search CLI command to succeed."); Assert(string.IsNullOrWhiteSpace(stderr), "Expected no stderr output for successful search CLI command."); Assert(stdout.Contains("--- 2026-02-01 ---", StringComparison.Ordinal), "Expected matching entry header in search CLI output."); Assert(!stdout.Contains("--- 2026-02-05 ---", StringComparison.Ordinal), "Unexpected non-matching entry in filtered search CLI output."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } return Task.CompletedTask; } static Task TestSidecarSearchCliEmptyDataAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-sidecar-cli-smoke", Guid.NewGuid().ToString("N")); var dataDir = Path.Combine(root, "data"); Directory.CreateDirectory(dataDir); try { var cli = new SidecarCli(new VaultStorageService(new VaultCryptoService()), new EntrySearchService(), new JournalConfigService()); var (exitCode, stdout, _) = CaptureConsole(() => cli.RunSearchCommand(["--data-dir", dataDir])); Assert(exitCode == 0, "Expected search CLI command to return success for empty data directory."); Assert(stdout.Contains("No decrypted journal entries found", StringComparison.OrdinalIgnoreCase), "Expected empty-data guidance message."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } return Task.CompletedTask; } static Task TestEntrySavePayloadFileNameDeserializationAsync() { // Simulate what DeserializePayload does: parse JSON to JsonElement, then Deserialize var json = """{"content":"hello","mode":"Overwrite","fileName":"My Custom Name"}"""; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var element = JsonSerializer.Deserialize(json); var payload = element.Deserialize(options); Assert(payload is not null, "Payload should not be null."); Assert(payload!.Content == "hello", "Content should be deserialized."); Assert(payload.Mode == "Overwrite", "Mode should be deserialized."); Assert(payload.FileName == "My Custom Name", "FileName should be deserialized from camelCase JSON via JsonElement."); Assert(payload.FilePath is null, "FilePath should be null when not provided."); return Task.CompletedTask; } static async Task TestEntrySaveWithFileNameAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-entry-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { // Use EntryFileService directly to test the full save path with fileName var service = new EntryFileService(new DiskEntryFileRepository()); var payload = new EntrySavePayload( Content: "# Custom Entry\n\nHello world", FilePath: null, Mode: "Overwrite", FileName: "My Custom Name"); var result = service.SaveEntry(payload, root); var expectedPath = Path.GetFullPath(Path.Combine(root, "My Custom Name.md")); Assert(result.FilePath == expectedPath, $"Expected path '{expectedPath}' but got '{result.FilePath}'."); Assert(File.Exists(expectedPath), "Custom-named file should exist on disk."); Assert(File.ReadAllText(expectedPath).Contains("Hello world"), "File content should match."); // Also test via Entry.HandleCommandAsync with JSON to verify full deserialization chain var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "entries.save", payload = new { content = "# Second Entry", mode = "Overwrite", fileName = "Another Custom Name" } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for entries.save with fileName."); var savedFilePath = doc.RootElement.GetProperty("data").GetProperty("FilePath").GetString() ?? ""; Assert(savedFilePath.Contains("Another Custom Name.md", StringComparison.OrdinalIgnoreCase), $"Expected file path to contain 'Another Custom Name.md' but got '{savedFilePath}'."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } }