53b4f60da1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
7.2 KiB
Swift
134 lines
7.2 KiB
Swift
import Foundation
|
|
|
|
@main
|
|
enum ClaudePlanGaugeTests {
|
|
|
|
static var failures = 0
|
|
|
|
static func check(_ label: String, _ got: String, _ expected: String) {
|
|
if got == expected {
|
|
print(" ✓ \(label)")
|
|
} else {
|
|
print(" ✗ \(label)")
|
|
print(" got: \(got.debugDescription)")
|
|
print(" expected: \(expected.debugDescription)")
|
|
failures += 1
|
|
}
|
|
}
|
|
|
|
static func checkTrue(_ label: String, _ value: Bool) {
|
|
if value { print(" ✓ \(label)") }
|
|
else { print(" ✗ \(label)"); failures += 1 }
|
|
}
|
|
|
|
static func main() {
|
|
let futureEpoch: Double = Date().timeIntervalSince1970 + 7200 // 2 hours from now
|
|
let pastEpoch: Double = Date().timeIntervalSince1970 - 100 // already passed
|
|
|
|
// ── parse ──────────────────────────────────────────────────────────────
|
|
print("ClaudePlanGauge.parse")
|
|
|
|
let full: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 23.5, "resets_at": futureEpoch],
|
|
"seven_day": ["used_percentage": 67.0, "resets_at": futureEpoch],
|
|
]]
|
|
let usage = ClaudePlanGauge.parse(payload: full)
|
|
checkTrue("parse full payload → non-nil", usage != nil)
|
|
checkTrue("five_hour usedPct 23.5", usage?.fiveHour?.usedPct == 23.5)
|
|
checkTrue("seven_day usedPct 67.0", usage?.sevenDay?.usedPct == 67.0)
|
|
|
|
// Missing rate_limits → nil
|
|
checkTrue("missing rate_limits → nil", ClaudePlanGauge.parse(payload: [:]) == nil)
|
|
|
|
// Absurd pct (>200) → nil window (150 is now clamped to 100)
|
|
let badPct: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 250.0, "resets_at": futureEpoch],
|
|
]]
|
|
let badUsage = ClaudePlanGauge.parse(payload: badPct)
|
|
checkTrue("absurd pct (250) → nil window", badUsage?.fiveHour == nil)
|
|
|
|
// pct 150 → clamped to 100 (not rejected)
|
|
let clampPct: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 150.0, "resets_at": futureEpoch],
|
|
]]
|
|
let clampUsage = ClaudePlanGauge.parse(payload: clampPct)
|
|
checkTrue("pct 150 → clamped to 100", clampUsage?.fiveHour?.usedPct == 100.0)
|
|
|
|
// pct 201 → rejected
|
|
let tooBig: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 201.0, "resets_at": futureEpoch],
|
|
]]
|
|
checkTrue("pct 201 → nil window", ClaudePlanGauge.parse(payload: tooBig)?.fiveHour == nil)
|
|
|
|
// resets_at > 400 days → rejected
|
|
let farFuture = Date().timeIntervalSince1970 + 401 * 86400
|
|
let msEpoch: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 50.0, "resets_at": farFuture],
|
|
]]
|
|
checkTrue("resets_at > 400d → nil window", ClaudePlanGauge.parse(payload: msEpoch)?.fiveHour == nil)
|
|
|
|
// Negative pct → nil window
|
|
let negPct: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": -5.0, "resets_at": futureEpoch],
|
|
]]
|
|
checkTrue("negative pct → nil window", ClaudePlanGauge.parse(payload: negPct)?.fiveHour == nil)
|
|
|
|
// Int pct accepted
|
|
let intPct: [String: Any] = ["rate_limits": [
|
|
"five_hour": ["used_percentage": 42, "resets_at": Int(futureEpoch)],
|
|
]]
|
|
let intUsage = ClaudePlanGauge.parse(payload: intPct)
|
|
checkTrue("Int pct parsed", intUsage?.fiveHour?.usedPct == 42.0)
|
|
|
|
// ── effectivePct (expired window) ─────────────────────────────────────
|
|
print("ClaudePlanGauge.effectivePct")
|
|
|
|
let expiredWindow = PlanWindow(usedPct: 80, resetsAt: Date(timeIntervalSince1970: pastEpoch))
|
|
let futureWindow = PlanWindow(usedPct: 80, resetsAt: Date(timeIntervalSince1970: futureEpoch))
|
|
checkTrue("expired window → 0", ClaudePlanGauge.effectivePct(expiredWindow) == 0)
|
|
checkTrue("future window → original pct", ClaudePlanGauge.effectivePct(futureWindow) == 80)
|
|
|
|
// ── dominantPct ────────────────────────────────────────────────────────
|
|
print("ClaudePlanGauge.dominantPct")
|
|
|
|
let both = PlanUsage(fiveHour: PlanWindow(usedPct: 30, resetsAt: Date(timeIntervalSince1970: futureEpoch)),
|
|
sevenDay: PlanWindow(usedPct: 70, resetsAt: Date(timeIntervalSince1970: futureEpoch)),
|
|
updatedAt: Date())
|
|
let fhOnly = PlanUsage(fiveHour: PlanWindow(usedPct: 55, resetsAt: Date(timeIntervalSince1970: futureEpoch)),
|
|
sevenDay: nil, updatedAt: Date())
|
|
let empty = PlanUsage(fiveHour: nil, sevenDay: nil, updatedAt: Date())
|
|
|
|
checkTrue("dominant picks higher (70)", ClaudePlanGauge.dominantPct(both) == 70)
|
|
checkTrue("dominant with one window (55)", ClaudePlanGauge.dominantPct(fhOnly) == 55)
|
|
checkTrue("dominant with no windows → nil", ClaudePlanGauge.dominantPct(empty) == nil)
|
|
|
|
// ── color ──────────────────────────────────────────────────────────────
|
|
print("ClaudePlanGauge.color")
|
|
|
|
check("nil → grey", ClaudePlanGauge.color(for: nil), "#6B7079")
|
|
check("0 → green", ClaudePlanGauge.color(for: 0), "#22C55E")
|
|
check("49 → green", ClaudePlanGauge.color(for: 49), "#22C55E")
|
|
check("50 → orange", ClaudePlanGauge.color(for: 50), "#F59E0B")
|
|
check("79 → orange", ClaudePlanGauge.color(for: 79), "#F59E0B")
|
|
check("80 → red", ClaudePlanGauge.color(for: 80), "#F4505E")
|
|
check("100 → red", ClaudePlanGauge.color(for: 100), "#F4505E")
|
|
|
|
// ── pillLabel ──────────────────────────────────────────────────────────
|
|
print("ClaudePlanGauge.pillLabel")
|
|
|
|
check("nil usage → 'Claude plan'", ClaudePlanGauge.pillLabel(nil), "Claude plan")
|
|
check("no windows → 'Claude plan'", ClaudePlanGauge.pillLabel(empty), "Claude plan")
|
|
check("70 pct → 'Claude 70%'", ClaudePlanGauge.pillLabel(both), "Claude 70%")
|
|
check("55 pct → 'Claude 55%'", ClaudePlanGauge.pillLabel(fhOnly), "Claude 55%")
|
|
|
|
// ── finish ─────────────────────────────────────────────────────────────
|
|
if failures == 0 {
|
|
print("\nAll tests passed.")
|
|
exit(0)
|
|
} else {
|
|
print("\n\(failures) test(s) failed.")
|
|
exit(1)
|
|
}
|
|
}
|
|
}
|