import CodexBarCoreimport Foundationimport SwiftUIimport Testing@testable import CodexBar @MainActorstruct CodexLocalSessionCostSettingsTests { @Test func `codex exposes usage and cookie pickers`() throws { let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-codex") let context = fixture.settingsContext(provider: .codex) let pickers = CodexProviderImplementation().settingsPickers(context: context) let toggles = CodexProviderImplementation().settingsToggles(context: context) #expect(pickers.contains(where: { $0.id == "codex-usage-source" })) let usagePicker = try #require(pickers.first(where: { $0.id == "codex-usage-source" })) #expect(usagePicker.title == "Quota usage source") #expect(usagePicker.subtitle.contains("Local session cost estimates work independently")) let cookiePicker = try #require(pickers.first(where: { $0.id == "codex-cookie-source" })) #expect(cookiePicker.placement == .connection) let localLedgerToggle = try #require(toggles.first(where: { $0.id == "codex-local-session-cost-ledger" })) #expect(localLedgerToggle.title == "Local session cost estimates") #expect(localLedgerToggle.subtitle.contains("organization API keys")) #expect(!localLedgerToggle.binding.wrappedValue) localLedgerToggle.binding.wrappedValue = true #expect(fixture.settings.codexLocalSessionCostLedgerEnabled) #expect(!fixture.settings.costUsageEnabled) #expect(fixture.settings.isCostUsageEffectivelyEnabled(for: .codex)) #expect(!fixture.settings.isCostUsageEffectivelyEnabled(for: .claude)) #expect(toggles.contains(where: { $0.id == "codex-historical-tracking" })) let sparkToggle = try #require(toggles.first(where: { $0.id == "codex-spark-usage-visible" })) #expect(sparkToggle.title == "Show Codex Spark usage") #expect(sparkToggle.subtitle.contains("menu and provider preview")) #expect(sparkToggle.binding.wrappedValue) #expect(sparkToggle.isEnabled?() == true) sparkToggle.binding.wrappedValue = false #expect(fixture.settings.codexSparkUsageVisible == false) fixture.settings.showOptionalCreditsAndExtraUsage = false #expect(sparkToggle.isEnabled?() == false) } @Test func `codex local ledger ignores the managed account home`() throws { let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-local-ledger") fixture.settings._test_activeManagedCodexRemoteHomePath = "/tmp/managed-codex-home" fixture.settings.codexActiveSource = .managedAccount(id: UUID()) defer { fixture.settings._test_activeManagedCodexRemoteHomePath = nil } let managedScope = fixture.store.tokenCostScope(for: .codex) fixture.settings.codexLocalSessionCostLedgerEnabled = true let localScope = fixture.store.tokenCostScope(for: .codex) #expect(managedScope.codexHomePath == "/tmp/managed-codex-home") #expect(managedScope.signature == "codex:managed:/tmp/managed-codex-home") #expect(localScope.codexHomePath == nil) #expect(localScope.signature == "codex:ambient") } @Test func `unresolved managed cost scope never falls back to ambient sessions`() throws { let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-managed-unresolved") let accountID = UUID() fixture.settings.codexActiveSource = .managedAccount(id: accountID) let scope = fixture.store.tokenCostScope(for: .codex) #expect(scope.codexHomePath != nil) #expect(scope.signature != "codex:ambient") #expect(scope.signature.hasPrefix("codex:managed:")) } private func makeSettingsFixture(suite: String) throws -> Fixture { let defaults = try #require(UserDefaults(suiteName: suite)) defaults.removePersistentDomain(forName: suite) let settings = SettingsStore( userDefaults: defaults, configStore: testConfigStore(suiteName: suite), zaiTokenStore: NoopZaiTokenStore(), syntheticTokenStore: NoopSyntheticTokenStore()) let store = UsageStore( fetcher: UsageFetcher(environment: [:]), browserDetection: BrowserDetection(cacheTTL: 0), settings: settings) return Fixture(settings: settings, store: store) } private struct Fixture { let settings: SettingsStore let store: UsageStore private let state = ProviderSettingsContextState() @MainActor func settingsContext(provider: UsageProvider) -> ProviderSettingsContext { let settings = self.settings let store = self.store let state = self.state return ProviderSettingsContext( provider: provider, settings: settings, store: store, boolBinding: { keyPath in Binding( get: { settings[keyPath: keyPath] }, set: { settings[keyPath: keyPath] = $0 }) }, stringBinding: { keyPath in Binding( get: { settings[keyPath: keyPath] }, set: { settings[keyPath: keyPath] = $0 }) }, statusText: { id in state.statusByID[id] }, setStatusText: { id, text in if let text { state.statusByID[id] = text } else { state.statusByID.removeValue(forKey: id) } }, lastAppActiveRunAt: { id in state.lastRunAtByID[id] }, setLastAppActiveRunAt: { id, date in if let date { state.lastRunAtByID[id] = date } else { state.lastRunAtByID.removeValue(forKey: id) } }, requestConfirmation: { _ in }, runLoginFlow: {}) } } private final class ProviderSettingsContextState { var statusByID: [String: String] = [:] var lastRunAtByID: [String: Date] = [:] }}
import CodexBarCore
import Foundation
import SwiftUI
import Testing
@testable import CodexBar
@MainActor
struct CodexLocalSessionCostSettingsTests {
@Test
func `codex exposes usage and cookie pickers`() throws {
let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-codex")
let context = fixture.settingsContext(provider: .codex)
let pickers = CodexProviderImplementation().settingsPickers(context: context)
let toggles = CodexProviderImplementation().settingsToggles(context: context)
#expect(pickers.contains(where: { $0.id == "codex-usage-source" }))
let usagePicker = try #require(pickers.first(where: { $0.id == "codex-usage-source" }))
#expect(usagePicker.title == "Quota usage source")
#expect(usagePicker.subtitle.contains("Local session cost estimates work independently"))
let cookiePicker = try #require(pickers.first(where: { $0.id == "codex-cookie-source" }))
#expect(cookiePicker.placement == .connection)
let localLedgerToggle = try #require(toggles.first(where: { $0.id == "codex-local-session-cost-ledger" }))
#expect(localLedgerToggle.title == "Local session cost estimates")
#expect(localLedgerToggle.subtitle.contains("organization API keys"))
#expect(!localLedgerToggle.binding.wrappedValue)
localLedgerToggle.binding.wrappedValue = true
#expect(fixture.settings.codexLocalSessionCostLedgerEnabled)
#expect(!fixture.settings.costUsageEnabled)
#expect(fixture.settings.isCostUsageEffectivelyEnabled(for: .codex))
#expect(!fixture.settings.isCostUsageEffectivelyEnabled(for: .claude))
#expect(toggles.contains(where: { $0.id == "codex-historical-tracking" }))
let sparkToggle = try #require(toggles.first(where: { $0.id == "codex-spark-usage-visible" }))
#expect(sparkToggle.title == "Show Codex Spark usage")
#expect(sparkToggle.subtitle.contains("menu and provider preview"))
#expect(sparkToggle.binding.wrappedValue)
#expect(sparkToggle.isEnabled?() == true)
sparkToggle.binding.wrappedValue = false
#expect(fixture.settings.codexSparkUsageVisible == false)
fixture.settings.showOptionalCreditsAndExtraUsage = false
#expect(sparkToggle.isEnabled?() == false)
}
@Test
func `codex local ledger ignores the managed account home`() throws {
let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-local-ledger")
fixture.settings._test_activeManagedCodexRemoteHomePath = "/tmp/managed-codex-home"
fixture.settings.codexActiveSource = .managedAccount(id: UUID())
defer { fixture.settings._test_activeManagedCodexRemoteHomePath = nil }
let managedScope = fixture.store.tokenCostScope(for: .codex)
fixture.settings.codexLocalSessionCostLedgerEnabled = true
let localScope = fixture.store.tokenCostScope(for: .codex)
#expect(managedScope.codexHomePath == "/tmp/managed-codex-home")
#expect(managedScope.signature == "codex:managed:/tmp/managed-codex-home")
#expect(localScope.codexHomePath == nil)
#expect(localScope.signature == "codex:ambient")
}
@Test
func `unresolved managed cost scope never falls back to ambient sessions`() throws {
let fixture = try self.makeSettingsFixture(suite: "CodexLocalSessionCostSettingsTests-managed-unresolved")
let accountID = UUID()
fixture.settings.codexActiveSource = .managedAccount(id: accountID)
let scope = fixture.store.tokenCostScope(for: .codex)
#expect(scope.codexHomePath != nil)
#expect(scope.signature != "codex:ambient")
#expect(scope.signature.hasPrefix("codex:managed:"))
}
private func makeSettingsFixture(suite: String) throws -> Fixture {
let defaults = try #require(UserDefaults(suiteName: suite))
defaults.removePersistentDomain(forName: suite)
let settings = SettingsStore(
userDefaults: defaults,
configStore: testConfigStore(suiteName: suite),
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore())
let store = UsageStore(
fetcher: UsageFetcher(environment: [:]),
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings)
return Fixture(settings: settings, store: store)
}
private struct Fixture {
let settings: SettingsStore
let store: UsageStore
private let state = ProviderSettingsContextState()
@MainActor
func settingsContext(provider: UsageProvider) -> ProviderSettingsContext {
let settings = self.settings
let store = self.store
let state = self.state
return ProviderSettingsContext(
provider: provider,
settings: settings,
store: store,
boolBinding: { keyPath in
Binding(
get: { settings[keyPath: keyPath] },
set: { settings[keyPath: keyPath] = $0 })
},
stringBinding: { keyPath in
Binding(
get: { settings[keyPath: keyPath] },
set: { settings[keyPath: keyPath] = $0 })
},
statusText: { id in state.statusByID[id] },
setStatusText: { id, text in
if let text {
state.statusByID[id] = text
} else {
state.statusByID.removeValue(forKey: id)
}
},
lastAppActiveRunAt: { id in state.lastRunAtByID[id] },
setLastAppActiveRunAt: { id, date in
if let date {
state.lastRunAtByID[id] = date
} else {
state.lastRunAtByID.removeValue(forKey: id)
}
},
requestConfirmation: { _ in },
runLoginFlow: {})
}
}
private final class ProviderSettingsContextState {
var statusByID: [String: String] = [:]
var lastRunAtByID: [String: Date] = [:]
}
}