366 lines
11 KiB
Swift
366 lines
11 KiB
Swift
import CodexBarCore
|
|
import Foundation
|
|
import Testing
|
|
@testable import CodexBar
|
|
|
|
struct MenuBarResetTimeDisplayTests {
|
|
@Test
|
|
func `reset time mode formats the selected window reset`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let resetsAt = now.addingTimeInterval(2 * 3600)
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: resetsAt,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true,
|
|
resetTimeDisplayStyle: .absolute,
|
|
now: now)
|
|
|
|
#expect(text == "↻ \(UsageFormatter.resetDescription(from: resetsAt, now: now))")
|
|
}
|
|
|
|
@Test
|
|
func `reset time mode uses countdown preference`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let resetsAt = now.addingTimeInterval(2 * 3600 + 15 * 60)
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: resetsAt,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true,
|
|
resetTimeDisplayStyle: .countdown,
|
|
now: now)
|
|
|
|
#expect(text == "↻ in 2h 15m")
|
|
}
|
|
|
|
@Test
|
|
func `reset time mode falls back to used percent without reset metadata`() {
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true)
|
|
|
|
#expect(text == "42%")
|
|
}
|
|
|
|
@Test
|
|
func `reset time mode uses text reset metadata`() {
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: "in 2h 15m")
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true)
|
|
|
|
#expect(text == "↻ in 2h 15m")
|
|
}
|
|
|
|
@Test
|
|
func `reset time mode surfaces daily reset metadata`() {
|
|
let window = RateWindow(
|
|
usedPercent: 39,
|
|
windowMinutes: 1440,
|
|
resetsAt: nil,
|
|
resetDescription: "resets daily")
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true)
|
|
|
|
#expect(text == "↻ resets daily")
|
|
}
|
|
|
|
@Test(arguments: [
|
|
"Resets in 2h",
|
|
"tomorrow, 3:00 PM",
|
|
"next week",
|
|
"expires in 4d",
|
|
])
|
|
func `reset time mode accepts reset timing phrases`(_ description: String) {
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: description)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true)
|
|
|
|
#expect(text == "↻ \(description)")
|
|
}
|
|
|
|
@Test(arguments: [
|
|
"250/1000 requests",
|
|
"160 requests",
|
|
"5 hours window",
|
|
"$10.00 available",
|
|
])
|
|
func `reset time mode rejects non-reset provider summaries`(_ description: String) {
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: description)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: true)
|
|
|
|
#expect(text == "42%")
|
|
}
|
|
|
|
@Test
|
|
func `reset time mode falls back to remaining percent without reset metadata`() {
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: false)
|
|
|
|
#expect(text == "58%")
|
|
}
|
|
|
|
@Test(arguments: [MenuBarDisplayMode.percent, .pace, .both])
|
|
func `smart reset shows countdown when the quota is exhausted`(_ mode: MenuBarDisplayMode) {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(2 * 3600 + 15 * 60),
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: mode,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
resetTimeDisplayStyle: .countdown,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "↻ in 2h 15m")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset honors the absolute clock preference`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let resetsAt = now.addingTimeInterval(2 * 3600)
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: resetsAt,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
resetTimeDisplayStyle: .absolute,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "↻ \(UsageFormatter.resetDescription(from: resetsAt, now: now))")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset leaves a non-exhausted quota untouched`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(3600),
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "58%")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset disabled keeps the exhausted percent`() {
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: Date(timeIntervalSince1970: 1_800_000_000),
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false)
|
|
|
|
#expect(text == "0%")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset falls back to percent once the reset has elapsed`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
// Exhausted window whose reset moment is already in the past (e.g. snapshot lingering at 100%
|
|
// before the next provider refresh). Showing "↻ now" here would be stale and could stick.
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(-60),
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
resetTimeDisplayStyle: .countdown,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "0%")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset ignores textual reset metadata without a concrete reset time`() {
|
|
// Provider supplies only a textual resetDescription (no resetsAt). The smart option can't hand
|
|
// that to the refresh scheduler, so it keeps the percent rather than freezing on "↻ in 2h".
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: "in 2h")
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
showsResetTimeWhenExhausted: true)
|
|
|
|
#expect(text == "0%")
|
|
// Reset-time mode still surfaces the textual metadata (unchanged behavior).
|
|
let resetTimeText = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: false)
|
|
#expect(resetTimeText == "↻ in 2h")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset falls back to percent without reset metadata`() {
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .percent,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
showsResetTimeWhenExhausted: true)
|
|
|
|
#expect(text == "0%")
|
|
}
|
|
|
|
@Test(arguments: [MenuBarDisplayMode.pace, .both])
|
|
func `smart reset keeps exhausted percent when pace exists but reset is unusable`(_ mode: MenuBarDisplayMode) {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let window = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(-60),
|
|
resetDescription: nil)
|
|
let pace = UsagePace(
|
|
stage: .ahead,
|
|
deltaPercent: 12,
|
|
expectedUsedPercent: 40,
|
|
actualUsedPercent: 52,
|
|
etaSeconds: nil,
|
|
willLastToReset: true)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: mode,
|
|
percentWindow: window,
|
|
pace: pace,
|
|
showUsed: false,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "0%")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset does not alter reset time mode`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let resetsAt = now.addingTimeInterval(3600)
|
|
let window = RateWindow(
|
|
usedPercent: 42,
|
|
windowMinutes: 300,
|
|
resetsAt: resetsAt,
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.displayText(
|
|
mode: .resetTime,
|
|
percentWindow: window,
|
|
showUsed: false,
|
|
resetTimeDisplayStyle: .countdown,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "↻ in 1h")
|
|
}
|
|
|
|
@Test
|
|
func `smart reset replaces only the exhausted lane in combined text`() {
|
|
let now = Date(timeIntervalSince1970: 1_800_000_000)
|
|
let session = RateWindow(
|
|
usedPercent: 100,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(2 * 3600 + 15 * 60),
|
|
resetDescription: nil)
|
|
let weekly = RateWindow(
|
|
usedPercent: 55,
|
|
windowMinutes: 10080,
|
|
resetsAt: now.addingTimeInterval(3 * 86400),
|
|
resetDescription: nil)
|
|
|
|
let text = MenuBarDisplayText.combinedSessionWeeklyPercentText(
|
|
sessionWindow: session,
|
|
weeklyWindow: weekly,
|
|
showUsed: false,
|
|
resetTimeDisplayStyle: .countdown,
|
|
showsResetTimeWhenExhausted: true,
|
|
now: now)
|
|
|
|
#expect(text == "5h ↻ in 2h 15m · W 45%")
|
|
}
|
|
}
|