Files
steipete--codexbar/Tests/CodexBarTests/MenuCardModelTests.swift
T
2026-07-13 12:22:33 +08:00

1572 lines
58 KiB
Swift

import CodexBarCore
import Foundation
import SwiftUI
import Testing
@testable import CodexBar
struct OverviewMenuCardVisibilityTests {
@Test
func `overview hides cards that only contain an error`() throws {
let metadata = try #require(ProviderDefaults.metadata[.cursor])
let model = UsageMenuCardView.Model.make(.init(
provider: .cursor,
metadata: metadata,
snapshot: nil,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: "No Cursor session found.",
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: Date()))
#expect(model.isOverviewErrorOnly)
}
@Test
func `overview keeps cards with graceful unavailable placeholders`() throws {
let metadata = try #require(ProviderDefaults.metadata[.codex])
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: nil,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "pro"),
isRefreshing: false,
lastError: UsageError.noRateLimitsFound.errorDescription,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: Date()))
#expect(model.placeholder == "Limits not available")
#expect(!model.isOverviewErrorOnly)
}
@Test
func `claude subscription-only quota keeps local cost content`() throws {
let metadata = try #require(ProviderDefaults.metadata[.claude])
let now = Date(timeIntervalSince1970: 1_800_000_000)
let tokenSnapshot = CostUsageTokenSnapshot(
sessionTokens: 4200,
sessionCostUSD: 1.25,
last30DaysTokens: 42000,
last30DaysCostUSD: 12.50,
daily: [],
updatedAt: now)
let quotaError = ClaudeStatusProbeError.parseFailed(
ClaudeStatusProbe.subscriptionQuotaUnavailableDescription).localizedDescription
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: nil,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: tokenSnapshot,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: quotaError,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: true,
tokenCostMenuSectionEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.placeholder == "Limits not available")
#expect(model.subtitleStyle == .info)
#expect(model.tokenUsage != nil)
#expect(model.metrics.isEmpty)
#expect(!model.isOverviewErrorOnly)
}
}
struct ProviderInlineDashboardModelTests {
@Test
func `kimi model orders rate limit before weekly quota`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.kimi])
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 18.3,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(4 * 24 * 60 * 60),
resetDescription: "375/2048 requests"),
secondary: RateWindow(
usedPercent: 9.5,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: "Rate: 19/200 per 5 hours"),
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .kimi,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.map(\.id) == ["secondary", "primary"])
#expect(model.metrics.map(\.title) == ["Rate Limit", "Weekly"])
}
@Test
func `openrouter period usage gets inline dashboard`() throws {
let now = Date(timeIntervalSince1970: 1_700_179_200)
let metadata = try #require(ProviderDefaults.metadata[.openrouter])
let usage = OpenRouterUsageSnapshot(
totalCredits: 100,
totalUsage: 40,
balance: 60,
usedPercent: 40,
keyDataFetched: true,
keyLimit: 25,
keyUsage: 10,
keyUsageDaily: 1.25,
keyUsageWeekly: 7.5,
keyUsageMonthly: 18.75,
rateLimit: OpenRouterRateLimit(requests: 100, interval: "10s"),
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .openrouter,
metadata: metadata,
snapshot: usage.toUsageSnapshot(),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.inlineUsageDashboard?.kpis.first?.value == "$60.00")
#expect(model.inlineUsageDashboard?.points.map(\.label) == ["Today", "Week", "Month"])
#expect(model.inlineUsageDashboard?.detailLines.contains("Rate limit: 100 / 10s") == true)
}
@Test
func `local cost history gets inline dashboard`() throws {
let now = Date(timeIntervalSince1970: 1_700_179_200)
let metadata = try #require(ProviderDefaults.metadata[.claude])
let daily = [
CostUsageDailyReport.Entry(
date: "2023-11-14",
inputTokens: 100,
outputTokens: 50,
totalTokens: 150,
costUSD: 0.12,
modelsUsed: ["claude-sonnet-4"],
modelBreakdowns: [
CostUsageDailyReport.ModelBreakdown(
modelName: "claude-sonnet-4",
costUSD: 0.12,
totalTokens: 150),
]),
CostUsageDailyReport.Entry(
date: "2023-11-15",
inputTokens: 200,
outputTokens: 75,
totalTokens: 275,
costUSD: 0.25,
modelsUsed: ["claude-opus-4"],
modelBreakdowns: [
CostUsageDailyReport.ModelBreakdown(
modelName: "claude-opus-4",
costUSD: 0.25,
totalTokens: 275),
]),
]
let tokenSnapshot = CostUsageTokenSnapshot(
sessionTokens: 275,
sessionCostUSD: 0.25,
last30DaysTokens: 425,
last30DaysCostUSD: 0.37,
daily: daily,
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: UsageSnapshot(
primary: RateWindow(usedPercent: 10, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
updatedAt: now),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: tokenSnapshot,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.inlineUsageDashboard?.kpis.first?.value == "$0.25")
#expect(model.inlineUsageDashboard?.points.count == 2)
#expect(model.inlineUsageDashboard?.detailLines.contains { $0.contains("claude-opus-4") } == true)
#expect(model.tokenUsage?.sessionLine.contains("$0.25") == true)
#expect(model.tokenUsage?.monthLine.contains("$0.37") == true)
}
@Test
func `mistral daily buckets get inline dashboard`() throws {
let now = Date(timeIntervalSince1970: 1_700_179_200)
let metadata = try #require(ProviderDefaults.metadata[.mistral])
let snapshot = MistralUsageSnapshot(
totalCost: 1.5,
currency: "EUR",
currencySymbol: "€",
totalInputTokens: 100,
totalOutputTokens: 50,
totalCachedTokens: 0,
modelCount: 1,
daily: [
MistralDailyUsageBucket(
day: "2023-11-14",
cost: 1.5,
inputTokens: 100,
cachedTokens: 0,
outputTokens: 50,
models: [
MistralDailyUsageBucket.ModelBreakdown(
name: "mistral-large",
cost: 1.5,
inputTokens: 100,
cachedTokens: 0,
outputTokens: 50),
]),
],
startDate: nil,
endDate: nil,
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .mistral,
metadata: metadata,
snapshot: snapshot.toUsageSnapshot(),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
tokenCostInlineDashboardEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.inlineUsageDashboard?.kpis.first?.value == "€1.50")
#expect(model.inlineUsageDashboard?.points.first?.accessibilityValue == "2023-11-14: €1.50")
#expect(model.inlineUsageDashboard?.detailLines.contains("Top model: mistral-large") == true)
}
@Test
func `mistral billing usage can show cost card summary`() throws {
let now = Date(timeIntervalSince1970: 1_700_179_200)
let metadata = try #require(ProviderDefaults.metadata[.mistral])
let snapshot = MistralUsageSnapshot(
totalCost: 1.5,
currency: "EUR",
currencySymbol: "€",
totalInputTokens: 100,
totalOutputTokens: 50,
totalCachedTokens: 25,
modelCount: 1,
daily: [
MistralDailyUsageBucket(
day: "2023-11-14",
cost: 1.5,
inputTokens: 100,
cachedTokens: 25,
outputTokens: 50,
models: [
MistralDailyUsageBucket.ModelBreakdown(
name: "mistral-large",
cost: 1.5,
inputTokens: 100,
cachedTokens: 25,
outputTokens: 50),
]),
],
startDate: nil,
endDate: nil,
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .mistral,
metadata: metadata,
snapshot: snapshot.toUsageSnapshot(),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: snapshot.toCostUsageTokenSnapshot(historyDays: 30),
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(ProviderDescriptorRegistry.descriptor(for: .mistral).tokenCost.supportsTokenCost)
#expect(model.tokenUsage?.sessionLine == "Latest billing day (Nov 14): €1.50 · 175 tokens")
#expect(model.tokenUsage?.monthLine == "This month: €1.50 · 175 tokens")
#expect(model.tokenUsage?.hintLine == "Reported by Mistral billing usage.")
}
@Test
func `zai hourly usage gets inline dashboard`() throws {
let now = try #require(Self.zaiDate("2023-11-15 12:00"))
let metadata = try #require(ProviderDefaults.metadata[.zai])
let usage = ZaiUsageSnapshot(
tokenLimit: nil,
timeLimit: nil,
planName: "Pro",
modelUsage: ZaiModelUsageData(
xTime: ["2023-11-14 12:00", "2023-11-15 12:00"],
modelDataList: [
ZaiModelDataItem(modelName: "glm-4.5", tokensUsage: [100, 200]),
]),
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .zai,
metadata: metadata,
snapshot: usage.toUsageSnapshot(),
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.inlineUsageDashboard?.kpis.first?.value == "300")
#expect(model.inlineUsageDashboard?.points.map(\.label) == ["12", "12"])
#expect(Set(model.inlineUsageDashboard?.points.map(\.id) ?? []).count == 2)
#expect(model.inlineUsageDashboard?.detailLines.contains("Top model: glm-4.5") == true)
}
private static func zaiDate(_ text: String) -> Date? {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm"
return formatter.date(from: text)
}
}
struct FactoryMenuCardModelTests {
@Test
func `factory token rate billing uses time window labels`() throws {
let now = Date()
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: RateWindow(usedPercent: 34, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
tertiary: RateWindow(usedPercent: 56, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
updatedAt: now,
identity: nil)
let metadata = try #require(ProviderDefaults.metadata[.factory])
let model = UsageMenuCardView.Model.make(.init(
provider: .factory,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.map(\.title) == ["5-hour", "Weekly", "Monthly"])
}
@Test
func `factory legacy billing keeps pool labels`() throws {
let now = Date()
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 12, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: RateWindow(usedPercent: 34, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
updatedAt: now,
identity: nil)
let metadata = try #require(ProviderDefaults.metadata[.factory])
let model = UsageMenuCardView.Model.make(.init(
provider: .factory,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.map(\.title) == ["Standard", "Premium"])
}
@Test
func `factory extra usage balance renders as optional balance`() throws {
let now = Date()
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: RateWindow(usedPercent: 34, windowMinutes: 10080, resetsAt: nil, resetDescription: nil),
tertiary: RateWindow(usedPercent: 56, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
providerCost: ProviderCostSnapshot(
used: 25,
limit: 0,
currencyCode: "USD",
period: "Extra usage balance",
updatedAt: now),
updatedAt: now,
identity: nil)
let metadata = try #require(ProviderDefaults.metadata[.factory])
let visible = UsageMenuCardView.Model.make(.init(
provider: .factory,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(visible.providerCost?.title == "Extra usage")
#expect(visible.providerCost?.spendLine == "Balance: $25.00")
#expect(visible.providerCost?.percentUsed == nil)
#expect(visible.providerCost?.percentLine == nil)
let hidden = UsageMenuCardView.Model.make(.init(
provider: .factory,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: false,
hidePersonalInfo: false,
now: now))
#expect(hidden.providerCost == nil)
}
}
struct MiniMaxMenuCardModelTests {
@Test
func `minimax service metrics use codex aligned quota copy`() throws {
let now = Date()
let minimax = MiniMaxUsageSnapshot(
planName: "Max",
availablePrompts: nil,
currentPrompts: nil,
remainingPrompts: nil,
windowMinutes: nil,
usedPercent: nil,
resetsAt: nil,
updatedAt: now,
services: [
MiniMaxServiceUsage(
serviceType: "text-generation",
windowType: "5 hours",
timeRange: "10:00-15:00(UTC+8)",
usage: 2,
limit: 10,
percent: 20,
resetsAt: now.addingTimeInterval(3600),
resetDescription: "Resets in 1 hour"),
])
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 20, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: nil,
minimaxUsage: minimax,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .minimax,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Max"))
let metadata = try #require(ProviderDefaults.metadata[.minimax])
let used = UsageMenuCardView.Model.make(.init(
provider: .minimax,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(used.metrics.first?.title == "Text Generation")
#expect(used.metrics.first?.detailLeftText == "Usage: 2 / 10")
#expect(used.metrics.first?.detailRightText == nil)
#expect(used.metrics.first?.detailText == nil)
#expect(used.metrics.first?.percent == 20)
#expect(used.metrics.first?.cardStyle == false)
}
@Test
func `text generation badge uses real window type when multiple windows exist`() throws {
let now = Date()
let minimax = MiniMaxUsageSnapshot(
planName: "Max",
availablePrompts: nil,
currentPrompts: nil,
remainingPrompts: nil,
windowMinutes: nil,
usedPercent: nil,
resetsAt: nil,
updatedAt: now,
services: [
MiniMaxServiceUsage(
serviceType: "text-generation",
windowType: "Today",
timeRange: "2026/05/16 00:00 - 2026/05/17 00:00",
usage: 2,
limit: 10,
percent: 20,
resetsAt: now.addingTimeInterval(3600),
resetDescription: "Resets in 1 hour"),
MiniMaxServiceUsage(
serviceType: "text-generation",
windowType: "Weekly",
timeRange: "05/11 00:00 - 05/18 00:00(UTC+8)",
usage: 20,
limit: 100,
percent: 20,
resetsAt: now.addingTimeInterval(7200),
resetDescription: "Resets in 2 hours"),
])
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 20, windowMinutes: 1440, resetsAt: nil, resetDescription: nil),
secondary: nil,
minimaxUsage: minimax,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .minimax,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Max"))
let metadata = try #require(ProviderDefaults.metadata[.minimax])
let model = UsageMenuCardView.Model.make(.init(
provider: .minimax,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.count == 2)
#expect(model.metrics[0].title == "Text Generation · Today")
#expect(model.metrics[1].title == "Text Generation · Weekly")
}
@Test
func `minimax token plan model shows weekly quota and points balance`() throws {
let now = Date()
let minimax = MiniMaxUsageSnapshot(
planName: "Token Plan · TokenPlanPlus-年度会员",
availablePrompts: nil,
currentPrompts: nil,
remainingPrompts: nil,
windowMinutes: nil,
usedPercent: nil,
resetsAt: nil,
updatedAt: now,
services: [
MiniMaxServiceUsage(
serviceType: "text-generation",
windowType: "5 hours",
timeRange: "10:00-15:00(UTC+8)",
usage: 4,
limit: 100,
percent: 4,
resetsAt: now.addingTimeInterval(4 * 3600),
resetDescription: "Resets in 4 hours"),
MiniMaxServiceUsage(
serviceType: "text-generation",
windowType: "Weekly",
timeRange: "06/01 00:00 - 06/08 00:00(UTC+8)",
usage: 1,
limit: 100,
percent: 1,
resetsAt: now.addingTimeInterval(6 * 24 * 3600),
resetDescription: "Resets in 6 days"),
],
pointsBalance: 14000,
subscriptionRenewsAt: Date(timeIntervalSince1970: 1_810_569_600))
let snapshot = minimax.toUsageSnapshot()
let metadata = try #require(ProviderDefaults.metadata[.minimax])
let model = UsageMenuCardView.Model.make(.init(
provider: .minimax,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.planText == "Plus")
#expect(model.metrics[0].title == "Text Generation · 5h")
#expect(model.metrics[1].title == "Text Generation · Weekly")
#expect(model.metrics[0].detailLeftText == "Usage: 4 / 100")
#expect(model.metrics[1].detailLeftText == "Usage: 1 / 100")
#expect(model.metrics[0].detailRightText == nil)
#expect(model.metrics[1].detailRightText == nil)
#expect(model.metrics[0].detailText == nil)
#expect(model.metrics[1].detailText == nil)
#expect(model.metrics[0].cardStyle == false)
#expect(model.metrics[1].cardStyle == false)
#expect(model.providerCost?.title == "Credits")
#expect(model.providerCost?.spendLine == "Balance: 14000")
#expect(model.usageNotes == [String(format: L("Renews: %@"), minimaxRenewDate(1_810_569_600))])
}
}
struct ClaudeMenuCardCostTests {
@Test
func `claude extra usage labels monthly denominator as cap`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.claude])
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 0, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
tertiary: nil,
providerCost: ProviderCostSnapshot(
used: 5,
limit: 20,
currencyCode: "USD",
period: "Monthly cap",
updatedAt: now),
updatedAt: now,
identity: nil)
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.providerCost?.spendLine == "Monthly cap: $5.00 / $20.00")
}
}
struct MenuCardModelTests {
@Test
func `builds metrics using remaining percent`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "codex@example.com",
accountOrganization: nil,
loginMethod: "Plus Plan")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 22,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(3000),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 40,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6000),
resetDescription: nil),
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let updatedSnap = try UsageSnapshot(
primary: snapshot.primary,
secondary: RateWindow(
usedPercent: #require(snapshot.secondary?.usedPercent),
windowMinutes: #require(snapshot.secondary?.windowMinutes),
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
tertiary: snapshot.tertiary,
updatedAt: now,
identity: identity)
let codexProjection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: updatedSnap,
rawUsageError: nil,
liveCredits: nil,
rawCreditsError: nil,
liveDashboard: nil,
rawDashboardError: nil,
dashboardAttachmentAuthorized: false,
dashboardRequiresLogin: false,
now: now))
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: updatedSnap,
codexProjection: codexProjection,
credits: CreditsSnapshot(remaining: 12, events: [], updatedAt: now),
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: "Plus Plan"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
quotaWarningThresholds: [.session: [50, 20], .weekly: [25, 0]],
now: now))
#expect(model.providerName == "Codex")
#expect(model.metrics.count == 2)
#expect(model.metrics.first?.percent == 78)
#expect(model.metrics.first?.warningMarkerPercents == [50, 20])
#expect(model.metrics[1].warningMarkerPercents == [25])
#expect(model.planText == "Plus")
#expect(model.subtitleText.hasPrefix("Updated"))
#expect(model.progressColor != Color.clear)
#expect(model.metrics[1].resetText?.isEmpty == false)
}
@Test
func `claude model hides weekly when unavailable`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .claude,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Max")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.claude])
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: "plus"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.count == 1)
#expect(model.metrics.first?.title == "Session")
#expect(model.planText == "Max")
}
@Test
func `claude model includes routines bar when present`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .claude,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Max")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 8,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(7200),
resetDescription: nil),
tertiary: RateWindow(
usedPercent: 16,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(7800),
resetDescription: nil),
extraRateWindows: [
NamedRateWindow(
id: "claude-routines",
title: "Daily Routines",
window: RateWindow(
usedPercent: 7,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(9200),
resetDescription: nil)),
],
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.claude])
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: "plus"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.map(\.title) == ["Session", "Weekly", "Sonnet", "Daily Routines"])
}
@Test
func `shows error subtitle when present`() throws {
let metadata = try #require(ProviderDefaults.metadata[.codex])
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: nil,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: "Probe failed for Codex",
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: Date()))
#expect(model.subtitleStyle == .error)
#expect(model.subtitleText.contains("Probe failed"))
#expect(model.placeholder == nil)
}
@Test
func `cost section includes last30 days tokens`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.codex])
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 0, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: nil,
tertiary: nil,
updatedAt: now)
let tokenSnapshot = CostUsageTokenSnapshot(
sessionTokens: 123,
sessionCostUSD: 1.23,
last30DaysTokens: 456,
last30DaysCostUSD: 78.9,
daily: [],
updatedAt: now)
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: tokenSnapshot,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: true,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.tokenUsage?.monthLine.contains("456") == true)
#expect(model.tokenUsage?.monthLine.contains("tokens") == true)
#expect(model.tokenUsage?.hintLine == "Estimated from local Codex logs for the selected account.")
}
@Test
func `claude model does not leak codex plan`() throws {
let metadata = try #require(ProviderDefaults.metadata[.claude])
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: nil,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: "plus"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: Date()))
#expect(model.planText == nil)
#expect(model.email.isEmpty)
}
@Test
func `hides claude extra usage when disabled`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .claude,
accountEmail: "claude@example.com",
accountOrganization: nil,
loginMethod: nil)
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 0, windowMinutes: nil, resetsAt: nil, resetDescription: nil),
secondary: nil,
tertiary: nil,
providerCost: ProviderCostSnapshot(used: 12, limit: 200, currencyCode: "USD", updatedAt: now),
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.claude])
let model = UsageMenuCardView.Model.make(.init(
provider: .claude,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: false,
hidePersonalInfo: false,
now: now))
#expect(model.providerCost == nil)
}
@Test
@MainActor
func `open router model uses API key quota bar and quota detail`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.openrouter])
let snapshot = OpenRouterUsageSnapshot(
totalCredits: 50,
totalUsage: 45.3895596325,
balance: 4.6104403675,
usedPercent: 90.779119265,
keyLimit: 20,
keyUsage: 0.5,
rateLimit: nil,
updatedAt: now).toUsageSnapshot()
let model = UsageMenuCardView.Model.make(.init(
provider: .openrouter,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.creditsText == nil)
#expect(model.metrics.count == 1)
#expect(model.usageNotes.isEmpty)
let metric = try #require(model.metrics.first)
let popupTitle = UsageMenuCardView.popupMetricTitle(
provider: .openrouter,
metric: metric)
#expect(popupTitle == "API key limit")
#expect(metric.resetText == "$19.50/$20.00 left")
#expect(metric.detailRightText == nil)
}
@Test
func `open router model without key limit shows text only summary`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.openrouter])
let snapshot = OpenRouterUsageSnapshot(
totalCredits: 50,
totalUsage: 45.3895596325,
balance: 4.6104403675,
usedPercent: 90.779119265,
keyDataFetched: true,
keyLimit: nil,
keyUsage: nil,
rateLimit: nil,
updatedAt: now).toUsageSnapshot()
let model = UsageMenuCardView.Model.make(.init(
provider: .openrouter,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.isEmpty)
#expect(model.creditsText == nil)
#expect(model.placeholder == nil)
#expect(model.usageNotes == ["No limit set for the API key"])
}
@Test
func `open router model when key fetch unavailable shows unavailable note`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.openrouter])
let snapshot = OpenRouterUsageSnapshot(
totalCredits: 50,
totalUsage: 45.3895596325,
balance: 4.6104403675,
usedPercent: 90.779119265,
keyDataFetched: false,
keyLimit: nil,
keyUsage: nil,
rateLimit: nil,
updatedAt: now).toUsageSnapshot()
let model = UsageMenuCardView.Model.make(.init(
provider: .openrouter,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.isEmpty)
#expect(model.usageNotes == ["API key limit unavailable right now"])
}
@Test
func `hides email when personal info hidden`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "codex@example.com",
accountOrganization: nil,
loginMethod: nil)
let snapshot = UsageSnapshot(
primary: RateWindow(usedPercent: 0, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: "OpenAI dashboard signed in as codex@example.com.",
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: nil),
isRefreshing: false,
lastError: "OpenAI dashboard signed in as codex@example.com.",
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: true,
now: now))
#expect(model.email.isEmpty)
#expect(model.subtitleText.contains("codex@example.com") == false)
#expect(model.creditsHintCopyText?.isEmpty == true)
#expect(model.creditsHintText?.contains("codex@example.com") == false)
}
@Test
func `kilo model splits pass and activity and shows fallback note`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.kilo])
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 40,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "40/100 credits"),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .kilo,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Kilo Pass Pro · Auto top-up: visa"))
let model = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
sourceLabel: "cli",
kiloAutoMode: true,
hidePersonalInfo: false,
now: now))
#expect(model.planText == "Kilo Pass Pro")
#expect(model.usageNotes.contains("Auto top-up: visa"))
#expect(model.usageNotes.contains("Using CLI fallback"))
}
@Test
func `kilo model treats auto top up only login as activity`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.kilo])
let snapshot = UsageSnapshot(
primary: nil,
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .kilo,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Auto top-up: off"))
let model = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.planText == nil)
#expect(model.usageNotes.contains("Auto top-up: off"))
}
@Test
func `kilo model does not show fallback note when not auto to CLI`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.kilo])
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 40,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "40/100 credits"),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .kilo,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Kilo Pass Pro · Auto top-up: visa"))
let apiModel = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
sourceLabel: "api",
kiloAutoMode: true,
hidePersonalInfo: false,
now: now))
let nonAutoModel = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
sourceLabel: "cli",
kiloAutoMode: false,
hidePersonalInfo: false,
now: now))
#expect(!apiModel.usageNotes.contains("Using CLI fallback"))
#expect(!nonAutoModel.usageNotes.contains("Using CLI fallback"))
}
@Test
func `kilo model shows primary detail when reset date missing`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.kilo])
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 10,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "10/100 credits"),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: ProviderIdentitySnapshot(
providerID: .kilo,
accountEmail: nil,
accountOrganization: nil,
loginMethod: "Kilo Pass Pro"))
let model = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let primary = try #require(model.metrics.first)
#expect(primary.resetText == nil)
#expect(primary.detailText == "10/100 credits")
}
@Test
func `kilo model keeps zero total edge state visible`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.kilo])
let snapshot = KiloUsageSnapshot(
creditsUsed: 0,
creditsTotal: 0,
creditsRemaining: 0,
planName: "Kilo Pass Pro",
autoTopUpEnabled: true,
autoTopUpMethod: "visa",
updatedAt: now).toUsageSnapshot()
let model = UsageMenuCardView.Model.make(.init(
provider: .kilo,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let primary = try #require(model.metrics.first)
#expect(primary.percent == 0)
#expect(primary.detailText == "0/0 credits")
#expect(model.placeholder == nil)
}
@Test
func `warp model shows primary detail when reset date missing`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .warp,
accountEmail: nil,
accountOrganization: nil,
loginMethod: nil)
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 10,
windowMinutes: nil,
resetsAt: nil,
resetDescription: "10/100 credits"),
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.warp])
let model = UsageMenuCardView.Model.make(.init(
provider: .warp,
metadata: metadata,
snapshot: snapshot,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: nil, plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let primary = try #require(model.metrics.first)
#expect(primary.resetText == nil)
#expect(primary.detailText == "10/100 credits")
}
}