Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions ModernTests/ClaudeCodeSummaryBuilderTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// ClaudeCodeSummaryBuilderTests.swift
// iTerm2
//

import XCTest
@testable import iTerm2SharedARC

final class ClaudeCodeSummaryBuilderTests: XCTestCase {

// MARK: - Helpers

private func makeStatus(_ text: String, id: String = UUID().uuidString) -> iTermSessionTabStatus {
let s = iTermSessionTabStatus(sessionID: id)
s.statusText = text
return s
}

// MARK: - isClaudeCodeStatus

func testIsClaudeCodeStatus_waiting() {
XCTAssertTrue(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Waiting"))
}

func testIsClaudeCodeStatus_working() {
XCTAssertTrue(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Working\u{2026}"))
}

func testIsClaudeCodeStatus_idle() {
XCTAssertTrue(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Idle"))
}

func testIsClaudeCodeStatus_nil() {
XCTAssertFalse(ClaudeCodeSummaryBuilder.isClaudeCodeStatus(nil))
}

func testIsClaudeCodeStatus_emptyString() {
XCTAssertFalse(ClaudeCodeSummaryBuilder.isClaudeCodeStatus(""))
}

func testIsClaudeCodeStatus_unrelatedStatus() {
XCTAssertFalse(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Running"))
}

func testIsClaudeCodeStatus_partialMatch() {
// "Waiting" must match exactly — a prefix should not pass.
XCTAssertFalse(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Wait"))
}

func testIsClaudeCodeStatus_wrongEllipsis() {
// Three ASCII dots are not the Unicode ellipsis character used in "Working…".
XCTAssertFalse(ClaudeCodeSummaryBuilder.isClaudeCodeStatus("Working..."))
}

// MARK: - buildSummary — empty

func testBuildSummary_empty() {
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: []), "No sessions")
}

// MARK: - buildSummary — single counts (singular form)

func testBuildSummary_oneWaiting() {
let sessions = [makeStatus("Waiting")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 waiting")
}

func testBuildSummary_oneWorking() {
let sessions = [makeStatus("Working\u{2026}")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 working")
}

func testBuildSummary_oneIdle() {
let sessions = [makeStatus("Idle")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 idle")
}

// MARK: - buildSummary — plural counts

func testBuildSummary_twoWaiting() {
let sessions = [makeStatus("Waiting"), makeStatus("Waiting")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "2 waiting")
}

func testBuildSummary_twoWorking() {
let sessions = [makeStatus("Working\u{2026}"), makeStatus("Working\u{2026}")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "2 working")
}

func testBuildSummary_twoIdle() {
let sessions = [makeStatus("Idle"), makeStatus("Idle")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "2 idle")
}

// MARK: - buildSummary — mixed states (ordering: waiting, working, idle)

func testBuildSummary_waitingAndWorking() {
let sessions = [makeStatus("Waiting"), makeStatus("Working\u{2026}")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 waiting, 1 working")
}

func testBuildSummary_waitingAndIdle() {
let sessions = [makeStatus("Waiting"), makeStatus("Idle")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 waiting, 1 idle")
}

func testBuildSummary_workingAndIdle() {
let sessions = [makeStatus("Working\u{2026}"), makeStatus("Idle")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 working, 1 idle")
}

func testBuildSummary_allThreeStates() {
let sessions = [
makeStatus("Waiting"),
makeStatus("Working\u{2026}"),
makeStatus("Idle"),
]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "1 waiting, 1 working, 1 idle")
}

func testBuildSummary_multipleOfEachState() {
let sessions = [
makeStatus("Waiting"), makeStatus("Waiting"),
makeStatus("Working\u{2026}"),
makeStatus("Idle"), makeStatus("Idle"), makeStatus("Idle"),
]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "2 waiting, 1 working, 3 idle")
}

// MARK: - buildSummary — exemplar from the status bar (regression guard)

func testBuildSummary_exemplarString() {
// The exemplar shown in statusBarComponentExemplar is "2 waiting, 1 working".
// This test guards against regressions that would silently change the format.
let sessions = [makeStatus("Waiting"), makeStatus("Waiting"), makeStatus("Working\u{2026}")]
XCTAssertEqual(ClaudeCodeSummaryBuilder.buildSummary(from: sessions), "2 waiting, 1 working")
}
}
8 changes: 8 additions & 0 deletions iTerm2.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@
4705C05130977E2C81FD75E8 /* iTermUnicodeNormalization.h in Sources */ = {isa = PBXBuildFile; fileRef = 3335AD96138BA74CC79D25A8 /* iTermUnicodeNormalization.h */; };
4887C7B3CAB5465296225860 /* MenuTips.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 904AE312A0E0489899D9ECB8 /* MenuTips.xcassets */; };
49A6E4091211CC6000D9AD6F /* Compatability.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A6E4081211CC6000D9AD6F /* Compatability.h */; };
4B395950B0EF00428363FA75 /* iTermStatusBarClaudeCodeComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 854E1EAA1B9E2B6D8BA548D0 /* iTermStatusBarClaudeCodeComponent.swift */; };
4BC1E97CEA4441CF9390DD52 /* MenuTips.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 904AE312A0E0489899D9ECB8 /* MenuTips.xcassets */; };
4C4BE71D1C8948BD8CD672BC /* iTermLayoutCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = AF19E441FF824539A275D8DA /* iTermLayoutCalculator.m */; };
4C9D9EF0E49226A8A974CE88 /* SearchResultSoftBoundaryExtender.swift in Sources */ = {isa = PBXBuildFile; fileRef = A004AF3FD82E9DE92D43DF5E /* SearchResultSoftBoundaryExtender.swift */; };
Expand Down Expand Up @@ -5183,6 +5184,7 @@
A7E25DCB1956D4A7FA738CB9 /* iTermStreamingPNGWriter.h in Sources */ = {isa = PBXBuildFile; fileRef = CB2F48F836C5732146BCEDD9 /* iTermStreamingPNGWriter.h */; };
AA190CE70997D5318EF50177 /* ClaudeCodeOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = E961A126DE6D9EFA0C6CC9AB /* ClaudeCodeOnboarding.swift */; };
B2CA85E23B4CCCC3391BA025 /* NotifyingDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877B9444B69DE32D9CF87354 /* NotifyingDictionary.swift */; };
B9E5F0B3A747133496AC5145 /* ClaudeCodeStatusPopoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E743E798CA3A96AB8F6168 /* ClaudeCodeStatusPopoverViewController.swift */; };
C48D7AA2E70B019313C401F3 /* WordSelectionAtom.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08AA4008946722C3F4C67C1 /* WordSelectionAtom.swift */; };
C5F394249CF581965B22B714 /* GlobalJobMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA34A6F29B10471D8FD572F6 /* GlobalJobMonitor.swift */; };
C6675EBC1C4FE96B0041173B /* iTermSelectorSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = C6675EBB1C4FE96B0041173B /* iTermSelectorSwizzler.m */; };
Expand Down Expand Up @@ -6311,6 +6313,7 @@
7F3AA921DF1744D7BA890104 /* PillBackgroundRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillBackgroundRenderer.swift; sourceTree = "<group>"; };
80A64098B399CE71B981E2C7 /* iTermRenderingComparer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = iTermRenderingComparer.swift; sourceTree = "<group>"; };
81E145AE29B68F8F2A69891A /* iTermLocatedString+ScreenCharArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "iTermLocatedString+ScreenCharArray.swift"; sourceTree = "<group>"; };
854E1EAA1B9E2B6D8BA548D0 /* iTermStatusBarClaudeCodeComponent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = iTermStatusBarClaudeCodeComponent.swift; sourceTree = "<group>"; };
86FC661122588ABDA0EE3245 /* PTYTextViewAccessibilityTest.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = PTYTextViewAccessibilityTest.m; sourceTree = "<group>"; };
8742065A0564169600CFC3F1 /* iTerm2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iTerm2.app; sourceTree = BUILT_PRODUCTS_DIR; };
877B9444B69DE32D9CF87354 /* NotifyingDictionary.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotifyingDictionary.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -9235,6 +9238,7 @@
C6675EBA1C4FE96B0041173B /* iTermSelectorSwizzler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTermSelectorSwizzler.h; sourceTree = "<group>"; };
C6675EBB1C4FE96B0041173B /* iTermSelectorSwizzler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTermSelectorSwizzler.m; sourceTree = "<group>"; };
C80C997508DC4BF559F599EB /* UnderlineCompositeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UnderlineCompositeRenderer.swift; sourceTree = "<group>"; };
C9E743E798CA3A96AB8F6168 /* ClaudeCodeStatusPopoverViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ClaudeCodeStatusPopoverViewController.swift; sourceTree = "<group>"; };
CA1C7B91071000DE37B9DA33 /* iTermSessionTabStatus.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = iTermSessionTabStatus.swift; sourceTree = "<group>"; };
CA34A6F29B10471D8FD572F6 /* GlobalJobMonitor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GlobalJobMonitor.swift; sourceTree = "<group>"; };
CB2F48F836C5732146BCEDD9 /* iTermStreamingPNGWriter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = iTermStreamingPNGWriter.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -9623,6 +9627,8 @@
E961A126DE6D9EFA0C6CC9AB /* ClaudeCodeOnboarding.swift */,
81E145AE29B68F8F2A69891A /* iTermLocatedString+ScreenCharArray.swift */,
AF73E7832C84F926A6CE54CA /* iTermOptionalPathRecognizer.swift */,
854E1EAA1B9E2B6D8BA548D0 /* iTermStatusBarClaudeCodeComponent.swift */,
C9E743E798CA3A96AB8F6168 /* ClaudeCodeStatusPopoverViewController.swift */,
);
name = Classes;
path = sources/;
Expand Down Expand Up @@ -20262,6 +20268,8 @@
AA190CE70997D5318EF50177 /* ClaudeCodeOnboarding.swift in Sources */,
8E9796208C12DD69744D3606 /* iTermLocatedString+ScreenCharArray.swift in Sources */,
D7391EB323E94EAC34943C01 /* iTermOptionalPathRecognizer.swift in Sources */,
4B395950B0EF00428363FA75 /* iTermStatusBarClaudeCodeComponent.swift in Sources */,
B9E5F0B3A747133496AC5145 /* ClaudeCodeStatusPopoverViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Loading
Loading