import CodexBarCoreimport Foundationimport Testing@testable import CodexBar @MainActor@Suitestruct SettingsStoreCoverageTests { @Test func providerOrderingAndCaching() throws { let suite = "SettingsStoreCoverageTests-ordering" let defaults = UserDefaults(suiteName: suite)! defaults.removePersistentDomain(forName: suite) let configStore = testConfigStore(suiteName: suite) let config = CodexBarConfig(providers: [ ProviderConfig(id: .zai), ProviderConfig(id: .codex), ProviderConfig(id: .claude), ]) try configStore.save(config) let settings = Self.makeSettingsStore(userDefaults: defaults, configStore: configStore) let ordered = settings.orderedProviders() let cached = settings.orderedProviders() #expect(ordered == cached) #expect(ordered.first == .zai) #expect(ordered.contains(.minimax)) settings.moveProvider(fromOffsets: IndexSet(integer: 0), toOffset: 2) #expect(settings.orderedProviders() != ordered) let metadata = ProviderRegistry.shared.metadata settings.setProviderEnabled(provider: .codex, metadata: metadata[.codex]!, enabled: true) settings.setProviderEnabled(provider: .claude, metadata: metadata[.claude]!, enabled: false) let enabled = settings.enabledProvidersOrdered(metadataByProvider: metadata) #expect(enabled.contains(.codex)) } @Test func menuBarMetricPreferencesAndDisplayModes() { let settings = Self.makeSettingsStore() settings.setMenuBarMetricPreference(.average, for: .codex) #expect(settings.menuBarMetricPreference(for: .codex) == .automatic) settings.setMenuBarMetricPreference(.average, for: .gemini) #expect(settings.menuBarMetricPreference(for: .gemini) == .average) #expect(settings.menuBarMetricSupportsAverage(for: .gemini)) settings.setMenuBarMetricPreference(.secondary, for: .zai) #expect(settings.menuBarMetricPreference(for: .zai) == .primary) settings.menuBarDisplayMode = .pace #expect(settings.menuBarDisplayMode == .pace) settings.resetTimesShowAbsolute = true #expect(settings.resetTimeDisplayStyle == .absolute) } @Test func tokenAccountMutationsApplySideEffects() { let settings = Self.makeSettingsStore() settings.addTokenAccount(provider: .claude, label: "Primary", token: "token") #expect(settings.tokenAccounts(for: .claude).count == 1) #expect(settings.claudeCookieSource == .manual) let account = settings.selectedTokenAccount(for: .claude) #expect(account != nil) settings.setActiveTokenAccountIndex(10, for: .claude) #expect(settings.selectedTokenAccount(for: .claude)?.id == account?.id) if let id = account?.id { settings.removeTokenAccount(provider: .claude, accountID: id) } #expect(settings.tokenAccounts(for: .claude).isEmpty) settings.reloadTokenAccounts() } @Test func tokenCostUsageSourceDetection() throws { let fileManager = FileManager.default let root = fileManager.temporaryDirectory.appendingPathComponent( "token-cost-\(UUID().uuidString)", isDirectory: true) let codexRoot = root.appendingPathComponent("sessions", isDirectory: true) try fileManager.createDirectory(at: codexRoot, withIntermediateDirectories: true) let codexFile = codexRoot.appendingPathComponent("usage.jsonl") fileManager.createFile(atPath: codexFile.path, contents: Data("{}".utf8)) #expect(SettingsStore.hasAnyTokenCostUsageSources( env: ["CODEX_HOME": root.path], fileManager: fileManager)) let claudeRoot = fileManager.temporaryDirectory.appendingPathComponent( "claude-\(UUID().uuidString)", isDirectory: true) let claudeProjects = claudeRoot.appendingPathComponent("projects", isDirectory: true) try fileManager.createDirectory(at: claudeProjects, withIntermediateDirectories: true) let claudeFile = claudeProjects.appendingPathComponent("usage.jsonl") fileManager.createFile(atPath: claudeFile.path, contents: Data("{}".utf8)) #expect(SettingsStore.hasAnyTokenCostUsageSources( env: ["CLAUDE_CONFIG_DIR": claudeRoot.path], fileManager: fileManager)) } @Test func ensureTokenLoadersExecute() { let settings = Self.makeSettingsStore() settings.ensureZaiAPITokenLoaded() settings.ensureSyntheticAPITokenLoaded() settings.ensureCodexCookieLoaded() settings.ensureClaudeCookieLoaded() settings.ensureCursorCookieLoaded() settings.ensureOpenCodeCookieLoaded() settings.ensureFactoryCookieLoaded() settings.ensureMiniMaxCookieLoaded() settings.ensureMiniMaxAPITokenLoaded() settings.ensureKimiAuthTokenLoaded() settings.ensureKimiK2APITokenLoaded() settings.ensureAugmentCookieLoaded() settings.ensureAmpCookieLoaded() settings.ensureCopilotAPITokenLoaded() settings.ensureTokenAccountsLoaded() #expect(settings.zaiAPIToken.isEmpty) #expect(settings.syntheticAPIToken.isEmpty) } @Test func keychainDisableForcesManualCookieSources() { let suite = "SettingsStoreCoverageTests-keychain" let defaults = UserDefaults(suiteName: suite)! defaults.removePersistentDomain(forName: suite) let configStore = testConfigStore(suiteName: suite) let settings = Self.makeSettingsStore(userDefaults: defaults, configStore: configStore) settings.codexCookieSource = .auto settings.claudeCookieSource = .auto settings.kimiCookieSource = .off settings.debugDisableKeychainAccess = true #expect(settings.codexCookieSource == .manual) #expect(settings.claudeCookieSource == .manual) #expect(settings.kimiCookieSource == .off) } private static func makeSettingsStore(suiteName: String = "SettingsStoreCoverageTests") -> SettingsStore { let defaults = UserDefaults(suiteName: suiteName)! defaults.removePersistentDomain(forName: suiteName) defaults.set(false, forKey: "debugDisableKeychainAccess") let configStore = testConfigStore(suiteName: suiteName) return Self.makeSettingsStore(userDefaults: defaults, configStore: configStore) } private static func makeSettingsStore( userDefaults: UserDefaults, configStore: CodexBarConfigStore) -> SettingsStore { SettingsStore( userDefaults: userDefaults, configStore: configStore, zaiTokenStore: NoopZaiTokenStore(), syntheticTokenStore: NoopSyntheticTokenStore(), codexCookieStore: InMemoryCookieHeaderStore(), claudeCookieStore: InMemoryCookieHeaderStore(), cursorCookieStore: InMemoryCookieHeaderStore(), opencodeCookieStore: InMemoryCookieHeaderStore(), factoryCookieStore: InMemoryCookieHeaderStore(), minimaxCookieStore: InMemoryMiniMaxCookieStore(), minimaxAPITokenStore: InMemoryMiniMaxAPITokenStore(), kimiTokenStore: InMemoryKimiTokenStore(), kimiK2TokenStore: InMemoryKimiK2TokenStore(), augmentCookieStore: InMemoryCookieHeaderStore(), ampCookieStore: InMemoryCookieHeaderStore(), copilotTokenStore: InMemoryCopilotTokenStore(), tokenAccountStore: InMemoryTokenAccountStore()) }}
import CodexBarCore
import Foundation
import Testing
@testable import CodexBar
@MainActor
@Suite
struct SettingsStoreCoverageTests {
@Test
func providerOrderingAndCaching() throws {
let suite = "SettingsStoreCoverageTests-ordering"
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let configStore = testConfigStore(suiteName: suite)
let config = CodexBarConfig(providers: [
ProviderConfig(id: .zai),
ProviderConfig(id: .codex),
ProviderConfig(id: .claude),
])
try configStore.save(config)
let settings = Self.makeSettingsStore(userDefaults: defaults, configStore: configStore)
let ordered = settings.orderedProviders()
let cached = settings.orderedProviders()
#expect(ordered == cached)
#expect(ordered.first == .zai)
#expect(ordered.contains(.minimax))
settings.moveProvider(fromOffsets: IndexSet(integer: 0), toOffset: 2)
#expect(settings.orderedProviders() != ordered)
let metadata = ProviderRegistry.shared.metadata
settings.setProviderEnabled(provider: .codex, metadata: metadata[.codex]!, enabled: true)
settings.setProviderEnabled(provider: .claude, metadata: metadata[.claude]!, enabled: false)
let enabled = settings.enabledProvidersOrdered(metadataByProvider: metadata)
#expect(enabled.contains(.codex))
}
@Test
func menuBarMetricPreferencesAndDisplayModes() {
let settings = Self.makeSettingsStore()
settings.setMenuBarMetricPreference(.average, for: .codex)
#expect(settings.menuBarMetricPreference(for: .codex) == .automatic)
settings.setMenuBarMetricPreference(.average, for: .gemini)
#expect(settings.menuBarMetricPreference(for: .gemini) == .average)
#expect(settings.menuBarMetricSupportsAverage(for: .gemini))
settings.setMenuBarMetricPreference(.secondary, for: .zai)
#expect(settings.menuBarMetricPreference(for: .zai) == .primary)
settings.menuBarDisplayMode = .pace
#expect(settings.menuBarDisplayMode == .pace)
settings.resetTimesShowAbsolute = true
#expect(settings.resetTimeDisplayStyle == .absolute)
}
@Test
func tokenAccountMutationsApplySideEffects() {
let settings = Self.makeSettingsStore()
settings.addTokenAccount(provider: .claude, label: "Primary", token: "token")
#expect(settings.tokenAccounts(for: .claude).count == 1)
#expect(settings.claudeCookieSource == .manual)
let account = settings.selectedTokenAccount(for: .claude)
#expect(account != nil)
settings.setActiveTokenAccountIndex(10, for: .claude)
#expect(settings.selectedTokenAccount(for: .claude)?.id == account?.id)
if let id = account?.id {
settings.removeTokenAccount(provider: .claude, accountID: id)
}
#expect(settings.tokenAccounts(for: .claude).isEmpty)
settings.reloadTokenAccounts()
}
@Test
func tokenCostUsageSourceDetection() throws {
let fileManager = FileManager.default
let root = fileManager.temporaryDirectory.appendingPathComponent(
"token-cost-\(UUID().uuidString)",
isDirectory: true)
let codexRoot = root.appendingPathComponent("sessions", isDirectory: true)
try fileManager.createDirectory(at: codexRoot, withIntermediateDirectories: true)
let codexFile = codexRoot.appendingPathComponent("usage.jsonl")
fileManager.createFile(atPath: codexFile.path, contents: Data("{}".utf8))
#expect(SettingsStore.hasAnyTokenCostUsageSources(
env: ["CODEX_HOME": root.path],
fileManager: fileManager))
let claudeRoot = fileManager.temporaryDirectory.appendingPathComponent(
"claude-\(UUID().uuidString)",
isDirectory: true)
let claudeProjects = claudeRoot.appendingPathComponent("projects", isDirectory: true)
try fileManager.createDirectory(at: claudeProjects, withIntermediateDirectories: true)
let claudeFile = claudeProjects.appendingPathComponent("usage.jsonl")
fileManager.createFile(atPath: claudeFile.path, contents: Data("{}".utf8))
#expect(SettingsStore.hasAnyTokenCostUsageSources(
env: ["CLAUDE_CONFIG_DIR": claudeRoot.path],
fileManager: fileManager))
}
@Test
func ensureTokenLoadersExecute() {
let settings = Self.makeSettingsStore()
settings.ensureZaiAPITokenLoaded()
settings.ensureSyntheticAPITokenLoaded()
settings.ensureCodexCookieLoaded()
settings.ensureClaudeCookieLoaded()
settings.ensureCursorCookieLoaded()
settings.ensureOpenCodeCookieLoaded()
settings.ensureFactoryCookieLoaded()
settings.ensureMiniMaxCookieLoaded()
settings.ensureMiniMaxAPITokenLoaded()
settings.ensureKimiAuthTokenLoaded()
settings.ensureKimiK2APITokenLoaded()
settings.ensureAugmentCookieLoaded()
settings.ensureAmpCookieLoaded()
settings.ensureCopilotAPITokenLoaded()
settings.ensureTokenAccountsLoaded()
#expect(settings.zaiAPIToken.isEmpty)
#expect(settings.syntheticAPIToken.isEmpty)
}
@Test
func keychainDisableForcesManualCookieSources() {
let suite = "SettingsStoreCoverageTests-keychain"
let defaults = UserDefaults(suiteName: suite)!
defaults.removePersistentDomain(forName: suite)
let configStore = testConfigStore(suiteName: suite)
let settings = Self.makeSettingsStore(userDefaults: defaults, configStore: configStore)
settings.codexCookieSource = .auto
settings.claudeCookieSource = .auto
settings.kimiCookieSource = .off
settings.debugDisableKeychainAccess = true
#expect(settings.codexCookieSource == .manual)
#expect(settings.claudeCookieSource == .manual)
#expect(settings.kimiCookieSource == .off)
}
private static func makeSettingsStore(suiteName: String = "SettingsStoreCoverageTests") -> SettingsStore {
let defaults = UserDefaults(suiteName: suiteName)!
defaults.removePersistentDomain(forName: suiteName)
defaults.set(false, forKey: "debugDisableKeychainAccess")
let configStore = testConfigStore(suiteName: suiteName)
return Self.makeSettingsStore(userDefaults: defaults, configStore: configStore)
}
private static func makeSettingsStore(
userDefaults: UserDefaults,
configStore: CodexBarConfigStore) -> SettingsStore
{
SettingsStore(
userDefaults: userDefaults,
configStore: configStore,
zaiTokenStore: NoopZaiTokenStore(),
syntheticTokenStore: NoopSyntheticTokenStore(),
codexCookieStore: InMemoryCookieHeaderStore(),
claudeCookieStore: InMemoryCookieHeaderStore(),
cursorCookieStore: InMemoryCookieHeaderStore(),
opencodeCookieStore: InMemoryCookieHeaderStore(),
factoryCookieStore: InMemoryCookieHeaderStore(),
minimaxCookieStore: InMemoryMiniMaxCookieStore(),
minimaxAPITokenStore: InMemoryMiniMaxAPITokenStore(),
kimiTokenStore: InMemoryKimiTokenStore(),
kimiK2TokenStore: InMemoryKimiK2TokenStore(),
augmentCookieStore: InMemoryCookieHeaderStore(),
ampCookieStore: InMemoryCookieHeaderStore(),
copilotTokenStore: InMemoryCopilotTokenStore(),
tokenAccountStore: InMemoryTokenAccountStore())
}
}