343 lines
10 KiB
Swift
343 lines
10 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodexBar
|
|
@testable import CodexBarCore
|
|
|
|
struct ClaudeCLIScopedWeeklyUsageTests {
|
|
@Test
|
|
func `CLI usage surfaces Fable scoped weekly limit`() async throws {
|
|
let cliUsage = """
|
|
Settings Status Config Usage Stats
|
|
|
|
Current session
|
|
9% used
|
|
Resets 2:09pm (Europe/Prague)
|
|
|
|
Current week (all models)
|
|
67% used
|
|
Resets Jul 10 t 2:59am (Europe/Prague)
|
|
|
|
Current week (Fable)
|
|
68% used
|
|
Reset Jul 10 at 2:59am (Europe/Prague)
|
|
|
|
Current week (Example Model)
|
|
12% used
|
|
"""
|
|
let status = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
let fetcher = ClaudeUsageFetcher(
|
|
browserDetection: BrowserDetection(cacheTTL: 0),
|
|
environment: [:],
|
|
dataSource: .cli)
|
|
let fetchOverride: ClaudeStatusProbe.FetchOverride = { _, _, _ in status }
|
|
|
|
let snapshot = try await ClaudeCLIResolver.withResolvedBinaryPathOverrideForTesting("/usr/bin/true") {
|
|
try await ClaudeStatusProbe.withFetchOverrideForTesting(fetchOverride) {
|
|
try await fetcher.loadLatestUsage(model: "sonnet")
|
|
}
|
|
}
|
|
|
|
let fable = try #require(snapshot.extraRateWindows.first { $0.id == "claude-weekly-scoped-fable" })
|
|
#expect(fable.title == "Fable only")
|
|
#expect(fable.window.usedPercent == 68)
|
|
#expect(fable.window.resetDescription == "Reset Jul 10 at 2:59am (Europe/Prague)")
|
|
let example = try #require(
|
|
snapshot.extraRateWindows.first { $0.id == "claude-weekly-scoped-example-model" })
|
|
#expect(example.title == "Example Model only")
|
|
#expect(example.window.usedPercent == 12)
|
|
#expect(example.window.resetDescription == "Resets Jul 10 at 2:59am (Europe/Prague)")
|
|
#expect(snapshot.opus == nil)
|
|
}
|
|
|
|
@Test
|
|
func `scoped weekly panel does not become all models weekly usage`() throws {
|
|
let cliUsage = """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (Fable)
|
|
68% used
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
|
|
#expect(snapshot.weeklyPercentLeft == nil)
|
|
#expect(snapshot.secondaryResetDescription == nil)
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Fable only"])
|
|
}
|
|
|
|
@Test
|
|
func `compact scoped weekly label is parsed`() throws {
|
|
let snapshot = try ClaudeStatusProbe.parse(text: """
|
|
Current session
|
|
9% used
|
|
|
|
Currentweek(Fable)
|
|
68% used
|
|
""")
|
|
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Fable only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 68)
|
|
}
|
|
|
|
@Test
|
|
func `overlapping scoped model names do not cross panel boundaries`() throws {
|
|
let snapshot = try ClaudeStatusProbe.parse(text: """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (Example Model)
|
|
rendering
|
|
|
|
Current week (Example Model Plus)
|
|
42% used
|
|
""")
|
|
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Example Model Plus only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 42)
|
|
}
|
|
|
|
@Test
|
|
func `informational Sonnet prose does not duplicate a scoped limit`() throws {
|
|
let snapshot = try ClaudeStatusProbe.parse(text: """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
20% used
|
|
|
|
Current week (Fable)
|
|
42% used
|
|
|
|
Sonnet now has its own limit.
|
|
""")
|
|
|
|
#expect(snapshot.opusPercentLeft == nil)
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Fable only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 42)
|
|
}
|
|
|
|
@Test
|
|
func `Sonnet prefixed scoped model does not become legacy quota`() throws {
|
|
let snapshot = try ClaudeStatusProbe.parse(text: """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
20% used
|
|
|
|
Current week (Sonnet Test Variant)
|
|
42% used
|
|
""")
|
|
|
|
#expect(snapshot.opusPercentLeft == nil)
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Sonnet Test Variant only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 42)
|
|
}
|
|
|
|
@Test
|
|
func `later complete scoped panel replaces partial redraw`() throws {
|
|
let spacer = Array(repeating: "rendering", count: 14).joined(separator: "\n")
|
|
let cliUsage = """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
67% used
|
|
|
|
Current week (Fable)
|
|
\(spacer)
|
|
|
|
Current week (Fable)
|
|
70% used
|
|
Reset Jul 10 at 2:59am (Europe/Prague)
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
let fable = try #require(snapshot.extraRateWindows.first)
|
|
|
|
#expect(snapshot.extraRateWindows.count == 1)
|
|
#expect(fable.window.usedPercent == 70)
|
|
#expect(fable.window.resetDescription == "Reset Jul 10 at 2:59am (Europe/Prague)")
|
|
}
|
|
|
|
@Test
|
|
func `incomplete scoped panel stops at session redraw`() throws {
|
|
let cliUsage = """
|
|
Current week (Fable)
|
|
rendering
|
|
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
20% used
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
|
|
#expect(snapshot.sessionPercentLeft == 91)
|
|
#expect(snapshot.weeklyPercentLeft == 80)
|
|
#expect(snapshot.extraRateWindows.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func `incomplete all models panel does not consume scoped percentage`() throws {
|
|
let cliUsage = """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
rendering
|
|
|
|
Current week (Fable)
|
|
42% used
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
|
|
#expect(snapshot.weeklyPercentLeft == nil)
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Fable only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 42)
|
|
}
|
|
|
|
@Test
|
|
func `incomplete Opus panel does not consume prefixed scoped percentage`() throws {
|
|
let cliUsage = """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
20% used
|
|
|
|
Current week (Opus)
|
|
rendering
|
|
|
|
Current week (Opus Test Variant)
|
|
42% used
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
|
|
#expect(snapshot.opusPercentLeft == nil)
|
|
#expect(snapshot.extraRateWindows.map(\.title) == ["Opus Test Variant only"])
|
|
#expect(snapshot.extraRateWindows.first?.window.usedPercent == 42)
|
|
}
|
|
|
|
@Test
|
|
func `later complete scoped panel replaces earlier complete value`() throws {
|
|
let cliUsage = """
|
|
Current session
|
|
9% used
|
|
|
|
Current week (all models)
|
|
67% used
|
|
|
|
Current week (Fable)
|
|
20% used
|
|
|
|
Current week (Fable)
|
|
70% used
|
|
"""
|
|
|
|
let snapshot = try ClaudeStatusProbe.parse(text: cliUsage)
|
|
let fable = try #require(snapshot.extraRateWindows.first)
|
|
|
|
#expect(snapshot.extraRateWindows.count == 1)
|
|
#expect(fable.window.usedPercent == 70)
|
|
}
|
|
|
|
@Test
|
|
func `web extra windows merge with CLI scoped weekly limits`() throws {
|
|
let fable = NamedRateWindow(
|
|
id: "claude-weekly-scoped-fable",
|
|
title: "Fable only",
|
|
window: RateWindow(
|
|
usedPercent: 68,
|
|
windowMinutes: 7 * 24 * 60,
|
|
resetsAt: nil,
|
|
resetDescription: "Resets Jul 10 at 2:59am (Europe/Prague)"))
|
|
let webFable = try #require(ClaudeScopedWeeklyLimitMapper.extraRateWindows(from: [
|
|
ClaudeScopedWeeklyLimitMapper.Limit(
|
|
kind: "weekly_scoped",
|
|
group: "weekly",
|
|
percent: 70,
|
|
resetsAt: nil,
|
|
modelID: "test-only-fable-id",
|
|
modelName: "Fable"),
|
|
]).first)
|
|
let routines = NamedRateWindow(
|
|
id: "claude-routines",
|
|
title: "Daily Routines",
|
|
window: RateWindow(
|
|
usedPercent: 11,
|
|
windowMinutes: 7 * 24 * 60,
|
|
resetsAt: nil,
|
|
resetDescription: nil))
|
|
|
|
let merged = ClaudeUsageFetcher._mergeExtraRateWindowsForTesting(
|
|
primary: [fable],
|
|
web: [webFable, routines])
|
|
|
|
#expect(merged.map(\.id) == ["claude-weekly-scoped-fable", "claude-routines"])
|
|
#expect(webFable.id == "claude-weekly-scoped-test-only-fable-id")
|
|
#expect(merged.first?.window.usedPercent == 68)
|
|
#expect(merged.last?.title == "Daily Routines")
|
|
}
|
|
|
|
@Test
|
|
func `same title web limits keep distinct stable IDs`() {
|
|
let webLimits = ["first-id", "second-id"].map { id in
|
|
NamedRateWindow(
|
|
id: "claude-weekly-scoped-\(id)",
|
|
title: "Example Model only",
|
|
window: RateWindow(
|
|
usedPercent: 25,
|
|
windowMinutes: 7 * 24 * 60,
|
|
resetsAt: nil,
|
|
resetDescription: nil))
|
|
}
|
|
|
|
let merged = ClaudeUsageFetcher._mergeExtraRateWindowsForTesting(
|
|
primary: [],
|
|
web: webLimits)
|
|
|
|
#expect(merged.map(\.id) == [
|
|
"claude-weekly-scoped-first-id",
|
|
"claude-weekly-scoped-second-id",
|
|
])
|
|
}
|
|
|
|
@Test
|
|
func `ambiguous same title web limits survive CLI merge`() {
|
|
let cli = NamedRateWindow(
|
|
id: "claude-weekly-scoped-example-model",
|
|
title: "Example Model only",
|
|
window: RateWindow(
|
|
usedPercent: 20,
|
|
windowMinutes: 7 * 24 * 60,
|
|
resetsAt: nil,
|
|
resetDescription: nil))
|
|
let webLimits = ["first-id", "second-id"].map { id in
|
|
NamedRateWindow(
|
|
id: "claude-weekly-scoped-\(id)",
|
|
title: "Example Model only",
|
|
window: RateWindow(
|
|
usedPercent: 25,
|
|
windowMinutes: 7 * 24 * 60,
|
|
resetsAt: nil,
|
|
resetDescription: nil))
|
|
}
|
|
|
|
let merged = ClaudeUsageFetcher._mergeExtraRateWindowsForTesting(
|
|
primary: [cli],
|
|
web: webLimits)
|
|
|
|
#expect(merged.map(\.id) == [
|
|
"claude-weekly-scoped-example-model",
|
|
"claude-weekly-scoped-first-id",
|
|
"claude-weekly-scoped-second-id",
|
|
])
|
|
}
|
|
}
|