import Foundation import Testing import WireProtocol // T-iOS-3 · 冻结契约常量绊线:Tunables(§3.2.1 唯一取值表)与 WireConstants。 // 这些断言故意逐字重复取值表——改常量必须回 T-iOS-3 改契约并同步这里。 @Test("Tunables 取值与 §3.2.1 表逐项一致") func tunablesMatchFrozenValueTable() { #expect(Tunables.pingInterval == .seconds(25)) #expect(Tunables.pongMissLimit == 2) #expect(Tunables.listPollInterval == .seconds(5)) // public/launcher.ts:30 REFRESH_MS #expect(Tunables.telemetryStaleTtlMs == 30_000) // public/tabs.ts:45 STATUSLINE_TTL_MS #expect(Tunables.digestFadeDelay == .seconds(8)) #expect(Tunables.titleMaxLength == 256) #expect(Tunables.maxWSMessageBytes == 16 * 1024 * 1024) } @Test("maxWSMessageBytes ≥ 6 × 默认 SCROLLBACK_BYTES(2MiB)(JSON 转义最坏膨胀系数)") func maxWSMessageBytesCoversWorstCaseReplayExpansion() { // Arrange — src/config.ts:39 DEFAULT_SCROLLBACK_BYTES = 2MiB;\uXXXX 转义最坏 6× let defaultScrollbackBytes = 2 * 1024 * 1024 let worstCaseEscapeFactor = 6 // Assert #expect(Tunables.maxWSMessageBytes >= worstCaseEscapeFactor * defaultScrollbackBytes) } @Test("WireConstants:wsPath/soft-reset 前缀/spawn 失败码/resize 区间") func wireConstantsMatchServer() { #expect(WireConstants.wsPath == "/term") // src/config.ts:41 DEFAULT_WS_PATH #expect(WireConstants.replaySoftResetPrefix == "\u{1B}[0m") // src/types.ts:167-170 #expect(WireConstants.spawnFailedExitCode == -1) // M4 #expect(WireConstants.resizeRange == 1...1000) // src/protocol.ts:113-115 } @Test("TransportConnection:能力句柄原样保存;frames finish = 干净断线") func transportConnectionHoldsCapabilityHandles() async throws { // Arrange actor Recorder { var sentFrames: [String] = [] var isClosed = false func recordSend(_ frame: String) { sentFrames.append(frame) } func recordClose() { isClosed = true } } let recorder = Recorder() let connection = TransportConnection( frames: AsyncThrowingStream { continuation in continuation.yield("{\"type\":\"output\",\"data\":\"x\"}") continuation.finish() }, send: { await recorder.recordSend($0) }, close: { await recorder.recordClose() } ) // Act var received: [String] = [] for try await frame in connection.frames { received.append(frame) } try await connection.send("{\"type\":\"reject\"}") await connection.close() // Assert #expect(received == ["{\"type\":\"output\",\"data\":\"x\"}"]) #expect(await recorder.sentFrames == ["{\"type\":\"reject\"}"]) #expect(await recorder.isClosed) } @Test("ClaudeStatus/GateKind rawValue 与服务器字面量一致") func statusAndGateRawValuesMatchServer() { #expect(ClaudeStatus.working.rawValue == "working") #expect(ClaudeStatus.waiting.rawValue == "waiting") #expect(ClaudeStatus.idle.rawValue == "idle") #expect(ClaudeStatus.unknown.rawValue == "unknown") #expect(ClaudeStatus.stuck.rawValue == "stuck") #expect(GateKind.tool.rawValue == "tool") #expect(GateKind.plan.rawValue == "plan") }