import XCTest @testable import Ten31Transcripts final class SessionNamingTests: XCTestCase { // MARK: sanitize func testSanitizeTrimsAndKeepsSpaces() { XCTAssertEqual(SessionNaming.sanitize(" Weekly Sync "), "Weekly Sync") } func testSanitizeReplacesPathSeparators() { XCTAssertEqual(SessionNaming.sanitize("9/10 standup"), "9-10 standup") XCTAssertEqual(SessionNaming.sanitize("a:b\\c"), "a-b-c") } func testSanitizeCollapsesWhitespaceRuns() { XCTAssertEqual(SessionNaming.sanitize("board 1:1"), "board 1-1") } func testSanitizeStripsLeadingDots() { XCTAssertEqual(SessionNaming.sanitize("...hidden"), "hidden") XCTAssertEqual(SessionNaming.sanitize(".."), "") } func testSanitizeEmptyForBlankOrWhitespace() { XCTAssertEqual(SessionNaming.sanitize(""), "") XCTAssertEqual(SessionNaming.sanitize(" \n\t "), "") } func testSanitizeCapsLength() { let long = String(repeating: "x", count: 200) XCTAssertEqual(SessionNaming.sanitize(long).count, 60) } func testSanitizeStripsControlCharacters() { XCTAssertEqual(SessionNaming.sanitize("a\u{0000}b\u{001F}c"), "abc") } // MARK: datePrefix func testDatePrefixFromAutoName() { XCTAssertEqual(SessionNaming.datePrefix(ofSessionNamed: "2026-06-17T09-59-48_signal"), "2026-06-17") } func testDatePrefixFromRenamedName() { XCTAssertEqual(SessionNaming.datePrefix(ofSessionNamed: "2026-06-17_Weekly sync_signal"), "2026-06-17") } // MARK: renamedLeaf func testRenamedLeafBasic() { XCTAssertEqual( SessionNaming.renamedLeaf(date: "2026-06-17", app: "signal", meetingName: "Weekly sync"), "2026-06-17_Weekly sync_signal") } func testRenamedLeafAppStaysLastSegment() { // The meeting name may contain underscores; the app must remain parseable as // the final "_"-segment (what SessionController.appLabel reads). let leaf = SessionNaming.renamedLeaf(date: "2026-06-17", app: "meet", meetingName: "q3_planning") XCTAssertEqual(leaf, "2026-06-17_q3_planning_meet") XCTAssertEqual(leaf?.split(separator: "_").last.map(String.init), "meet") } func testRenamedLeafNilForBlankName() { XCTAssertNil(SessionNaming.renamedLeaf(date: "2026-06-17", app: "signal", meetingName: " ")) } func testRenamedLeafCounterDisambiguatesNameSegment() { // A collision suffixes the NAME, not the whole leaf, so "_app" stays last. let leaf = SessionNaming.renamedLeaf(date: "2026-06-17", app: "signal", meetingName: "sync", counter: 1) XCTAssertEqual(leaf, "2026-06-17_sync-2_signal") XCTAssertEqual(leaf?.split(separator: "_").last.map(String.init), "signal") } func testRenamedLeafAppStaysLastAtMaxCollisionDepth() { // The 100-collision cap is counter 0…99; the app must still parse out last. let leaf = SessionNaming.renamedLeaf(date: "2026-06-17", app: "signal", meetingName: "q3_sync", counter: 99) XCTAssertEqual(leaf, "2026-06-17_q3_sync-100_signal") XCTAssertEqual(leaf?.split(separator: "_").last.map(String.init), "signal") } // MARK: recapTitle func testRecapTitleAutoNamePreservesLegacyFormat() { XCTAssertEqual( SessionNaming.recapTitle(app: "meet", sessionId: "2026-06-06T11-43-02_meet"), "Google Meet call — 2026-06-06 11:43") } func testRecapTitleNamedSession() { XCTAssertEqual( SessionNaming.recapTitle(app: "meet", sessionId: "2026-06-06_Weekly sync_meet"), "Weekly sync — Google Meet (2026-06-06)") } func testRecapTitleNamePreservesUnderscores() { // A meeting name with underscores must survive the split/join round-trip. XCTAssertEqual( SessionNaming.recapTitle(app: "meet", sessionId: "2026-06-06_q3_planning_meet"), "q3_planning — Google Meet (2026-06-06)") } func testRecapTitleUnknownAppCapitalizes() { XCTAssertEqual( SessionNaming.recapTitle(app: "manual", sessionId: "2026-06-06T11-43-02_manual"), "Manual call — 2026-06-06 11:43") } }