chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:22:33 +08:00
commit fc4fcbab58
1848 changed files with 472303 additions and 0 deletions
@@ -0,0 +1,86 @@
import Foundation
import Testing
@testable import CodexBarCore
#if os(Linux)
struct AntigravityCLIStrategyLinuxTests {
@Test
func `cli local strategy is available with HTTP fallback`() async throws {
let binaryURL = FileManager.default.temporaryDirectory
.appendingPathComponent("codexbar-antigravity-\(UUID().uuidString)")
try Data("#!/bin/sh\n".utf8).write(to: binaryURL)
try FileManager.default.setAttributes(
[.posixPermissions: 0o755],
ofItemAtPath: binaryURL.path)
defer { try? FileManager.default.removeItem(at: binaryURL) }
let context = ProviderFetchContext(
runtime: .cli,
sourceMode: .cli,
includeCredits: false,
webTimeout: 1,
webDebugDumpHTML: false,
verbose: false,
env: ["ANTIGRAVITY_CLI_PATH": binaryURL.path],
settings: nil,
fetcher: UsageFetcher(environment: [:]),
claudeFetcher: StubClaudeFetcher(),
browserDetection: BrowserDetection(cacheTTL: 0))
let isAvailable = await AntigravityCLIHTTPSFetchStrategy().isAvailable(context)
#expect(isAvailable)
}
@Test
func `cli local endpoints include Linux HTTP fallback`() {
#expect(
AntigravityStatusProbe.cliEndpoints(ports: [55624]) == [
AntigravityStatusProbe.AntigravityConnectionEndpoint(
scheme: "https",
port: 55624,
csrfToken: "",
source: .cliHTTPS),
AntigravityStatusProbe.AntigravityConnectionEndpoint(
scheme: "http",
port: 55624,
csrfToken: "",
source: .cliHTTPS),
])
}
@Test
func `language server endpoints include Linux HTTP fallback`() {
#expect(
AntigravityStatusProbe.connectionCandidates(
listeningPorts: [64440],
languageServerCSRFToken: "language-token",
extensionServerPort: nil,
extensionServerCSRFToken: nil) == [
AntigravityStatusProbe.AntigravityConnectionEndpoint(
scheme: "https",
port: 64440,
csrfToken: "language-token",
source: .languageServer),
AntigravityStatusProbe.AntigravityConnectionEndpoint(
scheme: "http",
port: 64440,
csrfToken: "language-token",
source: .languageServer),
])
}
private struct StubClaudeFetcher: ClaudeUsageFetching {
func loadLatestUsage(model _: String) async throws -> ClaudeUsageSnapshot {
throw ClaudeUsageError.parseFailed("stub")
}
func debugRawProbe(model _: String) async -> String {
"stub"
}
func detectVersion() -> String? {
nil
}
}
}
#endif
@@ -0,0 +1,72 @@
#if canImport(Glibc) || canImport(Musl)
import Foundation
#if canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#endif
import Testing
@testable import CodexBarCore
struct AntigravityProcessLauncherLinuxTests {
@Test
func `pty launcher uses home and closes unrelated descriptors`() throws {
let tempDirectory = FileManager.default.temporaryDirectory
.appendingPathComponent("antigravity-spawn-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true)
defer { try? FileManager.default.removeItem(at: tempDirectory) }
let inheritedSourceFD = open("/dev/null", O_RDONLY)
guard inheritedSourceFD >= 0 else {
Issue.record("Failed to open descriptor fixture")
return
}
defer { close(inheritedSourceFD) }
let inheritedFD = fcntl(inheritedSourceFD, F_DUPFD, 200)
guard inheritedFD >= 200 else {
Issue.record("Failed to duplicate descriptor fixture")
return
}
defer { close(inheritedFD) }
let outputURL = tempDirectory.appendingPathComponent("result.txt")
let scriptURL = tempDirectory.appendingPathComponent("probe.sh")
let script = """
#!/bin/sh
pwd > \(outputURL.path)
if [ -e /proc/self/fd/\(inheritedFD) ]; then
echo inherited >> \(outputURL.path)
else
echo closed >> \(outputURL.path)
fi
"""
// Direct writes close the executable before spawn; atomic replacement can race with exec on overlay
// filesystems.
try Data(script.utf8).write(to: scriptURL)
#expect(chmod(scriptURL.path, 0o700) == 0)
let handle = try AntigravityPTYProcessLauncher().launch(binary: scriptURL.path)
defer {
handle.killRoot()
handle.terminateTree(signal: SIGKILL, knownDescendants: [])
handle.closePTY()
}
for _ in 0..<200 {
if FileManager.default.fileExists(atPath: outputURL.path),
let output = try? String(contentsOf: outputURL, encoding: .utf8)
{
let lines = output
.split(separator: "\n")
.map(String.init)
if lines.count >= 2, output.hasSuffix("\n") { break }
}
Thread.sleep(forTimeInterval: 0.01)
}
let lines = try String(contentsOf: outputURL, encoding: .utf8)
.split(separator: "\n")
.map(String.init)
#expect(lines == [NSHomeDirectory(), "closed"])
}
}
#endif
@@ -0,0 +1,71 @@
import CodexBarCore
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import Testing
@Suite
struct AzureEndpointOverrideSecurityTests {
@Test
func azureOpenAIEndpointOverrideMustBeHTTPSOrBareHost() throws {
let httpsURL = try #require(AzureOpenAISettingsReader.endpointURL(from: "https://proxy.example.com/base"))
#expect(httpsURL.absoluteString == "https://proxy.example.com/base")
let bareURL = try #require(AzureOpenAISettingsReader.endpointURL(from: "resource.openai.azure.com"))
#expect(bareURL.absoluteString == "https://resource.openai.azure.com")
let hostPortURL = try #require(AzureOpenAISettingsReader.endpointURL(from: "localhost:8443/openai"))
#expect(hostPortURL.absoluteString == "https://localhost:8443/openai")
let trimmedURL = try #require(AzureOpenAISettingsReader.endpointURL(from: " https://trimmed.example.com/base "))
#expect(trimmedURL.absoluteString == "https://trimmed.example.com/base")
#expect(AzureOpenAISettingsReader.endpointURL(from: "http://attacker.test") == nil)
#expect(AzureOpenAISettingsReader.endpointURL(from: "https://user:pass@proxy.example.com") == nil)
#expect(AzureOpenAISettingsReader.endpointURL(from: "https://proxy.example.com%2f.attacker.test") == nil)
#expect(throws: AzureOpenAISettingsError.invalidEndpointOverride(
AzureOpenAISettingsReader.endpointEnvironmentKey))
{
try AzureOpenAISettingsReader.validateEndpointOverrides(environment: [
AzureOpenAISettingsReader.endpointEnvironmentKey: "http://attacker.test",
])
}
}
@Test
func azureOpenAIHTTPOverrideIsRejectedBeforeAPIKeyRequest() async throws {
let endpoint = try #require(URL(string: "http://127.0.0.1:31337"))
let transport = CapturingTransport { request in
Issue.record("Azure OpenAI should reject insecure endpoint overrides before sending api-key headers")
#expect(request.value(forHTTPHeaderField: "api-key") == nil)
throw CapturingTransportError.unexpectedRequest
}
do {
_ = try await AzureOpenAIUsageFetcher.fetchUsage(
apiKey: "AZURE_CANARY_KEY",
endpoint: endpoint,
deploymentName: "canary-deployment",
transport: transport,
updatedAt: Date(timeIntervalSince1970: 1_800_000_000))
Issue.record("Expected AzureOpenAIUsageError.invalidEndpointOverride")
} catch {
#expect(error as? AzureOpenAIUsageError == .invalidEndpointOverride(
AzureOpenAISettingsReader.endpointEnvironmentKey))
}
}
}
private enum CapturingTransportError: Error {
case unexpectedRequest
}
private struct CapturingTransport: ProviderHTTPTransport {
let handler: @Sendable (URLRequest) async throws -> (Data, URLResponse)
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
try await self.handler(request)
}
}
+615
View File
@@ -0,0 +1,615 @@
import CodexBarCore
import Foundation
import Testing
@testable import CodexBarCLI
struct CLICardsRendererTests {
@Test
func `computes column count from terminal width`() {
#expect(CLICardsRenderer.columnCount(terminalWidth: 80) == 2)
#expect(CLICardsRenderer.columnCount(terminalWidth: 120) == 3)
#expect(CLICardsRenderer.columnCount(terminalWidth: 160) == 4)
#expect(CLICardsRenderer.columnCount(terminalWidth: 30) == 1)
}
@Test
func `renders single codex card without color`() {
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "pro")
let snapshot = UsageSnapshot(
primary: .init(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: "today at 3:00 PM"),
secondary: .init(usedPercent: 25, windowMinutes: 10080, resetsAt: nil, resetDescription: "Fri at 9:00 AM"),
tertiary: nil,
updatedAt: Date(timeIntervalSince1970: 0),
identity: identity)
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .codex,
snapshot: snapshot,
credits: CreditsSnapshot(remaining: 42, events: [], updatedAt: Date()),
source: "oauth",
status: nil,
notes: [],
useColor: false,
resetStyle: .absolute,
weeklyWorkDays: nil,
now: Date()))
let output = CLICardsRenderer.render(cards: [card], failures: [], terminalWidth: 80, useColor: false)
#expect(output.contains("Codex"))
#expect(output.contains("[oauth]"))
#expect(output.contains("PLAN Pro 20x"))
#expect(output.contains("Session"))
#expect(output.contains("88% left"))
#expect(output.contains("[ "))
#expect(output.contains(""))
#expect(output.contains("Credits:"))
#expect(output.contains("42 left"))
#expect(output.contains("@ user@example.com"))
#expect(output.contains(""))
}
@Test
func `card includes account line`() {
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "pro")
let snapshot = UsageSnapshot(
primary: .init(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: nil,
tertiary: nil,
updatedAt: Date(timeIntervalSince1970: 0),
identity: identity)
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .codex,
snapshot: snapshot,
credits: nil,
source: "cli",
status: nil,
notes: [],
useColor: false,
resetStyle: .absolute,
weeklyWorkDays: nil,
now: Date()))
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: false)
let joined = lines.joined(separator: "\n")
#expect(joined.contains("@ user@example.com"))
#expect(joined.contains("Session"))
#expect(!joined.contains("Plan: Pro 20x"))
}
@Test
func `renders two card grid at fixed width`() {
let codex = CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: "Pro",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 88, resetText: nil)],
extraLines: [],
statusLine: nil)
let claude = CLICardModel(
provider: .claude,
title: "Claude",
sourceLabel: "web",
planBadge: "Max",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 50, resetText: nil)],
extraLines: [],
statusLine: nil)
let output = CLICardsRenderer.render(cards: [codex, claude], failures: [], terminalWidth: 120, useColor: false)
#expect(output.contains("Codex"))
#expect(output.contains("Claude"))
#expect(output.contains("88% left"))
#expect(output.contains("50% left"))
#expect(output.components(separatedBy: "").count >= 3)
}
@Test
func `renders failure footer without cards`() {
let failures = [
CLICardFailure(provider: .cursor, accountLabel: nil, message: "not configured"),
]
let output = CLICardsRenderer.render(cards: [], failures: failures, terminalWidth: 80, useColor: false)
#expect(output.contains("Failed providers:"))
#expect(output.contains("Cursor: not configured"))
}
@Test
func `appends failure footer after successful cards`() {
let card = CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 88, resetText: nil)],
extraLines: [],
statusLine: nil)
let failures = [
CLICardFailure(provider: .grok, accountLabel: nil, message: "timeout"),
]
let output = CLICardsRenderer.render(cards: [card], failures: failures, terminalWidth: 80, useColor: false)
#expect(output.contains("88% left"))
#expect(output.contains("Failed providers:"))
#expect(output.contains("Grok: timeout"))
}
@Test
func `brief mode renders usage table`() {
let card = CLICardModel(
provider: .claude,
title: "Claude",
sourceLabel: "web",
planBadge: "Max",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 2, resetText: "⏳ Resets in 1h 49m")],
extraLines: [],
statusLine: nil)
let rows = CLICardsBriefRenderer.makeRows(cards: [card])
let output = CLICardsBriefRenderer.render(
rows: rows,
failures: [],
terminalWidth: 80,
useColor: false,
now: Date(timeIntervalSince1970: 0))
#expect(output.contains("codexbar • AI Usage & Limits"))
#expect(output.contains("Provider"))
#expect(output.contains("Claude"))
#expect(output.contains("web"))
#expect(output.contains("Max"))
#expect(output.contains("98%"))
#expect(output.contains(""))
#expect(output.contains("1h 49m"))
#expect(output.contains("⚠ Warnings:"))
let tableLine = output.split(separator: "\n").first { $0.hasPrefix("") } ?? ""
#expect(tableLine.count >= 50)
#expect(tableLine.count <= 72)
}
@Test
func `synthetic quota lanes do not replace real brief usage`() {
let snapshot = UsageSnapshot(
primary: .init(
usedPercent: 0,
windowMinutes: 300,
resetsAt: nil,
resetDescription: nil,
isSyntheticPlaceholder: true),
secondary: .init(
usedPercent: 20,
windowMinutes: 10080,
resetsAt: nil,
resetDescription: nil),
tertiary: nil,
updatedAt: Date(timeIntervalSince1970: 0))
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .claude,
snapshot: snapshot,
credits: nil,
source: "oauth",
status: nil,
notes: [],
useColor: false,
resetStyle: .countdown,
weeklyWorkDays: nil,
now: Date(timeIntervalSince1970: 0)))
let rows = CLICardsBriefRenderer.makeRows(cards: [card])
#expect(card.metrics.map(\.label) == ["Weekly"])
#expect(rows.first?.usedPercent == 20)
}
@Test
func `brief reset summary wraps to terminal width`() {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let card = CLICardModel(
provider: .alibabatokenplan,
title: "Alibaba Token Plan",
sourceLabel: "web",
planBadge: "International",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(
label: "Monthly budget",
remainingPercent: 50,
resetText: "⏳ Resets July 30 at 11:59 PM",
resetAt: now.addingTimeInterval(3600))],
extraLines: [],
statusLine: nil)
let output = CLICardsBriefRenderer.render(
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
failures: [],
terminalWidth: 40,
useColor: false,
now: now)
let lines = output.split(separator: "\n", omittingEmptySubsequences: false)
#expect(output.contains("Next reset: Alibaba Token Plan"))
#expect(lines.allSatisfy { $0.count <= 40 })
}
@Test
func `detail backed quota descriptions are not rendered as resets`() {
let snapshot = UsageSnapshot(
primary: .init(
usedPercent: 25,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "25/100 credits"),
secondary: nil,
tertiary: nil,
updatedAt: Date(timeIntervalSince1970: 0))
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .kilo,
snapshot: snapshot,
credits: nil,
source: "api",
status: nil,
notes: [],
useColor: false,
resetStyle: .countdown,
weeklyWorkDays: nil,
now: Date(timeIntervalSince1970: 0)))
#expect(card.metrics.first?.resetText == nil)
#expect(card.metrics.first?.detailText == "25/100 credits")
let output = CLICardsBriefRenderer.render(
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
failures: [],
terminalWidth: 80,
useColor: false,
now: Date(timeIntervalSince1970: 0))
#expect(!output.contains("Next reset"))
#expect(!output.contains("Reset 25/100 credits"))
}
@Test
func `card metrics honor reset display style`() {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let snapshot = UsageSnapshot(
primary: .init(
usedPercent: 25,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
secondary: nil,
tertiary: nil,
updatedAt: now)
let countdown = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .codex,
snapshot: snapshot,
credits: nil,
source: "oauth",
status: nil,
notes: [],
useColor: false,
resetStyle: .countdown,
weeklyWorkDays: nil,
now: now))
let absolute = CLICardsRenderer.makeCard(CLICardBuildInput(
provider: .codex,
snapshot: snapshot,
credits: nil,
source: "oauth",
status: nil,
notes: [],
useColor: false,
resetStyle: .absolute,
weeklyWorkDays: nil,
now: now))
#expect(countdown.metrics.first?.resetText != absolute.metrics.first?.resetText)
#expect(countdown.metrics.first?.resetText?.contains("in 1h") == true)
#expect(absolute.metrics.first?.resetAt == now.addingTimeInterval(3600))
}
@Test
func `long detail rows stay within card width`() {
let card = CLICardModel(
provider: .clawrouter,
title: "ClawRouter",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: ["Workspace: " + String(repeating: "long-name-", count: 12)],
metrics: [],
extraLines: [],
statusLine: nil)
let lines = CLICardsRenderer.renderCard(card, width: 38, useColor: true, enhanced: true)
#expect(lines.allSatisfy { TextParsing.stripANSICodes($0).count == 38 })
}
@Test
func `brief warnings name the actual quota metric`() {
let card = CLICardModel(
provider: .openrouter,
title: "OpenRouter",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Spend", remainingPercent: 10, resetText: nil)],
extraLines: [],
statusLine: nil)
let output = CLICardsBriefRenderer.render(
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
failures: [],
terminalWidth: 80,
useColor: false,
now: Date(timeIntervalSince1970: 0))
#expect(output.contains("OpenRouter Spend: 90% used"))
#expect(!output.contains("session limit"))
}
@Test
func `brief rows preserve account identity`() {
let cards = [
CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: "Pro",
accountLine: "one@x.dev",
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 80, resetText: nil)],
extraLines: [],
statusLine: nil),
CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: "Pro",
accountLine: "two@x.dev",
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 60, resetText: nil)],
extraLines: [],
statusLine: nil),
]
let output = CLICardsBriefRenderer.render(
rows: CLICardsBriefRenderer.makeRows(cards: cards),
failures: [],
terminalWidth: 80,
useColor: false,
now: Date(timeIntervalSince1970: 0))
#expect(output.contains("one@x.dev"))
#expect(output.contains("two@x.dev"))
}
@Test
func `brief warnings wrap to terminal width`() {
let cards = ["OpenRouter", "Antigravity", "CommandCode"].map { title in
CLICardModel(
provider: .openrouter,
title: title,
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Monthly budget", remainingPercent: 5, resetText: nil)],
extraLines: [],
statusLine: nil)
}
let output = CLICardsBriefRenderer.render(
rows: CLICardsBriefRenderer.makeRows(cards: cards),
failures: [],
terminalWidth: 40,
useColor: false,
now: Date(timeIntervalSince1970: 0))
let warningLines = output.split(separator: "\n").filter {
$0.contains("Warnings:") || $0.contains("% used")
}
#expect(warningLines.count > 1)
#expect(warningLines.allSatisfy { $0.count <= 40 })
}
@Test
func `brief summary ignores unparseable reset labels and fits narrow terminals`() {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let rows = CLICardsBriefRenderer.makeRows(cards: [
CLICardModel(
provider: .kilo,
title: "Kilo",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Credits", remainingPercent: 75, resetText: "Reset Unlimited")],
extraLines: [],
statusLine: nil),
CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: "Pro",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(
label: "Session",
remainingPercent: 50,
resetText: "⏳ Resets in 5h",
resetAt: now.addingTimeInterval(5 * 3600))],
extraLines: [],
statusLine: nil),
])
let output = CLICardsBriefRenderer.render(
rows: rows,
failures: [],
terminalWidth: 40,
useColor: false,
now: now)
let lines = output.split(separator: "\n", omittingEmptySubsequences: false)
#expect(output.contains("Next reset: Codex in 5h"))
#expect(!output.contains("Next reset: Kilo"))
#expect(lines.allSatisfy { $0.count <= 40 })
}
@Test
func `enhanced brief mode fills bars from used percentage`() {
let rows = CLICardsBriefRenderer.makeRows(cards: [
CLICardModel(
provider: .codex,
title: "Unused",
sourceLabel: "oauth",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 100, resetText: nil)],
extraLines: [],
statusLine: nil),
CLICardModel(
provider: .openrouter,
title: "Exhausted",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
extraLines: [],
statusLine: nil),
])
let output = CLICardsBriefRenderer.render(
rows: rows,
failures: [],
terminalWidth: 80,
useColor: true,
enhanced: true,
now: Date(timeIntervalSince1970: 0))
let plainLines = TextParsing.stripANSICodes(output).split(separator: "\n")
let unusedLine = String(plainLines.first { $0.contains("Unused") } ?? "")
let exhaustedLine = String(plainLines.first { $0.contains("Exhausted") } ?? "")
#expect(unusedLine.contains("0%"))
#expect(unusedLine.filter { $0 == "" }.isEmpty)
#expect(exhaustedLine.contains("100%"))
#expect(exhaustedLine.filter { $0 == "" }.isEmpty)
}
@Test
func `standard brief mode fills bars from used percentage`() {
let rows = CLICardsBriefRenderer.makeRows(cards: [
CLICardModel(
provider: .codex,
title: "Unused",
sourceLabel: "oauth",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 100, resetText: nil)],
extraLines: [],
statusLine: nil),
CLICardModel(
provider: .openrouter,
title: "Exhausted",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
extraLines: [],
statusLine: nil),
])
let output = CLICardsBriefRenderer.render(
rows: rows,
failures: [],
terminalWidth: 80,
useColor: false,
enhanced: false,
now: Date(timeIntervalSince1970: 0))
let plainLines = output.split(separator: "\n")
let unusedLine = String(plainLines.first { $0.contains("Unused") } ?? "")
let exhaustedLine = String(plainLines.first { $0.contains("Exhausted") } ?? "")
#expect(unusedLine.contains("0%"))
#expect(unusedLine.filter { $0 == "" }.isEmpty)
#expect(exhaustedLine.contains("100%"))
#expect(exhaustedLine.filter { $0 == "" }.isEmpty)
}
@Test
func `standard card grid shows empty remaining bar at exhaustion`() {
let card = CLICardModel(
provider: .openrouter,
title: "Exhausted",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
extraLines: [],
statusLine: nil)
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: false, enhanced: false)
let barLine = String(lines.first { $0.contains("[ ") && $0.contains("]") } ?? "")
#expect(barLine.filter { $0 == "" }.isEmpty)
}
@Test
func `enhanced card grid shows empty remaining bar at exhaustion`() {
let card = CLICardModel(
provider: .openrouter,
title: "Exhausted",
sourceLabel: "api",
planBadge: nil,
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
extraLines: [],
statusLine: nil)
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: true, enhanced: true)
let plainBarLine = TextParsing.stripANSICodes(
String(lines.first { $0.contains("[ ") && $0.contains("]") } ?? ""))
#expect(plainBarLine.filter { !$0.isWhitespace && $0 != "" && $0 != "[" && $0 != "]" }.isEmpty)
}
@Test
func `enhanced mode uses truecolor gradient bars`() {
let card = CLICardModel(
provider: .codex,
title: "Codex",
sourceLabel: "oauth",
planBadge: "Pro",
accountLine: nil,
infoLines: [],
metrics: [CLICardMetric(label: "Session", remainingPercent: 50, resetText: nil)],
extraLines: [],
statusLine: nil)
let output = CLICardsRenderer.render(
cards: [card],
failures: [],
terminalWidth: 80,
useColor: true,
enhanced: true)
#expect(output.contains("38;2;"))
#expect(output.contains("48;2;"))
#expect(output.contains("[ "))
}
}
@@ -0,0 +1,49 @@
import Foundation
import Testing
@testable import CodexBarCLI
struct CLITerminalCapabilitiesTests {
@Test
func `detects kitty graphics backend`() {
let env = ["KITTY_WINDOW_ID": "1", "TERM": "xterm-kitty"]
#expect(CLITerminalCapabilities.detect(environment: env) == .kittyGraphics)
#expect(CLITerminalCapabilities.supportsEnhancedCards(useColor: true, environment: env))
}
@Test
func `detects ghostty backend`() {
let env = ["GHOSTTY_RESOURCES_DIR": "/usr/share/ghostty", "TERM": "xterm-ghostty"]
#expect(CLITerminalCapabilities.detect(environment: env) == .kittyGraphics)
}
@Test
func `detects truecolor without graphics env`() {
let env = ["COLORTERM": "truecolor", "TERM": "alacritty"]
#expect(CLITerminalCapabilities.detect(environment: env) == .truecolor)
}
@Test
func `respects forced enhanced env override`() {
let env = ["TERM": "dumb", "CODEXBAR_CARDS_ENHANCED": "1"]
#expect(CLITerminalCapabilities.supportsEnhancedCards(useColor: true, environment: env))
}
@Test
func `defaults cards to standard on plain ansi terminals`() {
let env = ["TERM": "xterm-256color"]
#expect(!CLITerminalCapabilities.supportsEnhancedCards(useColor: true, environment: env))
#expect(!CLITerminalCapabilities.supportsEnhancedCards(useColor: false, environment: env))
}
@Test
func `defaults cards to enhanced on truecolor terminals`() {
let env = ["TERM": "xterm-256color", "COLORTERM": "truecolor"]
#expect(CLITerminalCapabilities.supportsEnhancedCards(useColor: true, environment: env))
}
@Test
func `respects forced enhanced opt out`() {
let env = ["TERM": "xterm-256color", "CODEXBAR_CARDS_ENHANCED": "0"]
#expect(!CLITerminalCapabilities.supportsEnhancedCards(useColor: true, environment: env))
}
}
@@ -0,0 +1,27 @@
import Foundation
import Testing
@testable import CodexBarCore
struct ClaudeOAuthCredentialHistoryLinuxTests {
@Test
func historyOwnerIdentifierUsesSwiftCrypto() throws {
let first = ClaudeOAuthCredentials(
accessToken: "access-token-a",
refreshToken: "refresh-token-a",
expiresAt: Date(timeIntervalSinceNow: 3600),
scopes: ["user:profile"],
rateLimitTier: nil)
let second = ClaudeOAuthCredentials(
accessToken: "access-token-b",
refreshToken: "refresh-token-b",
expiresAt: Date(timeIntervalSinceNow: 3600),
scopes: ["user:profile"],
rateLimitTier: nil)
let firstIdentifier = try #require(first.historyOwnerIdentifier)
let secondIdentifier = try #require(second.historyOwnerIdentifier)
#expect(firstIdentifier.count == 64)
#expect(firstIdentifier != secondIdentifier)
#expect(firstIdentifier.allSatisfy { $0.isHexDigit })
}
}
@@ -0,0 +1,167 @@
import Foundation
import Testing
@testable import CodexBarCore
@Suite(.serialized)
struct ClaudeOAuthDelegatedRefreshLinuxTests {
private actor Counter {
private var value = 0
func increment() {
self.value += 1
}
func current() -> Int {
self.value
}
}
private actor VersionDetectionCapture {
private var value: Bool?
func record(_ value: Bool) {
self.value = value
}
func current() -> Bool? {
self.value
}
}
@Test
func cliOAuthSkipsVersionDetectionWhileAppPreservesIt() async throws {
#expect(try await self.detectsClaudeVersion(runtime: .cli) == false)
#expect(try await self.detectsClaudeVersion(runtime: .app) == true)
}
@Test
func cliOAuthDoesNotDelegateRefreshEvenForUserAction() async {
let result = await self.runDelegatedRefresh(
runtime: .cli,
interaction: .userInitiated,
promptMode: .always)
#expect(result.attempts == 0)
#expect(result.message.contains("CodexBar CLI does not launch Claude"))
}
@Test
func appOAuthPreservesUserInitiatedDelegatedRefresh() async {
let result = await self.runDelegatedRefresh(
runtime: .app,
interaction: .userInitiated,
promptMode: .onlyOnUserAction)
#expect(result.attempts == 1)
#expect(result.message.contains("still unavailable after delegated Claude CLI refresh"))
}
@Test
func appOAuthBackgroundRespectsPlatformKeychainPromptPolicy() async {
let result = await self.runDelegatedRefresh(
runtime: .app,
interaction: .background,
promptMode: .onlyOnUserAction)
#expect(result.attempts == 0)
#expect(result.message.contains("background repair is suppressed"))
}
private func runDelegatedRefresh(
runtime: ProviderRuntime,
interaction: ProviderInteraction,
promptMode: ClaudeOAuthKeychainPromptMode) async -> (attempts: Int, message: String)
{
let counter = Counter()
let fetcher = ClaudeUsageFetcher(
browserDetection: BrowserDetection(cacheTTL: 0),
environment: [:],
runtime: runtime,
dataSource: .oauth)
let credentialsOverride: @Sendable (
[String: String],
Bool,
Bool) async throws -> ClaudeOAuthCredentials = { _, _, _ in
throw ClaudeOAuthCredentialsError.refreshDelegatedToClaudeCLI
}
let delegatedOverride: @Sendable (
Date,
TimeInterval,
[String: String]) async -> ClaudeOAuthDelegatedRefreshCoordinator.Outcome = { _, _, _ in
await counter.increment()
return .attemptedSucceeded
}
do {
_ = try await ClaudeOAuthKeychainPromptPreference.withTaskOverrideForTesting(promptMode) {
try await ProviderInteractionContext.$current.withValue(interaction) {
try await ClaudeUsageFetcher.$loadOAuthCredentialsOverride
.withValue(credentialsOverride) {
try await ClaudeUsageFetcher.$delegatedRefreshAttemptOverride
.withValue(delegatedOverride) {
try await fetcher.loadLatestUsage(model: "sonnet")
}
}
}
}
Issue.record("Expected delegated-refresh path to fail with mocked stale credentials")
return (await counter.current(), "")
} catch let error as ClaudeUsageError {
guard case let .oauthFailed(message) = error else {
Issue.record("Expected ClaudeUsageError.oauthFailed, got \(error)")
return (await counter.current(), "")
}
return (await counter.current(), message)
} catch {
Issue.record("Expected ClaudeUsageError, got \(error)")
return (await counter.current(), "")
}
}
private func detectsClaudeVersion(runtime: ProviderRuntime) async throws -> Bool {
let capture = VersionDetectionCapture()
let fetcher = ClaudeUsageFetcher(
browserDetection: BrowserDetection(cacheTTL: 0),
environment: [:],
runtime: runtime,
dataSource: .oauth)
let credentialsOverride: @Sendable (
[String: String],
Bool,
Bool) async throws -> ClaudeOAuthCredentials = { _, _, _ in
ClaudeOAuthCredentials(
accessToken: "access-token",
refreshToken: nil,
expiresAt: Date(timeIntervalSinceNow: 3600),
scopes: ["user:profile"],
rateLimitTier: nil)
}
let fetchOverride: @Sendable (String, Bool) async throws -> OAuthUsageResponse = {
_, detectClaudeVersion in
await capture.record(detectClaudeVersion)
return try Self.makeOAuthUsageResponse()
}
_ = try await ClaudeUsageFetcher.$loadOAuthCredentialsOverride.withValue(credentialsOverride) {
try await ClaudeUsageFetcher.$fetchOAuthUsageOverride.withValue(fetchOverride) {
try await fetcher.loadLatestUsage(model: "sonnet")
}
}
guard let value = await capture.current() else {
Issue.record("Expected OAuth fetch to report its version-detection policy")
return false
}
return value
}
private static func makeOAuthUsageResponse() throws -> OAuthUsageResponse {
let json = """
{
"five_hour": { "utilization": 7, "resets_at": "2025-12-23T16:00:00.000Z" },
"seven_day": { "utilization": 21, "resets_at": "2025-12-29T23:00:00.000Z" }
}
"""
return try ClaudeOAuthUsageFetcher._decodeUsageResponseForTesting(Data(json.utf8))
}
}
@@ -0,0 +1,82 @@
import Logging
import Testing
@testable import CodexBarCore
@Suite(.serialized)
struct CodexBarLoggingPerformanceTests {
@Test
func `filtered log messages are not evaluated`() {
let probe = LogEvaluationProbe()
let logger = CodexBarLogger(minimumLevel: .info) { _, message, _ in
probe.loggedMessages.append(message)
}
logger.debug(probe.expensiveMessage())
#expect(probe.evaluations == 0)
#expect(probe.loggedMessages.isEmpty)
logger.info(probe.expensiveMessage())
#expect(probe.evaluations == 1)
#expect(probe.loggedMessages == ["evaluated"])
}
@Test
func `disabled file logging does not format metadata`() {
let sink = FileLogSink()
var handler = FileLogHandler(label: "test", sink: sink)
let probe = LogEvaluationProbe()
handler[metadataKey: "expensive"] = .stringConvertible(ExpensiveMetadataValue {
probe.evaluations += 1
})
handler.log(event: LogEvent(
level: .info,
message: "hello",
metadata: nil,
source: "test",
file: #filePath,
function: #function,
line: #line))
#expect(probe.evaluations == 0)
}
@Test
func `redactor leaves ordinary log lines unchanged`() {
let line = "CodexBar starting version=1.2.3 build=456"
#expect(LogRedactor.redact(line) == line)
}
@Test
func `redactor still redacts sensitive log lines`() {
let line = "Authorization: Bearer secret-token\nContact: user@example.com"
let redacted = LogRedactor.redact(line)
#expect(redacted.contains("secret-token") == false)
#expect(redacted.contains("user@example.com") == false)
#expect(redacted.contains("Authorization: <redacted>"))
#expect(redacted.contains("<redacted-email>"))
}
}
private final class LogEvaluationProbe: @unchecked Sendable {
var evaluations = 0
var loggedMessages: [String] = []
func expensiveMessage() -> String {
self.evaluations += 1
return "evaluated"
}
}
private struct ExpensiveMetadataValue: CustomStringConvertible, Sendable {
let onRender: @Sendable () -> Void
var description: String {
self.onRender()
return "rendered"
}
}
@@ -0,0 +1,31 @@
import Foundation
import Testing
@testable import CodexBarCore
@Suite
struct CodexOAuthCredentialsStoreLinuxTests {
@Test
func saveKeepsAuthJSONPrivate() throws {
#if os(macOS) || os(Linux)
let codexHome = FileManager.default.temporaryDirectory
.appendingPathComponent("codex-oauth-permissions-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager.default.removeItem(at: codexHome) }
let credentials = CodexOAuthCredentials(
accessToken: "access-token",
refreshToken: "refresh-token",
idToken: "id-token",
accountId: "account-123",
lastRefresh: Date())
try CodexOAuthCredentialsStore.save(credentials, env: ["CODEX_HOME": codexHome.path])
let authURL = codexHome.appendingPathComponent("auth.json")
let attributes = try FileManager.default.attributesOfItem(atPath: authURL.path)
let permissions = try #require(attributes[.posixPermissions] as? NSNumber)
#expect(permissions.intValue & 0o777 == 0o600)
#else
#expect(Bool(true))
#endif
}
}
@@ -0,0 +1,29 @@
import CodexBarCore
import Foundation
import Testing
@Suite
struct CostUsageScanExecutorLinuxTests {
@Test
func returnsWorkValue() async throws {
let value = try await CostUsageScanExecutor.run { _ in 42 }
#expect(value == 42)
}
@Test
func cancelledTaskThrowsCancellationError() async {
let task = Task {
try await CostUsageScanExecutor.run { checkCancellation in
while true {
try checkCancellation()
Thread.sleep(forTimeInterval: 0.005)
}
}
}
task.cancel()
await #expect(throws: CancellationError.self) {
try await task.value
}
}
}
+66
View File
@@ -0,0 +1,66 @@
#if os(Linux)
import Foundation
import Testing
@testable import CodexBarCLI
@testable import CodexBarCore
struct CursorLinuxTests {
@Test
func `Cursor database path honors absolute XDG config home`() {
let path = CursorAppAuthStore.resolveDefaultDBPath(
home: "/home/test",
environment: ["XDG_CONFIG_HOME": "/custom/config"])
#expect(path == "/custom/config/Cursor/User/globalStorage/state.vscdb")
}
@Test
func `Cursor database path falls back to dot config`() {
let path = CursorAppAuthStore.resolveDefaultDBPath(
home: "/home/test",
environment: [:])
#expect(path == "/home/test/.config/Cursor/User/globalStorage/state.vscdb")
}
@Test
func `Cursor database path rejects relative XDG config home`() {
let path = CursorAppAuthStore.resolveDefaultDBPath(
home: "/home/test",
environment: ["XDG_CONFIG_HOME": "relative/config"])
#expect(path == "/home/test/.config/Cursor/User/globalStorage/state.vscdb")
}
@Test
func `Cursor automatic source does not require macOS web support`() {
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(
.auto,
provider: .cursor,
settings: ProviderSettingsSnapshot.make(
cursor: .init(cookieSource: .auto, manualCookieHeader: nil))))
}
@Test
func `Cursor descriptor accepts explicit web source`() {
#expect(CursorProviderDescriptor.descriptor.fetchPlan.sourceModes.contains(.web))
}
@Test
func `Cursor manual cookie does not require macOS web support`() {
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(
.web,
provider: .cursor,
settings: ProviderSettingsSnapshot.make(
cursor: .init(
cookieSource: .manual,
manualCookieHeader: "WorkosCursorSessionToken=test"))))
}
@Test
func `disabled Cursor web source still requires macOS web support`() {
#expect(CodexBarCLI.sourceModeRequiresWebSupport(
.web,
provider: .cursor,
settings: ProviderSettingsSnapshot.make(
cursor: .init(cookieSource: .off, manualCookieHeader: nil))))
}
}
#endif
+190
View File
@@ -0,0 +1,190 @@
import CodexBarCore
import Foundation
import Testing
/// Tests for the regex-based JetBrains XML parser used on Linux.
/// These tests verify that the non-libxml2 implementation correctly parses
/// JetBrains AI Assistant quota files.
@Suite
struct JetBrainsParserLinuxTests {
@Test
func parsesQuotaXMLWithBothOptions() throws {
let quotaInfo = [
"{&#10; &quot;type&quot;: &quot;Available&quot;,",
"&#10; &quot;current&quot;: &quot;7478.3&quot;,",
"&#10; &quot;maximum&quot;: &quot;1000000&quot;,",
"&#10; &quot;until&quot;: &quot;2026-11-09T21:00:00Z&quot;,",
"&#10; &quot;tariffQuota&quot;: {",
"&#10; &quot;current&quot;: &quot;7478.3&quot;,",
"&#10; &quot;maximum&quot;: &quot;1000000&quot;,",
"&#10; &quot;available&quot;: &quot;992521.7&quot;",
"&#10; }&#10;}",
].joined()
let nextRefill = [
"{&#10; &quot;type&quot;: &quot;Known&quot;,",
"&#10; &quot;next&quot;: &quot;2026-01-16T14:00:54.939Z&quot;,",
"&#10; &quot;tariff&quot;: {",
"&#10; &quot;amount&quot;: &quot;1000000&quot;,",
"&#10; &quot;duration&quot;: &quot;PT720H&quot;",
"&#10; }&#10;}",
].joined()
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
<option name="quotaInfo" value="\(quotaInfo)" />
<option name="nextRefill" value="\(nextRefill)" />
</component>
</application>
"""
let data = Data(xml.utf8)
let snapshot = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
#expect(snapshot.quotaInfo.type == "Available")
#expect(snapshot.quotaInfo.used == 7478.3)
#expect(snapshot.quotaInfo.maximum == 1_000_000)
#expect(snapshot.quotaInfo.available == 992_521.7)
#expect(snapshot.refillInfo?.type == "Known")
#expect(snapshot.refillInfo?.amount == 1_000_000)
}
@Test
func parsesQuotaXMLWithOnlyQuotaInfo() throws {
let quotaInfo = "{&quot;type&quot;:&quot;free&quot;,&quot;current&quot;:&quot;5000&quot;,&quot;maximum&quot;:&quot;100000&quot;}"
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
<option name="quotaInfo" value="\(quotaInfo)" />
</component>
</application>
"""
let data = Data(xml.utf8)
let snapshot = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
#expect(snapshot.quotaInfo.type == "free")
#expect(snapshot.quotaInfo.used == 5000)
#expect(snapshot.quotaInfo.maximum == 100_000)
#expect(snapshot.refillInfo == nil)
}
@Test
func parsesXMLWithReversedAttributeOrder() throws {
// Test that parser handles value before name (different attribute order)
let quotaInfo = "{&quot;type&quot;:&quot;paid&quot;,&quot;current&quot;:&quot;1000&quot;,&quot;maximum&quot;:&quot;50000&quot;}"
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
<option value="\(quotaInfo)" name="quotaInfo" />
</component>
</application>
"""
let data = Data(xml.utf8)
let snapshot = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
#expect(snapshot.quotaInfo.type == "paid")
#expect(snapshot.quotaInfo.used == 1000)
#expect(snapshot.quotaInfo.maximum == 50000)
}
@Test
func handlesHTMLEntities() throws {
let quotaInfo = [
"{&quot;type&quot;:&quot;test&quot;",
",&quot;current&quot;:&quot;0&quot;",
",&quot;maximum&quot;:&quot;50000&quot;}",
].joined()
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
<option name="quotaInfo" value="\(quotaInfo)" />
</component>
</application>
"""
let data = Data(xml.utf8)
let snapshot = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
#expect(snapshot.quotaInfo.type == "test")
#expect(snapshot.quotaInfo.maximum == 50000)
}
@Test
func throwsOnMissingQuotaInfo() throws {
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
</component>
</application>
"""
let data = Data(xml.utf8)
#expect(throws: JetBrainsStatusProbeError.noQuotaInfo) {
_ = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
}
}
@Test
func throwsOnMissingComponent() throws {
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="SomeOtherComponent">
<option name="quotaInfo" value="{}" />
</component>
</application>
"""
let data = Data(xml.utf8)
#expect(throws: JetBrainsStatusProbeError.noQuotaInfo) {
_ = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
}
}
@Test
func throwsOnEmptyQuotaInfo() throws {
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name="AIAssistantQuotaManager2">
<option name="quotaInfo" value="" />
</component>
</application>
"""
let data = Data(xml.utf8)
#expect(throws: JetBrainsStatusProbeError.noQuotaInfo) {
_ = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
}
}
@Test
func parsesXMLWithSingleQuotes() throws {
let quotaInfo = "{&quot;type&quot;:&quot;single&quot;,&quot;current&quot;:&quot;100&quot;,&quot;maximum&quot;:&quot;10000&quot;}"
let xml = """
<?xml version="1.0" encoding="UTF-8"?>
<application>
<component name='AIAssistantQuotaManager2'>
<option name='quotaInfo' value='\(quotaInfo)' />
</component>
</application>
"""
let data = Data(xml.utf8)
let snapshot = try JetBrainsStatusProbe.parseXMLData(data, detectedIDE: nil)
#expect(snapshot.quotaInfo.type == "single")
#expect(snapshot.quotaInfo.maximum == 10000)
}
}
@@ -0,0 +1,60 @@
import CodexBarCore
import Foundation
import Testing
/// Cross-platform tests for the OpenAI dashboard text parser.
///
/// The dashboard renders reset countdowns like "Resets Wednesday at 3pm". The parser
/// converts a textual weekday into the next occurrence of that weekday so it can be
/// formatted into a concrete `Date`. These tests pin down full-weekday-name coverage
/// because the underlying regex previously missed "Wednesday" and "Saturday" (their
/// abbreviations were not long enough to combine with the optional "day" suffix).
@Suite
struct OpenAIDashboardParserLinuxTests {
private static func fixedNow() -> Date {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
// 2026-05-21 is a Thursday in the Gregorian calendar; using a fixed anchor keeps
// the test deterministic regardless of when it executes.
return calendar.date(from: DateComponents(year: 2026, month: 5, day: 21))!
}
private static func body(forWeekday weekday: String) -> String {
"""
5h limit
50% remaining
Resets \(weekday)
"""
}
@Test
func parsesResetLineForEveryFullWeekdayName() {
let now = Self.fixedNow()
for weekday in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] {
let result = OpenAIDashboardParser.parseRateLimits(
bodyText: Self.body(forWeekday: weekday),
now: now)
#expect(
result.primary?.resetsAt != nil,
"Expected a parsed resetsAt for weekday \(weekday)")
}
}
@Test
func parsesResetLineForLowercaseWednesday() {
let now = Self.fixedNow()
let result = OpenAIDashboardParser.parseRateLimits(
bodyText: Self.body(forWeekday: "wednesday"),
now: now)
#expect(result.primary?.resetsAt != nil)
}
@Test
func parsesResetLineForLowercaseSaturday() {
let now = Self.fixedNow()
let result = OpenAIDashboardParser.parseRateLimits(
bodyText: Self.body(forWeekday: "saturday"),
now: now)
#expect(result.primary?.resetsAt != nil)
}
}
+74
View File
@@ -0,0 +1,74 @@
import CodexBarCore
import Foundation
import Testing
@testable import CodexBarCLI
#if canImport(SQLite3)
import SQLite3
#elseif canImport(CSQLite3)
import CSQLite3
#endif
#if canImport(SQLite3) || canImport(CSQLite3)
@Suite
struct OpenCodeGoLinuxTests {
@Test
func autoSourceDoesNotRequireWebSupport() {
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(.auto, provider: .opencodego))
#expect(CodexBarCLI.sourceModeRequiresWebSupport(.web, provider: .opencodego))
}
@Test
func commandCodeManualCookieDoesNotRequireMacOSWebSupport() {
let settings = ProviderSettingsSnapshot.make(
commandcode: .init(cookieSource: .manual, manualCookieHeader: "session=manual"))
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(
.auto,
provider: .commandcode,
settings: settings))
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(
.web,
provider: .commandcode,
settings: settings))
}
@Test
func localReaderLoadsOpenCodeDatabase() throws {
let root = FileManager.default.temporaryDirectory
.appendingPathComponent("OpenCodeGoLinuxTests-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager.default.removeItem(at: root) }
try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
let databaseURL = root.appendingPathComponent("opencode.db")
let authURL = root.appendingPathComponent("auth.json")
let now = Date(timeIntervalSince1970: 1_800_000_000)
let createdMs = Int64((now.timeIntervalSince1970 - 60) * 1000)
try Self.createDatabase(at: databaseURL, createdMs: createdMs)
let snapshot = try OpenCodeGoLocalUsageReader(authURL: authURL, databaseURL: databaseURL).fetch(now: now)
#expect(snapshot.rollingUsagePercent == 50)
#expect(snapshot.weeklyUsagePercent == 20)
#expect(snapshot.monthlyUsagePercent == 10)
}
private static func createDatabase(at url: URL, createdMs: Int64) throws {
var database: OpaquePointer?
guard sqlite3_open(url.path, &database) == SQLITE_OK else {
sqlite3_close(database)
throw OpenCodeGoLocalUsageError.sqliteFailed("open failed")
}
defer { sqlite3_close(database) }
let data = "{\"time\":{\"created\":\(createdMs)},\"cost\":6,\"providerID\":\"opencode-go\",\"role\":\"assistant\"}"
let sql = """
CREATE TABLE message (id TEXT PRIMARY KEY, time_created INTEGER NOT NULL, data TEXT NOT NULL);
INSERT INTO message (id, time_created, data) VALUES ('message-1', \(createdMs), '\(data)');
"""
guard sqlite3_exec(database, sql, nil, nil, nil) == SQLITE_OK else {
throw OpenCodeGoLocalUsageError.sqliteFailed("fixture creation failed")
}
}
}
#endif
+257
View File
@@ -0,0 +1,257 @@
import Foundation
import Testing
@testable import CodexBarCLI
@testable import CodexBarCore
@Suite
struct PlatformGatingTests {
@Test
func `shell probe requests a detached Linux session`() {
#if os(Linux)
#expect(ShellCommandLocator.test_shellSpawnFlags == 0x80)
#else
#expect(Bool(true))
#endif
}
@Test
func ampAutoSource_doesNotRequireWebSupport() {
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(.auto, provider: .amp))
}
@Test
func claudeAutoSource_allowsPlannerToFallBackToCLI() {
#expect(!CodexBarCLI.sourceModeRequiresWebSupport(.auto, provider: .claude))
#expect(CodexBarCLI.sourceModeRequiresWebSupport(.web, provider: .claude))
}
@Test
func claudeAutoPipeline_skipsUnsupportedWebAndUsesCLI() async throws {
#if os(Linux)
let binaryURL = try Self.makeClaudeCLI(loggedIn: true)
defer { try? FileManager.default.removeItem(at: binaryURL) }
let context = self.makeClaudeAutoContext(env: ["CLAUDE_CLI_PATH": binaryURL.path])
let cliFetchOverride: ClaudeStatusProbe.FetchOverride = { _, _, _ in
Self.makeClaudeStatus()
}
let outcome = await ClaudeStatusProbe.withFetchOverrideForTesting(cliFetchOverride) {
await ClaudeProviderDescriptor.makeDescriptor().fetchPlan.fetchOutcome(
context: context,
provider: .claude)
}
let result = try outcome.result.get()
#expect(result.strategyID == "claude.cli")
#expect(outcome.attempts.map(\.strategyID) == ["claude.web", "claude.cli"])
#expect(outcome.attempts.map(\.wasAvailable) == [false, true])
#else
#expect(Bool(true))
#endif
}
@Test
func claudeAutoPipeline_withoutCLIReportsNoAvailableStrategy() async {
#if os(Linux)
let context = self.makeClaudeAutoContext()
let outcome = await ClaudeCLIResolver.withResolvedBinaryPathOverrideForTesting(
"/definitely/missing/claude")
{
await ClaudeProviderDescriptor.makeDescriptor().fetchPlan.fetchOutcome(
context: context,
provider: .claude)
}
switch outcome.result {
case .success:
Issue.record("Expected Claude auto without a CLI to report no available strategy")
case let .failure(error):
guard let fetchError = error as? ProviderFetchError else {
Issue.record("Expected ProviderFetchError, got \(error)")
return
}
switch fetchError {
case let .noAvailableStrategy(provider):
#expect(provider == .claude)
}
}
#expect(outcome.attempts.map(\.strategyID) == ["claude.web", "claude.cli"])
#expect(outcome.attempts.map(\.wasAvailable) == [false, false])
#else
#expect(Bool(true))
#endif
}
@Test(arguments: [ProviderSourceMode.auto, .cli])
func `Claude CLI runtime skips logged out interactive fallback`(sourceMode: ProviderSourceMode) async throws {
#if os(Linux)
let invocationLog = FileManager.default.temporaryDirectory
.appendingPathComponent("claude-cli-runtime-invocations-\(UUID().uuidString).log")
let binaryURL = try Self.makeClaudeCLI(loggedIn: false, invocationLog: invocationLog)
defer {
try? FileManager.default.removeItem(at: binaryURL)
try? FileManager.default.removeItem(at: invocationLog)
}
let context = self.makeClaudeContext(
sourceMode: sourceMode,
env: ["CLAUDE_CLI_PATH": binaryURL.path])
let cliFetchOverride: ClaudeStatusProbe.FetchOverride = { _, _, _ in
Issue.record("Logged-out Claude CLI reached the interactive usage probe")
return Self.makeClaudeStatus()
}
let outcome = await ClaudeStatusProbe.withFetchOverrideForTesting(cliFetchOverride) {
await ClaudeProviderDescriptor.makeDescriptor().fetchPlan.fetchOutcome(
context: context,
provider: .claude)
}
switch outcome.result {
case .success:
Issue.record("Expected logged-out Claude CLI to report no available strategy")
case let .failure(error):
guard let fetchError = error as? ProviderFetchError else {
Issue.record("Expected ProviderFetchError, got \(error)")
return
}
switch fetchError {
case let .noAvailableStrategy(provider):
#expect(provider == .claude)
}
}
let expectedStrategyIDs = sourceMode == .auto ? ["claude.web", "claude.cli"] : ["claude.cli"]
#expect(outcome.attempts.map(\.strategyID) == expectedStrategyIDs)
#expect(outcome.attempts.allSatisfy { !$0.wasAvailable })
#expect(try String(contentsOf: invocationLog, encoding: .utf8) == "auth status --json\n")
#else
#expect(Bool(true))
#endif
}
@Test
func claudeOAuthUsageDoesNotDetectCLIVersion() {
#expect(!CodexBarCLI.shouldDetectVersion(
provider: .claude,
result: self.makeResult(kind: .oauth)))
#expect(CodexBarCLI.shouldDetectVersion(
provider: .claude,
result: self.makeResult(kind: .cli)))
#expect(CodexBarCLI.shouldDetectVersion(
provider: .codex,
result: self.makeResult(kind: .oauth)))
}
@Test
func claudeWebFetcher_isNotSupportedOnLinux() async {
#if os(Linux)
let error = await #expect(throws: ClaudeWebAPIFetcher.FetchError.self) {
_ = try await ClaudeWebAPIFetcher.fetchUsage()
}
let isExpectedError = error.map { thrown in
if case .notSupportedOnThisPlatform = thrown { return true }
return false
} ?? false
#expect(isExpectedError)
#else
#expect(Bool(true))
#endif
}
@Test
func claudeWebFetcher_hasSessionKey_isFalseOnLinux() {
#if os(Linux)
#expect(ClaudeWebAPIFetcher.hasSessionKey(cookieHeader: nil) == false)
#else
#expect(Bool(true))
#endif
}
@Test
func claudeWebFetcher_sessionKeyInfo_throwsOnLinux() {
#if os(Linux)
let error = #expect(throws: ClaudeWebAPIFetcher.FetchError.self) {
_ = try ClaudeWebAPIFetcher.sessionKeyInfo()
}
let isExpectedError = error.map { thrown in
if case .notSupportedOnThisPlatform = thrown { return true }
return false
} ?? false
#expect(isExpectedError)
#else
#expect(Bool(true))
#endif
}
private func makeClaudeAutoContext(env: [String: String] = [:]) -> ProviderFetchContext {
self.makeClaudeContext(sourceMode: .auto, env: env)
}
private func makeClaudeContext(
sourceMode: ProviderSourceMode,
env: [String: String] = [:]) -> ProviderFetchContext
{
let browserDetection = BrowserDetection(cacheTTL: 0)
let usageDataSource: ClaudeUsageDataSource = sourceMode == .cli ? .cli : .auto
return ProviderFetchContext(
runtime: .cli,
sourceMode: sourceMode,
includeCredits: false,
webTimeout: 1,
webDebugDumpHTML: false,
verbose: false,
env: env,
settings: ProviderSettingsSnapshot.make(claude: .init(
usageDataSource: usageDataSource,
webExtrasEnabled: false,
cookieSource: .auto,
manualCookieHeader: nil)),
fetcher: UsageFetcher(environment: env),
claudeFetcher: ClaudeUsageFetcher(browserDetection: browserDetection),
browserDetection: browserDetection)
}
private static func makeClaudeCLI(loggedIn: Bool, invocationLog: URL? = nil) throws -> URL {
if let invocationLog {
try Data().write(to: invocationLog)
}
let binaryURL = FileManager.default.temporaryDirectory
.appendingPathComponent("claude-cli-runtime-\(UUID().uuidString)")
let recordInvocation = invocationLog.map { "printf '%s\\n' \"$*\" >> '\($0.path)'" } ?? ""
let loggedInJSON = loggedIn ? "true" : "false"
let script = """
#!/bin/sh
\(recordInvocation)
if [ "$1" = "auth" ] && [ "$2" = "status" ]; then
printf '%s\\n' '{"loggedIn":\(loggedInJSON)}'
fi
"""
try Data(script.utf8).write(to: binaryURL)
try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: binaryURL.path)
return binaryURL
}
private static func makeClaudeStatus() -> ClaudeStatusSnapshot {
ClaudeStatusSnapshot(
sessionPercentLeft: 80,
weeklyPercentLeft: nil,
opusPercentLeft: nil,
accountEmail: nil,
accountOrganization: nil,
loginMethod: nil,
primaryResetDescription: nil,
secondaryResetDescription: nil,
opusResetDescription: nil,
rawText: "stub")
}
private func makeResult(kind: ProviderFetchKind) -> ProviderFetchResult {
ProviderFetchResult(
usage: UsageSnapshot(
primary: nil,
secondary: nil,
updatedAt: Date(timeIntervalSince1970: 0)),
credits: nil,
dashboard: nil,
sourceLabel: "test",
strategyID: "test",
strategyKind: kind)
}
}
@@ -0,0 +1,111 @@
import Foundation
import Testing
@testable import CodexBarCore
/// Tests for the `/proc/<pid>/net/tcp` listening-port parser used on Linux as a
/// fallback for Antigravity CLI port detection when `lsof` is unavailable.
struct ProcNetTCPListeningPortParserLinuxTests {
/// Two loopback LISTEN sockets (inodes 111111, 222222) and one established
/// connection (inode 333333, st 01) that must be ignored.
private static let sample = """
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 111111 1 0000000000000000 100 0 0 10 0
1: 0100007F:C000 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 222222 1 0000000000000000 100 0 0 10 0
2: 0100007F:1F91 0100007F:E1F0 01 00000000:00000000 00:00000000 00000000 1000 0 333333 1 0000000000000000 100 0 0 10 0
"""
@Test
func `returns listening ports for owned socket inodes`() {
let ports = ProcNetTCPListeningPortParser.listeningPorts(
Self.sample, socketInodes: ["111111", "222222"])
#expect(ports == [8080, 49152])
}
@Test
func `parses tcp6 and deduplicates ports across tables`() {
let tcp6 = """
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000000000000000000000000000:C000 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 222222
"""
let tcpPorts = ProcNetTCPListeningPortParser.listeningPorts(
Self.sample, socketInodes: ["222222"])
let tcp6Ports = ProcNetTCPListeningPortParser.listeningPorts(
tcp6, socketInodes: ["222222"])
#expect(tcpPorts.union(tcp6Ports) == [49152])
}
@Test
func `ignores malformed and out of range ports`() {
let malformed = """
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:NOTHEX 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 111111
1: 0100007F:10000 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 111111
2: missing-columns
"""
#expect(ProcNetTCPListeningPortParser.listeningPorts(
malformed, socketInodes: ["111111"]).isEmpty)
#expect(ProcNetTCPListeningPortParser.listeningPorts(
"header only", socketInodes: ["111111"]).isEmpty)
}
@Test
func `accepts a headerless proc row`() {
let row = Self.sample.split(separator: "\n")[1]
#expect(ProcNetTCPListeningPortParser.listeningPorts(
String(row), socketInodes: ["111111"]) == [8080])
}
@Test
func `ignores listening sockets owned by other processes`() {
let ports = ProcNetTCPListeningPortParser.listeningPorts(
Self.sample, socketInodes: ["999999"])
#expect(ports.isEmpty)
}
@Test
func `ignores non listening sockets`() {
// inode 333333 is an established (st 01) socket, not LISTEN.
let ports = ProcNetTCPListeningPortParser.listeningPorts(
Self.sample, socketInodes: ["333333"])
#expect(ports.isEmpty)
}
@Test
func `parses socket inode from FD symlink destination`() {
#expect(ProcNetTCPListeningPortParser.socketInode(fromLink: "socket:[12345]") == "12345")
#expect(ProcNetTCPListeningPortParser.socketInode(fromLink: "/dev/pts/0") == nil)
#expect(ProcNetTCPListeningPortParser.socketInode(fromLink: "anon_inode:[eventpoll]") == nil)
#expect(ProcNetTCPListeningPortParser.socketInode(fromLink: "socket:[]") == nil)
}
@Test
func `reads process scoped TCP tables`() throws {
let fileManager = FileManager.default
let procRoot = fileManager.temporaryDirectory
.appendingPathComponent("codexbar-proc-\(UUID().uuidString)")
let processRoot = procRoot.appendingPathComponent("42")
let fdDirectory = processRoot.appendingPathComponent("fd")
let netDirectory = processRoot.appendingPathComponent("net")
let callerNetDirectory = procRoot.appendingPathComponent("net")
try fileManager.createDirectory(at: fdDirectory, withIntermediateDirectories: true)
try fileManager.createDirectory(at: netDirectory, withIntermediateDirectories: true)
try fileManager.createDirectory(at: callerNetDirectory, withIntermediateDirectories: true)
defer { try? fileManager.removeItem(at: procRoot) }
try fileManager.createSymbolicLink(
atPath: fdDirectory.appendingPathComponent("7").path,
withDestinationPath: "socket:[111111]")
try Self.sample.write(
to: netDirectory.appendingPathComponent("tcp"),
atomically: true,
encoding: .utf8)
try Self.sample.replacingOccurrences(of: ":1F90", with: ":C001").write(
to: callerNetDirectory.appendingPathComponent("tcp"),
atomically: true,
encoding: .utf8)
#expect(AntigravityStatusProbe.procListeningPorts(
pid: 42,
procRoot: procRoot.path) == [8080])
}
}
@@ -0,0 +1,137 @@
@testable import CodexBarCore
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import Testing
@Suite
struct ProviderEndpointOverrideSecurityLinuxTests {
@Test
func mimoInvalidEndpointOverrideDoesNotFallbackToLocalCache() {
#expect(MiMoWebFetchStrategy.shouldFallbackToLocal(
error: MiMoSettingsError.invalidEndpointOverride(MiMoSettingsReader.apiURLKey)) == false)
#expect(MiMoWebFetchStrategy.shouldFallbackToLocal(error: MiMoSettingsError.missingCookie()) == true)
#expect(MiMoWebFetchStrategy.shouldFallbackToLocal(error: MiMoSettingsError.invalidCookie) == true)
}
@Test
func deepgramRejectsInsecureOverrideBeforeSendingToken() async {
let transport = FailingTransport()
do {
_ = try await DeepgramUsageFetcher.fetchUsage(
apiKey: "dg-test-token",
environment: [DeepgramUsageFetcher.apiURLKey: "http://attacker.test/v1"],
transport: transport)
Issue.record("Expected DeepgramUsageError.invalidEndpointOverride")
} catch DeepgramUsageError.invalidEndpointOverride(DeepgramUsageFetcher.apiURLKey) {
// Expected.
} catch {
Issue.record("Expected DeepgramUsageError.invalidEndpointOverride, got \(error)")
}
}
@Test
func zaiRejectsInsecureQuotaOverrideBeforeSendingToken() async {
do {
_ = try await ZaiUsageFetcher.fetchUsage(
apiKey: "zai-test-token",
environment: [ZaiSettingsReader.quotaURLKey: "http://attacker.test/quota"])
Issue.record("Expected ZaiSettingsError.invalidEndpointOverride")
} catch ZaiSettingsError.invalidEndpointOverride(ZaiSettingsReader.quotaURLKey) {
// Expected.
} catch {
Issue.record("Expected ZaiSettingsError.invalidEndpointOverride, got \(error)")
}
}
@Test
func zaiRejectsInsecureAPIHostOverrideWhenQuotaURLIsAbsent() {
#expect(throws: ZaiSettingsError.invalidEndpointOverride(ZaiSettingsReader.apiHostKey)) {
try ZaiSettingsReader.validateEndpointOverrides(
environment: [ZaiSettingsReader.apiHostKey: "http://attacker.test"])
}
}
@Test
func zaiQuotaResolutionIgnoresInvalidLowerPriorityAPIHost() throws {
let environment = [
ZaiSettingsReader.quotaURLKey: "https://zai-proxy.test/quota",
ZaiSettingsReader.apiHostKey: "http://attacker.test",
]
try ZaiSettingsReader.validateQuotaEndpointOverride(environment: environment)
#expect(ZaiUsageFetcher.resolveQuotaURL(region: .global, environment: environment).absoluteString ==
"https://zai-proxy.test/quota")
}
@Test
func zaiCombinedFetchRejectsInvalidAPIHostBeforeQuotaRequest() async {
let environment = [
ZaiSettingsReader.quotaURLKey: "https://127.0.0.1:31337/quota",
ZaiSettingsReader.apiHostKey: "http://127.0.0.1:31337",
]
await #expect(throws: ZaiSettingsError.invalidEndpointOverride(ZaiSettingsReader.apiHostKey)) {
try await ZaiUsageFetcher.fetchUsageWithModelUsage(
apiKey: "ZAI_CANARY_KEY",
environment: environment)
}
}
@Test
func zaiModelUsageRejectsInsecureAPIHostOverride() async {
do {
_ = try await ZaiUsageFetcher.fetchModelUsage(
apiKey: "zai-test-token",
environment: [ZaiSettingsReader.apiHostKey: "http://attacker.test"])
Issue.record("Expected ZaiSettingsError.invalidEndpointOverride")
} catch ZaiSettingsError.invalidEndpointOverride(ZaiSettingsReader.apiHostKey) {
// Expected.
} catch {
Issue.record("Expected ZaiSettingsError.invalidEndpointOverride, got \(error)")
}
}
@Test
func mimoRejectsInsecureOverrideBeforeSendingCookie() async {
let transport = FailingTransport()
do {
_ = try await MiMoUsageFetcher.fetchUsage(
cookieHeader: "api-platform_serviceToken=session-token; userId=user-1",
environment: [MiMoSettingsReader.apiURLKey: "http://attacker.test/api/v1"],
session: transport)
Issue.record("Expected MiMoSettingsError.invalidEndpointOverride")
} catch MiMoSettingsError.invalidEndpointOverride(MiMoSettingsReader.apiURLKey) {
// Expected.
} catch {
Issue.record("Expected MiMoSettingsError.invalidEndpointOverride, got \(error)")
}
}
@Test
func affectedProviderOverridesAcceptHTTPSAndBareHosts() throws {
try DeepgramUsageFetcher.validateEndpointOverrides(environment: [
DeepgramUsageFetcher.apiURLKey: "deepgram-proxy.test/v1",
])
try ZaiSettingsReader
.validateEndpointOverrides(environment: [ZaiSettingsReader.quotaURLKey: "https://zai-proxy.test/quota"])
try ZaiSettingsReader.validateEndpointOverrides(environment: [ZaiSettingsReader.apiHostKey: "localhost:9443"])
try MiMoSettingsReader
.validateEndpointOverrides(environment: [MiMoSettingsReader.apiURLKey: "mimo-proxy.test/api/v1"])
#expect(ZaiSettingsReader.quotaURL(environment: [ZaiSettingsReader.quotaURLKey: "zai-proxy.test/quota"])?
.absoluteString == "https://zai-proxy.test/quota")
#expect(MiMoSettingsReader.apiURL(environment: [MiMoSettingsReader.apiURLKey: "mimo-proxy.test/api/v1"])
.absoluteString == "https://mimo-proxy.test/api/v1")
}
}
private struct FailingTransport: ProviderHTTPTransport {
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
Issue
.record(
"Endpoint override validation should fail before any request is sent to \(request.url?.absoluteString ?? "<nil>")")
throw URLError(.badURL)
}
}
@@ -0,0 +1,75 @@
import CodexBarCore
import Foundation
import Testing
/// Regression tests for a copy-pasted quote-unwrap helper that traps on length-1 input.
///
/// 32 provider settings readers (plus `CodexBarConfig` and `CLIConfigCommand`) share a
/// `cleaned(_:)` helper of the form:
///
/// if (value.hasPrefix("\"") && value.hasSuffix("\"")) ||
/// (value.hasPrefix("'") && value.hasSuffix("'"))
/// {
/// value.removeFirst()
/// value.removeLast()
/// }
///
/// For a value of length 1 (the single character `"` or `'`), both `hasPrefix` and
/// `hasSuffix` return true, `removeFirst()` empties the string, and `removeLast()` then
/// traps with "Can't remove last element from empty collection." This is reachable from
/// a misconfigured env var (e.g. `ALIBABA_TOKEN_PLAN_COOKIE='"'`) and from quoted JSON
/// values in `~/.codexbar/config.json`, both of which are user-controllable.
///
/// These tests exercise two representative public readers Alibaba Token Plan (the
/// newest addition in #1098) and the Ollama API key reader (added in #1087) by
/// passing the trap-inducing single-quote inputs and asserting the readers return nil
/// instead of crashing. The patch swaps `removeFirst()/removeLast()` for
/// `String(value.dropFirst().dropLast())`, which is empty-safe.
@Suite
struct SettingsReaderQuoteUnwrapTrapTests {
@Test
func alibabaTokenPlanCookieHeader_returnsNilForLoneDoubleQuoteValue() {
let env = [AlibabaTokenPlanSettingsReader.cookieHeaderKey: "\""]
#expect(AlibabaTokenPlanSettingsReader.cookieHeader(environment: env) == nil)
}
@Test
func alibabaTokenPlanCookieHeader_returnsNilForLoneApostropheValue() {
let env = [AlibabaTokenPlanSettingsReader.cookieHeaderKey: "'"]
#expect(AlibabaTokenPlanSettingsReader.cookieHeader(environment: env) == nil)
}
@Test
func alibabaTokenPlanCookieHeader_unwrapsProperlyDoubleQuotedValue() {
let env = [AlibabaTokenPlanSettingsReader.cookieHeaderKey: "\"abc=def\""]
#expect(AlibabaTokenPlanSettingsReader.cookieHeader(environment: env) == "abc=def")
}
@Test
func alibabaTokenPlanCookieHeader_unwrapsProperlySingleQuotedValue() {
let env = [AlibabaTokenPlanSettingsReader.cookieHeaderKey: "'abc=def'"]
#expect(AlibabaTokenPlanSettingsReader.cookieHeader(environment: env) == "abc=def")
}
@Test
func ollamaAPIKey_returnsNilForLoneDoubleQuoteValue() {
for key in OllamaAPISettingsReader.apiKeyEnvironmentKeys {
let env = [key: "\""]
#expect(OllamaAPISettingsReader.apiKey(environment: env) == nil)
}
}
@Test
func ollamaAPIKey_returnsNilForLoneApostropheValue() {
for key in OllamaAPISettingsReader.apiKeyEnvironmentKeys {
let env = [key: "'"]
#expect(OllamaAPISettingsReader.apiKey(environment: env) == nil)
}
}
@Test
func ollamaAPIKey_unwrapsProperlyQuotedValue() {
let env = [OllamaAPISettingsReader.apiKeyEnvironmentKeys[0]: "\"sk-token\""]
#expect(OllamaAPISettingsReader.apiKey(environment: env) == "sk-token")
}
}
@@ -0,0 +1,22 @@
import Foundation
import Testing
@testable import CodexBarCore
#if os(Linux)
@Suite(.serialized)
struct ShellCommandSessionLinuxTests {
@Test
func `shell probe launches as a detached session leader`() throws {
let output = ShellCommandLocator.test_runShellCommand(
shell: "/bin/sh",
arguments: ["-c", "printf '%s ' \"$$\"; ps -o sid= -p \"$$\""],
timeout: 5)
let text = try #require(output.flatMap { String(data: $0, encoding: .utf8) })
let identifiers = text.split(whereSeparator: \.isWhitespace).compactMap { Int32($0) }
#expect(identifiers.count == 2)
guard identifiers.count == 2 else { return }
#expect(identifiers[0] == identifiers[1])
}
}
#endif
+15
View File
@@ -0,0 +1,15 @@
import CodexBarCore
import Testing
@Suite(.serialized)
struct UsageFormatterLinuxTests {
@Test
func `rate-window formatting uses the standalone English fallback`() {
UsageFormatter.clearLocalizationProvider()
UsageFormatter.clearLocaleProvider()
#expect(UsageFormatter.usageLine(remaining: 25, used: 75, showUsed: false) == "25% left")
#expect(UsageFormatter.usageLine(remaining: 25, used: 75, showUsed: true) == "75% used")
#expect(UsageFormatter.usageLine(remaining: 0.75, used: 99.25, showUsed: false) == "<1% left")
}
}
@@ -0,0 +1,447 @@
import CodexBarCore
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import Testing
@testable import CodexBarCLI
/// Fixtures below were captured verbatim from a locally running Wayfinder gateway
/// (`wayfinder-router serve`, two-tier priced config) after routing real traffic.
struct WayfinderProviderLinuxTests {
@Test
func `assembles a snapshot from live gateway payloads`() throws {
let snapshot = try Self.makeSnapshot()
#expect(snapshot.gatewayStatus == "ok")
#expect(!snapshot.offline)
#expect(!snapshot.dryRun)
#expect(snapshot.missingKeys.isEmpty)
#expect(snapshot.modelCount == 2)
#expect(snapshot.requests == 14)
#expect(snapshot.tokens == 1028)
#expect(snapshot.priced)
#expect(snapshot.saved == 0.005694)
#expect(snapshot.savedPct == 61.5)
#expect(snapshot.routes.map(\.name) == ["local", "cloud"])
#expect(snapshot.routes.first { $0.name == "local" }?.requests == 10)
#expect(snapshot.routes.first { $0.name == "cloud" }?.requests == 4)
#expect(snapshot.statusLabel == "Local gateway")
#expect(snapshot.gatewaySummary == "ok · 2 models")
#expect(snapshot.displayLines == [
"Gateway: ok · 2 models",
"Routed: local: 10 · cloud: 4",
"Saved: <$0.01 · 61.5% vs highest-cost route",
"Avg decision: 0.1 ms",
])
let avgMs = try #require(snapshot.avgDecisionMs)
#expect(abs(avgMs - 0.0804) < 0.001)
}
@Test
func `maps the snapshot onto the shared usage snapshot`() throws {
let usage = try Self.makeSnapshot().toUsageSnapshot()
#expect(usage.primary == nil)
#expect(usage.secondary == nil)
#expect(usage.providerCost == nil)
#expect(usage.identity?.providerID == .wayfinder)
#expect(usage.identity?.accountEmail == nil)
#expect(usage.identity?.accountOrganization == "2 models · local gateway")
#expect(usage.identity?.loginMethod == "Local gateway")
#expect(usage.dataConfidence == .exact)
}
@Test
func `degraded health reports the missing key count`() throws {
let snapshot = try Self.makeSnapshot(healthData: Self.healthDegraded)
#expect(snapshot.gatewayStatus == "degraded")
#expect(snapshot.missingKeys == ["cloud"])
#expect(snapshot.statusLabel == "Degraded — 1 key missing")
}
@Test
func `empty savings suppress the routed and saved summaries`() throws {
let snapshot = try Self.makeSnapshot(savingsData: Self.savingsZeros)
#expect(snapshot.requests == 0)
#expect(snapshot.routedSummary == nil)
#expect(snapshot.savedSummary == nil)
#expect(snapshot.toUsageSnapshot().providerCost == nil)
}
@Test
func `unpriced savings never render dollars`() throws {
let snapshot = try Self.makeSnapshot(savingsData: Self.savingsUnpriced)
#expect(!snapshot.priced)
#expect(snapshot.savedSummary == "40% vs highest-cost route")
#expect(snapshot.toUsageSnapshot().providerCost == nil)
}
@Test
func `sub-cent priced savings render below one cent`() throws {
let snapshot = try Self.makeSnapshot()
#expect(snapshot.routedSummary == "local: 10 · cloud: 4")
#expect(snapshot.savedSummary == "<$0.01 · 61.5% vs highest-cost route")
#expect(snapshot.avgDecisionSummary == "0.1 ms")
}
@Test
func `metrics parsing is best effort`() throws {
#expect(WayfinderUsageFetcher._averageDecisionMillisecondsForTesting("") == nil)
#expect(WayfinderUsageFetcher._averageDecisionMillisecondsForTesting("garbage\nlines\n") == nil)
#expect(WayfinderUsageFetcher._averageDecisionMillisecondsForTesting(
"wayfinder_router_decision_latency_seconds_sum 1.5\n") == nil)
#expect(WayfinderUsageFetcher._averageDecisionMillisecondsForTesting(
"wayfinder_router_decision_latency_seconds_sum 1.5\n" +
"wayfinder_router_decision_latency_seconds_count 0\n") == nil)
let labeled = WayfinderUsageFetcher._averageDecisionMillisecondsForTesting(
"wayfinder_router_decision_latency_seconds_sum{route=\"all\"} 2.0\n" +
"wayfinder_router_decision_latency_seconds_count{route=\"all\"} 4\n")
#expect(labeled == 500)
let snapshot = try Self.makeSnapshot(metricsText: nil)
#expect(snapshot.avgDecisionMs == nil)
#expect(snapshot.avgDecisionSummary == nil)
}
@Test
func `endpoint URLs preserve prefixes and trailing slashes`() throws {
func endpoint(_ base: String, _ path: String) throws -> String {
try WayfinderUsageFetcher._endpointURLForTesting(
baseURL: #require(URL(string: base)),
path: path).absoluteString
}
#expect(try endpoint("http://127.0.0.1:8088", "healthz") == "http://127.0.0.1:8088/healthz")
#expect(try endpoint("http://127.0.0.1:8088/", "healthz") == "http://127.0.0.1:8088/healthz")
#expect(try endpoint("https://wayfinder.example.com/wf", "v1/savings") ==
"https://wayfinder.example.com/wf/v1/savings")
}
@Test
func `gateway URL override allows loopback HTTP and rejects remote HTTP`() throws {
let key = WayfinderSettingsReader.baseURLEnvironmentKey
try WayfinderSettingsReader.validateEndpointOverride(environment: [key: "http://127.0.0.1:9090"])
try WayfinderSettingsReader.validateEndpointOverride(environment: [key: "http://localhost:8088"])
try WayfinderSettingsReader.validateEndpointOverride(environment: [key: "https://wayfinder.example.com"])
#expect(WayfinderSettingsReader.baseURL(environment: [key: "http://127.0.0.1:9090"]).absoluteString ==
"http://127.0.0.1:9090")
#expect(throws: WayfinderSettingsError.invalidEndpointOverride(key)) {
try WayfinderSettingsReader.validateEndpointOverride(environment: [key: "http://192.168.1.5:8088"])
}
#expect(throws: WayfinderSettingsError.invalidEndpointOverride(key)) {
try WayfinderSettingsReader.validateEndpointOverride(environment: [key: "http://user@127.0.0.1:8088"])
}
#expect(WayfinderSettingsReader.baseURL(environment: [key: "http://attacker.test"]) ==
WayfinderSettingsReader.defaultBaseURL)
#expect(WayfinderSettingsReader.baseURL(environment: [:]) == WayfinderSettingsReader.defaultBaseURL)
}
@Test
func `dashboard URL follows the configured gateway and preserves its prefix`() {
let key = WayfinderSettingsReader.baseURLEnvironmentKey
#expect(WayfinderSettingsReader.dashboardURL(environment: [:]).absoluteString ==
"http://127.0.0.1:8088/router")
#expect(WayfinderSettingsReader.dashboardURL(
environment: [key: "http://localhost:9191/wayfinder/"]).absoluteString ==
"http://localhost:9191/wayfinder/router")
}
@Test
func `config projects the gateway URL into the fetch environment`() {
let config = ProviderConfig(id: .wayfinder, enterpriseHost: "http://localhost:9099")
let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(
base: [:],
provider: .wayfinder,
config: config)
#expect(environment[WayfinderSettingsReader.baseURLEnvironmentKey] == "http://localhost:9099")
#expect(WayfinderSettingsReader.baseURL(environment: environment).absoluteString == "http://localhost:9099")
}
@Test
func `descriptor is registered`() {
let descriptor = ProviderDescriptorRegistry.descriptor(for: .wayfinder)
#expect(descriptor.metadata.displayName == "Wayfinder")
#expect(descriptor.metadata.cliName == "wayfinder")
#expect(descriptor.cli.aliases.contains("wayfinder-router"))
#expect(!descriptor.metadata.defaultEnabled)
}
@Test
func `usage snapshot preserves Wayfinder detail when cached`() throws {
let snapshot = try Self.makeSnapshot()
let encoded = try JSONEncoder().encode(snapshot.toUsageSnapshot())
let decoded = try JSONDecoder().decode(UsageSnapshot.self, from: encoded)
#expect(decoded.wayfinderUsage == snapshot)
#expect(decoded.identity?.providerID == .wayfinder)
}
@Test
func `fetch polls only the documented read-only endpoints`() async throws {
let log = RequestLog()
let transport = ProviderHTTPTransportHandler { request in
let url = try #require(request.url)
log.append(url)
#expect(request.httpMethod == "GET")
let body: Data = switch url.path {
case "/healthz": Self.healthOK
case "/router/models": Self.models
case "/v1/savings": Self.savings30d
case "/metrics": Data(Self.metricsText.utf8)
default: Data()
}
let response = try #require(HTTPURLResponse(
url: url,
statusCode: 200,
httpVersion: nil,
headerFields: nil))
return (body, response)
}
let snapshot = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: transport)
#expect(snapshot.requests == 14)
#expect(log.paths() == ["/healthz", "/router/models", "/v1/savings", "/metrics"])
#expect(log.queries().contains("period=30d"))
}
@Test
func `fetch maps HTTP failures to actionable errors`() async throws {
let failing = ProviderHTTPTransportHandler { _ in
throw URLError(.cannotConnectToHost)
}
await #expect(throws: WayfinderUsageError.gatewayUnreachable) {
_ = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: failing)
}
let serverError = ProviderHTTPTransportHandler { request in
let url = try #require(request.url)
let response = try #require(HTTPURLResponse(
url: url,
statusCode: 500,
httpVersion: nil,
headerFields: nil))
return (Data(), response)
}
await #expect(throws: WayfinderUsageError.apiError(500)) {
_ = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: serverError)
}
}
@Test
func `required request cancellation remains cancellation`() async throws {
for error in [CancellationError() as any Error, URLError(.cancelled) as any Error] {
let cancelling = ProviderHTTPTransportHandler { _ in throw error }
await #expect(throws: CancellationError.self) {
_ = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: cancelling)
}
}
}
@Test
func `optional metrics cancellation remains cancellation`() async throws {
let cancelling = ProviderHTTPTransportHandler { request in
let url = try #require(request.url)
if url.path == "/metrics" {
throw CancellationError()
}
let body: Data = switch url.path {
case "/healthz": Self.healthOK
case "/router/models": Self.models
case "/v1/savings": Self.savings30d
default: Data()
}
let response = try #require(HTTPURLResponse(
url: url,
statusCode: 200,
httpVersion: nil,
headerFields: nil))
return (body, response)
}
await #expect(throws: CancellationError.self) {
_ = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: cancelling)
}
}
@Test
func `fetch rejects responses from a different origin`() async throws {
let redirecting = ProviderHTTPTransportHandler { _ in
let elsewhere = try #require(URL(string: "http://attacker.test/healthz"))
let response = try #require(HTTPURLResponse(
url: elsewhere,
statusCode: 200,
httpVersion: nil,
headerFields: nil))
return (Self.healthOK, response)
}
await #expect(throws: WayfinderUsageError.unexpectedRedirect) {
_ = try await WayfinderUsageFetcher.fetchUsage(
baseURL: #require(URL(string: "http://127.0.0.1:8088")),
transport: redirecting)
}
}
@Test
func `text CLI renders gateway health routed split savings and latency`() throws {
let output = try CLIRenderer.renderText(
provider: .wayfinder,
snapshot: Self.makeSnapshot().toUsageSnapshot(),
credits: nil,
context: RenderContext(
header: "Wayfinder (api)",
status: nil,
useColor: false,
resetStyle: .countdown))
#expect(output.contains("Gateway: ok · 2 models"))
#expect(output.contains("Routed: local: 10 · cloud: 4"))
#expect(output.contains("Saved: <$0.01 · 61.5% vs highest-cost route"))
#expect(output.contains("Avg decision: 0.1 ms"))
#expect(!output.contains("Cost:"))
}
@Test
func `routed summary reflects request counts regardless of configured model order`() throws {
// The heavier-traffic route ("primary-tier") is configured SECOND in /router/models,
// and the lighter one ("secondary-tier") FIRST proving nothing in the summary is
// derived from array position (the gateway's config order is not a semantic signal).
let reorderedModels = Data("""
{"models":[{"name":"secondary-tier","endpoint":"http://127.0.0.1:9102/v1",\
"model":"stand-in-large","api_key_env":"RIG_CLOUD_KEY","key_ok":true},\
{"name":"primary-tier","endpoint":"http://127.0.0.1:9101/v1","model":"stand-in-small",\
"api_key_env":null,"key_ok":true}],"dry_run":false}
""".utf8)
let snapshot = try Self.makeSnapshot(modelsData: reorderedModels)
#expect(snapshot.routedSummary == "local: 10 · cloud: 4")
#expect(snapshot.routes.first?.name == "local")
}
@Test
func `routed summary uses the gateway's own route names, not a hardcoded local or cloud label`() throws {
// Route names are whatever the user named their endpoints in the Wayfinder config —
// there is no "local"/"cloud" semantic anywhere in the gateway's JSON.
let customNamedSavings = Data("""
{"period_days":30,"unit":"usd","priced":true,"requests":14,"estimated_requests":0,\
"tokens":1028,"realized":0.003558,"baseline":0.009252,"saved":0.005694,"saved_pct":61.5,\
"by_route":{"groq-8b":{"requests":10,"realized":0.000264,"baseline":0.005958,\
"saved":0.005694,"tokens":662},"openai-o1":{"requests":4,"realized":0.003294,\
"baseline":0.003294,"saved":0.0,"tokens":366}},"by_key":{},\
"price_table_version":"a3db80fd9a78"}
""".utf8)
let snapshot = try Self.makeSnapshot(savingsData: customNamedSavings)
let summary = try #require(snapshot.routedSummary)
#expect(summary == "groq-8b: 10 · openai-o1: 4")
#expect(!summary.contains("local"))
#expect(!summary.contains("cloud"))
}
// MARK: - Helpers
private static func makeSnapshot(
healthData: Data = Self.healthOK,
modelsData: Data = Self.models,
savingsData: Data = Self.savings30d,
metricsText: String? = Self.metricsText) throws -> WayfinderUsageSnapshot
{
try WayfinderUsageFetcher._makeSnapshotForTesting(
healthData: healthData,
modelsData: modelsData,
savingsData: savingsData,
metricsText: metricsText,
updatedAt: Date(timeIntervalSince1970: 1))
}
private final class RequestLog: @unchecked Sendable {
private let lock = NSLock()
private var urls: [URL] = []
func append(_ url: URL) {
self.lock.lock()
defer { self.lock.unlock() }
self.urls.append(url)
}
func paths() -> [String] {
self.lock.lock()
defer { self.lock.unlock() }
return self.urls.map(\.path)
}
func queries() -> [String] {
self.lock.lock()
defer { self.lock.unlock() }
return self.urls.compactMap(\.query)
}
}
// MARK: - Fixtures (captured from a live gateway)
private static let healthOK = Data("""
{"status":"ok","models":["cloud","local"],"offline":false}
""".utf8)
private static let healthDegraded = Data("""
{"status":"degraded","models":["cloud","local"],"offline":false,"missing_keys":["cloud"]}
""".utf8)
private static let models = Data("""
{"models":[{"name":"local","endpoint":"http://127.0.0.1:9101/v1","model":"stand-in-small",\
"api_key_env":null,"key_ok":true},{"name":"cloud","endpoint":"http://127.0.0.1:9102/v1",\
"model":"stand-in-large","api_key_env":"RIG_CLOUD_KEY","key_ok":true}],"dry_run":false}
""".utf8)
private static let savings30d = Data("""
{"period_days":30,"unit":"usd","priced":true,"requests":14,"estimated_requests":0,\
"tokens":1028,"realized":0.003558,"baseline":0.009252,"saved":0.005694,"saved_pct":61.5,\
"by_route":{"cloud":{"requests":4,"realized":0.003294,"baseline":0.003294,"saved":0.0,\
"tokens":366},"local":{"requests":10,"realized":0.000264,"baseline":0.005958,\
"saved":0.005694,"tokens":662}},"by_key":{},"price_table_version":"a3db80fd9a78"}
""".utf8)
private static let savingsZeros = Data("""
{"period_days":30,"unit":"usd","priced":true,"requests":0,"estimated_requests":0,\
"tokens":0,"realized":0.0,"baseline":0.0,"saved":0.0,"saved_pct":0.0,"by_route":{},\
"by_key":{},"price_table_version":"a3db80fd9a78"}
""".utf8)
private static let savingsUnpriced = Data("""
{"period_days":30,"unit":"relative","priced":false,"requests":5,"estimated_requests":0,\
"tokens":420,"realized":1.8,"baseline":3.0,"saved":1.2,"saved_pct":40.0,\
"by_route":{"local":{"requests":4,"realized":0.8,"baseline":2.0,"saved":1.2,"tokens":320},\
"cloud":{"requests":1,"realized":1.0,"baseline":1.0,"saved":0.0,"tokens":100}},\
"by_key":{},"price_table_version":"a3db80fd9a78"}
""".utf8)
private static let metricsText = """
# HELP wayfinder_router_requests_total Routed requests by model and mode.
# TYPE wayfinder_router_requests_total counter
wayfinder_router_requests_total{model="local",mode="scored"} 10
wayfinder_router_requests_total{model="cloud",mode="scored"} 4
# HELP wayfinder_router_decision_latency_seconds Time to score a prompt and pick a model (no model call).
# TYPE wayfinder_router_decision_latency_seconds histogram
wayfinder_router_decision_latency_seconds_bucket{le="0.0001"} 13
wayfinder_router_decision_latency_seconds_bucket{le="0.00025"} 14
wayfinder_router_decision_latency_seconds_bucket{le="+Inf"} 14
wayfinder_router_decision_latency_seconds_sum 0.00112602
wayfinder_router_decision_latency_seconds_count 14
"""
}