|
| 1 | +import CodexBarCore |
| 2 | +import Foundation |
| 3 | +import Testing |
| 4 | + |
| 5 | +struct ProviderPaceCapabilityTests { |
| 6 | + private static let weeklyWindowMinutes = 7 * 24 * 60 |
| 7 | + private static let monthlyWindowSentinelMinutes = 30 * 24 * 60 |
| 8 | + |
| 9 | + @Test |
| 10 | + func `descriptor pace capabilities preserve the legacy provider mapping`() { |
| 11 | + let now = Date(timeIntervalSince1970: 1_750_000_000) |
| 12 | + let fixtures: [RateWindow] = [ |
| 13 | + Self.window(minutes: nil, resetsAt: nil), |
| 14 | + Self.window(minutes: nil, resetsAt: now.addingTimeInterval(4 * 24 * 60 * 60)), |
| 15 | + Self.window(minutes: nil, resetsAt: now.addingTimeInterval(8 * 24 * 60 * 60)), |
| 16 | + Self.window(minutes: nil, resetsAt: now.addingTimeInterval(30 * 24 * 60 * 60)), |
| 17 | + Self.window(minutes: 60, resetsAt: now.addingTimeInterval(30 * 60)), |
| 18 | + Self.window(minutes: Self.weeklyWindowMinutes, resetsAt: nil), |
| 19 | + Self.window(minutes: Self.weeklyWindowMinutes, resetsAt: now.addingTimeInterval(4 * 24 * 60 * 60)), |
| 20 | + Self.window(minutes: Self.weeklyWindowMinutes, resetsAt: now.addingTimeInterval(8 * 24 * 60 * 60)), |
| 21 | + Self.window(minutes: Self.monthlyWindowSentinelMinutes, resetsAt: nil), |
| 22 | + Self.window( |
| 23 | + minutes: Self.monthlyWindowSentinelMinutes, |
| 24 | + resetsAt: now.addingTimeInterval(20 * 24 * 60 * 60)), |
| 25 | + Self.window(minutes: 0, resetsAt: now.addingTimeInterval(60)), |
| 26 | + Self.window(minutes: Self.weeklyWindowMinutes, resetsAt: now.addingTimeInterval(-60)), |
| 27 | + ] |
| 28 | + |
| 29 | + for provider in UsageProvider.allCases { |
| 30 | + let capability = ProviderDescriptorRegistry.descriptor(for: provider).pace |
| 31 | + for window in fixtures { |
| 32 | + let actualResetWindowPace = capability.supportsResetWindowPace(window: window, now: now) |
| 33 | + let legacyResetWindowPace = Self.legacySupportsResetWindowPace( |
| 34 | + provider: provider, |
| 35 | + window: window, |
| 36 | + now: now) |
| 37 | + #expect( |
| 38 | + actualResetWindowPace == legacyResetWindowPace, |
| 39 | + "Reset-window pace changed for \(provider.rawValue), window=\(String(describing: window)).") |
| 40 | + |
| 41 | + let actualMonthlyInference = capability.usesInferredMonthlyDuration(window: window) |
| 42 | + let legacyMonthlyInference = Self.legacyUsesInferredMonthlyDuration( |
| 43 | + provider: provider, |
| 44 | + window: window) |
| 45 | + #expect( |
| 46 | + actualMonthlyInference == legacyMonthlyInference, |
| 47 | + "Monthly inference changed for \(provider.rawValue), window=\(String(describing: window)).") |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + private static func window(minutes: Int?, resetsAt: Date?) -> RateWindow { |
| 53 | + RateWindow( |
| 54 | + usedPercent: 50, |
| 55 | + windowMinutes: minutes, |
| 56 | + resetsAt: resetsAt, |
| 57 | + resetDescription: nil) |
| 58 | + } |
| 59 | + |
| 60 | + /// Snapshot of the switches removed from UsageMenuCardView.Model. |
| 61 | + private static func legacySupportsResetWindowPace( |
| 62 | + provider: UsageProvider, |
| 63 | + window: RateWindow, |
| 64 | + now: Date) -> Bool |
| 65 | + { |
| 66 | + switch provider { |
| 67 | + case .copilot: |
| 68 | + return window.resetsAt != nil |
| 69 | + case .cursor: |
| 70 | + return window.windowMinutes != nil |
| 71 | + case .grok: |
| 72 | + guard GrokProviderDescriptor.primaryLabel(window: window, now: now) == "Weekly", |
| 73 | + let resetsAt = window.resetsAt |
| 74 | + else { return false } |
| 75 | + let windowMinutes = window.windowMinutes ?? self.weeklyWindowMinutes |
| 76 | + let timeUntilReset = resetsAt.timeIntervalSince(now) |
| 77 | + return windowMinutes > 0 |
| 78 | + && timeUntilReset > 0 |
| 79 | + && timeUntilReset <= TimeInterval(windowMinutes) * 60 |
| 80 | + case .alibaba, .alibabatokenplan, .doubao, .opencodego: |
| 81 | + return window.windowMinutes == self.monthlyWindowSentinelMinutes |
| 82 | + default: |
| 83 | + return false |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + private static func legacyUsesInferredMonthlyDuration( |
| 88 | + provider: UsageProvider, |
| 89 | + window: RateWindow) -> Bool |
| 90 | + { |
| 91 | + switch provider { |
| 92 | + case .copilot: |
| 93 | + window.windowMinutes == nil |
| 94 | + case .alibaba, .alibabatokenplan, .doubao, .opencodego: |
| 95 | + window.windowMinutes == self.monthlyWindowSentinelMinutes |
| 96 | + default: |
| 97 | + false |
| 98 | + } |
| 99 | + } |
| 100 | +} |
0 commit comments