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

882 lines
34 KiB
Swift

import CodexBarCore
import Foundation
import SwiftUI
import Testing
@testable import CodexBar
struct MenuCardModelCodexProjectionTests {
@Test
func `codex weekly lane derives pace from its visible window`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: projection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let weekly = try #require(model.metrics.first { $0.id == "secondary" })
#expect(weekly.detailLeftText == "10% in reserve")
#expect(weekly.detailRightText == "Lasts until reset")
}
@Test
func `codex weekly lane includes workday markers when workDaysPerWeek is set`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: projection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
quotaWarningThresholds: [.session: [], .weekly: []],
workDaysPerWeek: 5,
now: now))
let weekly = try #require(model.metrics.first { $0.id == "secondary" })
#expect(weekly.warningMarkerPercents.isEmpty)
#expect(weekly.workdayMarkerPercents == [20.0, 40.0, 60.0, 80.0])
let session = try #require(model.metrics.first { $0.id == "primary" })
#expect(session.warningMarkerPercents.isEmpty)
}
@Test
func `codex weekly lane keeps workday and quota warning markers separate`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: projection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
quotaWarningThresholds: [.session: [], .weekly: [50]],
workDaysPerWeek: 5,
now: now))
let weekly = try #require(model.metrics.first { $0.id == "secondary" })
#expect(weekly.warningMarkerPercents == [50.0])
#expect(weekly.workdayMarkerPercents == [20.0, 40.0, 60.0, 80.0])
}
@Test
func `codex weekly lane workday markers not inverted by usageBarsShowUsed`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: projection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
quotaWarningThresholds: [.session: [], .weekly: []],
workDaysPerWeek: 5,
now: now))
let weekly = try #require(model.metrics.first { $0.id == "secondary" })
#expect(weekly.warningMarkerPercents.isEmpty)
#expect(weekly.workdayMarkerPercents == [20.0, 40.0, 60.0, 80.0])
}
@Test
func `codex plan only snapshot shows limits unavailable placeholder`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "pro")
let snapshot = UsageSnapshot(
primary: nil,
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: identity)
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
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: UsageError.noRateLimitsFound.errorDescription,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.placeholder == "Limits not available")
#expect(model.metrics.isEmpty)
#expect(model.subtitleStyle == .info)
#expect(!model.subtitleText.contains("Found sessions"))
#expect(model.planText == "Pro 20x")
}
@Test
func `codex plan only snapshot keeps actionable refresh errors visible`() throws {
let now = Date()
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "pro")
let snapshot = UsageSnapshot(
primary: nil,
secondary: nil,
tertiary: nil,
updatedAt: now,
identity: identity)
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
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: "Codex connection failed: timed out.",
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.placeholder == nil)
#expect(model.subtitleStyle == .error)
#expect(model.subtitleText == "Codex connection failed: timed out.")
#expect(model.planText == "Pro 20x")
}
@Test
func `codex account fallback shows limits unavailable instead of no limits error`() throws {
let now = Date()
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: now))
#expect(model.placeholder == "Limits not available")
#expect(model.subtitleStyle == .info)
#expect(!model.subtitleText.contains("Found sessions"))
#expect(model.email == "user@example.com")
#expect(model.planText == "Pro 20x")
}
@Test
func `codex no account fallback keeps no limits error visible`() throws {
let now = Date()
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: UsageError.noRateLimitsFound.errorDescription,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.placeholder == nil)
#expect(model.subtitleStyle == .error)
#expect(model.subtitleText == UsageError.noRateLimitsFound.errorDescription)
}
@Test
func `builds metrics using used percent when enabled`() 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 dashboard = OpenAIDashboardSnapshot(
signedInEmail: "codex@example.com",
codeReviewRemainingPercent: 73,
codeReviewLimit: RateWindow(
usedPercent: 27,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
creditEvents: [],
dailyBreakdown: [],
usageBreakdown: [],
creditsPurchaseURL: nil,
updatedAt: now)
let codexProjection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
rawUsageError: nil,
liveCredits: nil,
rawCreditsError: nil,
liveDashboard: dashboard,
rawDashboardError: nil,
dashboardAttachmentAuthorized: true,
dashboardRequiresLogin: false,
now: now))
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
codexProjection: codexProjection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: "Plus Plan"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: true,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.first?.title == "Session")
#expect(model.metrics.first?.percent == 22)
#expect(model.metrics.first?.percentLabel.contains("used") == true)
#expect(model.metrics.contains { $0.title == "Code review" && $0.percent == 27 })
}
@Test
func `shows code review metric when dashboard present`() 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 dashboard = OpenAIDashboardSnapshot(
signedInEmail: "codex@example.com",
codeReviewRemainingPercent: 73,
codeReviewLimit: RateWindow(
usedPercent: 27,
windowMinutes: nil,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
creditEvents: [],
dailyBreakdown: [],
usageBreakdown: [],
creditsPurchaseURL: nil,
updatedAt: now)
let codexProjection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
rawUsageError: nil,
liveCredits: nil,
rawCreditsError: nil,
liveDashboard: dashboard,
rawDashboardError: nil,
dashboardAttachmentAuthorized: true,
dashboardRequiresLogin: false,
now: now))
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
codexProjection: codexProjection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
#expect(model.metrics.contains { $0.title == "Code review" && $0.percent == 73 })
let codeReviewMetric = model.metrics.first { $0.id == "code-review" }
#expect(codeReviewMetric?.resetText?.contains("Resets") == true)
}
@Test
func `uses semantic codex lanes when weekly duration drifts`() throws {
let now = Date()
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "codex@example.com",
accountOrganization: nil,
loginMethod: nil)
let snapshot = UsageSnapshot(
primary: nil,
secondary: RateWindow(
usedPercent: 25,
windowMinutes: 11040,
resetsAt: now.addingTimeInterval(3600),
resetDescription: nil),
tertiary: nil,
updatedAt: now,
identity: identity)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let codexProjection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: codexProjection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "codex@example.com", plan: nil),
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?.id == "secondary")
#expect(model.metrics.first?.title == "Weekly")
#expect(model.metrics.first?.percent == 75)
}
@Test
func `renders codex spark as a named extra metric after the core lanes`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
extraRateWindows: [
NamedRateWindow(
id: "codex-spark",
title: "Codex Spark 5-hour",
window: RateWindow(
usedPercent: 80,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(2 * 60 * 60),
resetDescription: nil)),
NamedRateWindow(
id: "codex-spark-weekly",
title: "Codex Spark Weekly",
window: RateWindow(
usedPercent: 100,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil)),
],
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
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: snapshot,
codexProjection: projection,
credits: nil,
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
hidePersonalInfo: false,
now: now))
let spark = try #require(model.metrics.first { $0.id == "codex-spark" })
#expect(spark.title == "Codex Spark 5-hour")
#expect(spark.percent == 20)
#expect(spark.percentLabel == "20% left")
#expect(spark.resetText != nil)
#expect(spark.detailLeftText == "20% in deficit")
#expect(spark.detailRightText == "Projected empty in 45m")
let sparkWeekly = try #require(model.metrics.first { $0.id == "codex-spark-weekly" })
#expect(sparkWeekly.title == "Codex Spark Weekly")
#expect(sparkWeekly.percent == 0)
#expect(sparkWeekly.percentLabel == "0% left")
#expect(sparkWeekly.resetText != nil)
#expect(sparkWeekly.detailLeftText == "86% in deficit")
#expect(sparkWeekly.detailRightText == "Runs out now")
// Spark trails the core session/weekly lanes rather than replacing them.
let sparkIndex = try #require(model.metrics.firstIndex { $0.id == "codex-spark" })
let sparkWeeklyIndex = try #require(model.metrics.firstIndex { $0.id == "codex-spark-weekly" })
let sessionIndex = try #require(model.metrics.firstIndex { $0.id == "primary" })
#expect(sparkIndex > sessionIndex)
#expect(sparkWeeklyIndex > sparkIndex)
}
@Test
func `hides codex credits when disabled`() 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 codexProjection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
rawUsageError: nil,
liveCredits: CreditsSnapshot(remaining: 12, events: [], updatedAt: now),
rawCreditsError: nil,
liveDashboard: nil,
rawDashboardError: nil,
dashboardAttachmentAuthorized: false,
dashboardRequiresLogin: false,
now: now))
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
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: nil),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: false,
hidePersonalInfo: false,
now: now))
#expect(model.creditsText == nil)
}
}
struct MenuCardModelCodexSparkVisibilityTests {
@Test
func `codex spark visibility hides only spark metrics`() throws {
let now = Date(timeIntervalSince1970: 1_800_000_000)
let metadata = try #require(ProviderDefaults.metadata[.codex])
let identity = ProviderIdentitySnapshot(
providerID: .codex,
accountEmail: "user@example.com",
accountOrganization: nil,
loginMethod: "Pro")
let snapshot = UsageSnapshot(
primary: RateWindow(
usedPercent: 2,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(4 * 60 * 60),
resetDescription: nil),
secondary: RateWindow(
usedPercent: 4,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil),
tertiary: nil,
extraRateWindows: [
NamedRateWindow(
id: "codex-spark",
title: "Codex Spark 5-hour",
window: RateWindow(
usedPercent: 30,
windowMinutes: 300,
resetsAt: now.addingTimeInterval(60 * 60),
resetDescription: nil)),
NamedRateWindow(
id: "codex-spark-weekly",
title: "Codex Spark Weekly",
window: RateWindow(
usedPercent: 100,
windowMinutes: 10080,
resetsAt: now.addingTimeInterval(6 * 24 * 60 * 60),
resetDescription: nil)),
NamedRateWindow(
id: "codex-other-limit",
title: "Other Codex limit",
window: RateWindow(
usedPercent: 25,
windowMinutes: 1440,
resetsAt: now.addingTimeInterval(12 * 60 * 60),
resetDescription: nil)),
],
updatedAt: now,
identity: identity)
let projection = CodexConsumerProjection.make(
surface: .liveCard,
context: CodexConsumerProjection.Context(
snapshot: snapshot,
rawUsageError: nil,
liveCredits: CreditsSnapshot(remaining: 12, events: [], updatedAt: now),
rawCreditsError: nil,
liveDashboard: nil,
rawDashboardError: nil,
dashboardAttachmentAuthorized: false,
dashboardRequiresLogin: false,
now: now))
let model = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
codexProjection: projection,
credits: CreditsSnapshot(remaining: 12, events: [], updatedAt: now),
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: true,
codexSparkUsageVisible: false,
hidePersonalInfo: false,
now: now))
#expect(!model.metrics.contains { $0.id == "codex-spark" })
#expect(!model.metrics.contains { $0.id == "codex-spark-weekly" })
#expect(model.metrics.contains { $0.id == "primary" })
#expect(model.metrics.contains { $0.id == "secondary" })
#expect(model.metrics.contains { $0.id == "codex-other-limit" })
#expect(model.creditsText != nil)
let globalOffModel = UsageMenuCardView.Model.make(.init(
provider: .codex,
metadata: metadata,
snapshot: snapshot,
codexProjection: projection,
credits: CreditsSnapshot(remaining: 12, events: [], updatedAt: now),
creditsError: nil,
dashboard: nil,
dashboardError: nil,
tokenSnapshot: nil,
tokenError: nil,
account: AccountInfo(email: "user@example.com", plan: "Pro"),
isRefreshing: false,
lastError: nil,
usageBarsShowUsed: false,
resetTimeDisplayStyle: .countdown,
tokenCostUsageEnabled: false,
showOptionalCreditsAndExtraUsage: false,
codexSparkUsageVisible: true,
hidePersonalInfo: false,
now: now))
#expect(!globalOffModel.metrics.contains { $0.id == "codex-spark" })
#expect(!globalOffModel.metrics.contains { $0.id == "codex-spark-weekly" })
#expect(!globalOffModel.metrics.contains { $0.id == "codex-other-limit" })
#expect(globalOffModel.creditsText == nil)
}
}