// // ConversationNotesServiceTests.swift // oAITests // // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 // Copyright (C) 2026 Rune Olsen import Testing import Foundation @testable import Confab @Suite("ConversationNotesService") struct ConversationNotesServiceTests { @Test("makeFilename sanitizes the conversation name and appends a short ID suffix") func makeFilenameSanitizesAndSuffixes() { let id = UUID(uuidString: "A3F2B1C0-0000-0000-0000-000000000000")! let filename = ConversationNotesService.shared.makeFilename(conversationName: "My Recipe Chat", conversationId: id) #expect(filename == "My Recipe Chat-a3f2.md") } @Test("makeFilename sanitizes invalid filename characters in the conversation name") func makeFilenameSanitizesInvalidChars() { let id = UUID(uuidString: "A3F2B1C0-0000-0000-0000-000000000000")! let filename = ConversationNotesService.shared.makeFilename(conversationName: "Q&A: What/Why?", conversationId: id) #expect(filename == "Q&A- What-Why--a3f2.md") } @Test("makeFilename falls back to Untitled for an empty conversation name") func makeFilenameFallsBackForEmptyName() { let id = UUID(uuidString: "A3F2B1C0-0000-0000-0000-000000000000")! let filename = ConversationNotesService.shared.makeFilename(conversationName: "", conversationId: id) #expect(filename == "Untitled-a3f2.md") } @Test("write then readBody round-trips the body with the ID header stripped") func writeReadRoundTrip() { let id = UUID() let filename = "test-notes-\(UUID().uuidString).md" defer { ConversationNotesService.shared.delete(filename: filename) } ConversationNotesService.shared.write(body: "User prefers dark roast coffee.", filename: filename, conversationId: id) let body = ConversationNotesService.shared.readBody(filename: filename) #expect(body == "User prefers dark roast coffee.") } @Test("readBody on a nonexistent file returns nil, not an error") func readBodyMissingFileReturnsNil() { let body = ConversationNotesService.shared.readBody(filename: "definitely-does-not-exist-\(UUID().uuidString).md") #expect(body == nil) } @Test("readRaw returns the exact on-disk content, ID header included") func readRawIncludesHeader() { let id = UUID() let filename = "test-notes-\(UUID().uuidString).md" defer { ConversationNotesService.shared.delete(filename: filename) } ConversationNotesService.shared.write(body: "User prefers dark roast coffee.", filename: filename, conversationId: id) let raw = ConversationNotesService.shared.readRaw(filename: filename) #expect(raw == "**ID**: `\(id.uuidString)`\n\nUser prefers dark roast coffee.") } @Test("writeRaw then readRaw round-trips content byte-for-byte, with no header wrapping added") func writeRawReadRawRoundTrip() { let filename = "test-notes-\(UUID().uuidString).md" defer { ConversationNotesService.shared.delete(filename: filename) } let content = "**ID**: `12345678-1234-1234-1234-123456789012`\n\nImported from another machine." ConversationNotesService.shared.writeRaw(content: content, filename: filename) #expect(ConversationNotesService.shared.readRaw(filename: filename) == content) } @Test("stripIDHeader removes the embedded ID line and following blank line") func stripIDHeaderRemovesHeader() { let content = "**ID**: `12345678-1234-1234-1234-123456789012`\n\nActual notes content." #expect(ConversationNotesService.stripIDHeader(from: content) == "Actual notes content.") } @Test("stripIDHeader leaves content without the header untouched") func stripIDHeaderLeavesUnheaderedContentUntouched() { let content = "Just some content, no header." #expect(ConversationNotesService.stripIDHeader(from: content) == content) } }