180 lines
7.5 KiB
Swift
180 lines
7.5 KiB
Swift
import AppKit
|
|
import CodexBarCore
|
|
import Foundation
|
|
import Testing
|
|
@testable import CodexBar
|
|
|
|
@MainActor
|
|
struct MenuCardOverrideIsolationTests {
|
|
@Test
|
|
func `nil snapshot account card does not inherit ambient Claude costs`() throws {
|
|
let suite = "MenuCardOverrideIsolationTests-\(UUID().uuidString)"
|
|
let defaults = try #require(UserDefaults(suiteName: suite))
|
|
defaults.removePersistentDomain(forName: suite)
|
|
let settings = SettingsStore(
|
|
userDefaults: defaults,
|
|
configStore: testConfigStore(suiteName: suite),
|
|
zaiTokenStore: NoopZaiTokenStore(),
|
|
syntheticTokenStore: NoopSyntheticTokenStore())
|
|
settings.costUsageEnabled = true
|
|
let fetcher = UsageFetcher()
|
|
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
|
|
store._setTokenSnapshotForTesting(
|
|
CostUsageTokenSnapshot(
|
|
sessionTokens: 123,
|
|
sessionCostUSD: 0.12,
|
|
last30DaysTokens: 456,
|
|
last30DaysCostUSD: 1.23,
|
|
daily: [],
|
|
updatedAt: Date()),
|
|
provider: .claude)
|
|
let controller = StatusItemController(
|
|
store: store,
|
|
settings: settings,
|
|
account: fetcher.loadAccountInfo(),
|
|
updater: DisabledUpdaterController(),
|
|
preferencesSelection: PreferencesSelection(),
|
|
statusBar: .system)
|
|
|
|
let model = try #require(controller.menuCardModel(
|
|
for: .claude,
|
|
errorOverride: "Token expired",
|
|
forceOverrideCard: true,
|
|
accountOverride: AccountInfo(email: "account@example.com", plan: nil)))
|
|
|
|
#expect(model.tokenUsage == nil)
|
|
#expect(model.email == "account@example.com")
|
|
}
|
|
|
|
@Test
|
|
func `account card without its own error does not inherit the ambient Claude error`() throws {
|
|
let suite = "MenuCardOverrideIsolationTests-\(UUID().uuidString)"
|
|
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 fetcher = UsageFetcher()
|
|
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
|
|
store._setErrorForTesting("Claude OAuth credentials unavailable", provider: .claude)
|
|
let controller = StatusItemController(
|
|
store: store,
|
|
settings: settings,
|
|
account: fetcher.loadAccountInfo(),
|
|
updater: DisabledUpdaterController(),
|
|
preferencesSelection: PreferencesSelection(),
|
|
statusBar: .system)
|
|
let accountSnapshot = UsageSnapshot(
|
|
primary: RateWindow(usedPercent: 25, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: Date(),
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .claude,
|
|
accountEmail: "account@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "claude-swap"))
|
|
|
|
let model = try #require(controller.menuCardModel(
|
|
for: .claude,
|
|
snapshotOverride: accountSnapshot,
|
|
accountOverride: AccountInfo(email: "account@example.com", plan: nil)))
|
|
|
|
#expect(model.subtitleStyle != .error)
|
|
#expect(!model.subtitleText.contains("Claude OAuth credentials unavailable"))
|
|
|
|
let liveModel = try #require(controller.menuCardModel(for: .claude))
|
|
#expect(liveModel.subtitleStyle == .error)
|
|
#expect(liveModel.subtitleText == "Claude OAuth credentials unavailable")
|
|
}
|
|
|
|
@Test
|
|
func `failed stacked token account card keeps its configured label`() throws {
|
|
let suite = "MenuCardOverrideIsolationTests-\(UUID().uuidString)"
|
|
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 fetcher = UsageFetcher()
|
|
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
|
|
let controller = StatusItemController(
|
|
store: store,
|
|
settings: settings,
|
|
account: fetcher.loadAccountInfo(),
|
|
updater: DisabledUpdaterController(),
|
|
preferencesSelection: PreferencesSelection(),
|
|
statusBar: .system)
|
|
let account = ProviderTokenAccount(
|
|
id: UUID(),
|
|
label: "Rejected group",
|
|
token: "fixture",
|
|
addedAt: 0,
|
|
lastUsed: nil)
|
|
let accountSnapshot = TokenAccountUsageSnapshot(
|
|
account: account,
|
|
snapshot: nil,
|
|
error: "sub2api rejected the API key.",
|
|
sourceLabel: nil,
|
|
cacheKey: "fixture-cache")
|
|
|
|
let model = try #require(controller.tokenAccountMenuCardModel(
|
|
for: .sub2api,
|
|
accountSnapshot: accountSnapshot))
|
|
|
|
#expect(model.email == "Rejected group")
|
|
#expect(model.subtitleStyle == .error)
|
|
}
|
|
|
|
@Test
|
|
func `successful stacked token account card prefers fetched identity over configured label`() throws {
|
|
let suite = "MenuCardOverrideIsolationTests-\(UUID().uuidString)"
|
|
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 fetcher = UsageFetcher()
|
|
let store = UsageStore(fetcher: fetcher, browserDetection: BrowserDetection(cacheTTL: 0), settings: settings)
|
|
let controller = StatusItemController(
|
|
store: store,
|
|
settings: settings,
|
|
account: fetcher.loadAccountInfo(),
|
|
updater: DisabledUpdaterController(),
|
|
preferencesSelection: PreferencesSelection(),
|
|
statusBar: .system)
|
|
let account = ProviderTokenAccount(
|
|
id: UUID(),
|
|
label: "Configured group",
|
|
token: "fixture",
|
|
addedAt: 0,
|
|
lastUsed: nil)
|
|
let usage = UsageSnapshot(
|
|
primary: RateWindow(usedPercent: 25, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
|
|
secondary: nil,
|
|
updatedAt: Date(),
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .sub2api,
|
|
accountEmail: "fetched@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: nil))
|
|
let accountSnapshot = TokenAccountUsageSnapshot(
|
|
account: account,
|
|
snapshot: usage,
|
|
error: nil,
|
|
sourceLabel: "api",
|
|
cacheKey: "fixture-cache")
|
|
|
|
let model = try #require(controller.tokenAccountMenuCardModel(
|
|
for: .sub2api,
|
|
accountSnapshot: accountSnapshot))
|
|
|
|
#expect(model.email == "fetched@example.com")
|
|
}
|
|
}
|