use pretty_assertions::assert_eq;
use super::parse_usage_screen;
const NOW: i64 = 1_700_000_000;
fn window_map(text: &str) -> Vec<(String, Option<f64>, bool)> {
let state = parse_usage_screen(text, NOW).expect("parsed");
state
.sorted_windows()
.into_iter()
.map(|window| {
(
window.info.window_key().to_owned(),
window.info.utilization,
window.info.resets_at.is_some(),
)
})
.collect()
}
#[test]
fn typical_usage_panel_maps_session_week_and_extra() {
let text = r#"
Settings: Status Config [Usage]
Current session
████████░░░░░░░░ 1% used
Resets in 3h
Current week (all models)
░░░░░░░░░░░░░░░░ 0% used
Resets in 2d
Current week (Sonnet only)
░░░░░░░░░░░░░░░░ 0% used
Resets in 3h
Extra usage
██░░░░░░░░░░░░░░ 15% used
$77.33 / $500.00 spent · Resets in 14d
"#;
assert_eq!(
window_map(text),
vec![
("five_hour".into(), Some(0.01), true),
("seven_day".into(), Some(0.0), true),
("seven_day_sonnet".into(), Some(0.0), true),
("extra_usage".into(), Some(0.15), true),
]
);
}
#[test]
fn relative_reset_in_hours_and_minutes_becomes_unix() {
let text = "Current session\n10% used\nResets in 1h 30m\n";
let state = parse_usage_screen(text, NOW).expect("parsed");
let info = &state.sorted_windows()[0].info;
assert_eq!(info.resets_at, Some(NOW + 5_400));
}
#[test]
fn dated_reset_lands_on_the_named_day() {
use chrono::{Datelike, TimeZone, Timelike};
let now = chrono::Local.timestamp_opt(NOW, 0).unwrap();
let target = now + chrono::TimeDelta::days(4);
let text = format!(
"Current week (all models)\n26% used\nResets Sep {}, 8am (America/Los_Angeles)\n",
target.day()
);
let state = parse_usage_screen(&text, NOW).expect("parsed");
let resets_at = state.sorted_windows()[0].info.resets_at.expect("resets_at");
let resolved = chrono::Local.timestamp_opt(resets_at, 0).unwrap();
assert_eq!(
(resolved.day(), resolved.hour(), resolved.minute()),
(target.day(), 8, 0)
);
}
#[test]
fn clock_only_reset_stays_within_a_day() {
let text = "Current session\n29% used\nResets 5:30am (America/Los_Angeles)\n";
let state = parse_usage_screen(text, NOW).expect("parsed");
let resets_at = state.sorted_windows()[0].info.resets_at.expect("resets_at");
let delta = resets_at - NOW;
assert!((0..=86_400).contains(&delta), "{delta}");
}
#[test]
fn tz_label_digits_are_not_a_day_of_month() {
const EARLY_IN_MONTH: i64 = 1_698_926_400; for label in ["(UTC+10)", "(EST5EDT)", "(GMT-5)"] {
let text = format!("Current session\n29% used\nResets 5:30am {label}\n");
let state = parse_usage_screen(&text, EARLY_IN_MONTH).expect("parsed");
let resets_at = state.sorted_windows()[0].info.resets_at.expect("resets_at");
let delta = resets_at - EARLY_IN_MONTH;
assert!((0..=86_400).contains(&delta), "{label}: {delta}");
}
}
#[test]
fn header_without_percent_is_skipped() {
let text = "Current session\nsome random text\nmore random text\n";
assert!(parse_usage_screen(text, NOW).is_none());
}
#[test]
fn incidental_percent_is_not_window_used() {
let compact = "Current session\nauto-compact at 80%\n10% used\nResets in 1h\n";
assert_eq!(
window_map(compact),
vec![("five_hour".into(), Some(0.10), true)]
);
let only_bare = "Current session\nauto-compact at 80%\nResets in 1h\n";
assert!(parse_usage_screen(only_bare, NOW).is_none());
}
#[test]
fn box_drawing_and_leading_whitespace_are_stripped() {
let text = "│ Current session │\n│ ██░░ 10% used │\n│ Resets in 5m │\n";
assert_eq!(
window_map(text),
vec![("five_hour".into(), Some(0.10), true)]
);
}
#[test]
fn fable_week_parses_from_live_layouts() {
let same_line = "Current session 0%used Current week (all models) 18%used Current week (Claude Fable) 33%used\n";
assert_eq!(
window_map(same_line)
.into_iter()
.map(|(key, used, _)| (key, used))
.collect::<Vec<_>>(),
vec![
("five_hour".into(), Some(0.0)),
("seven_day".into(), Some(0.18)),
("seven_day_fable".into(), Some(0.33)),
]
);
let columns = "\
Current session Current week (all models) Current week (Fable)
0%used 18%used 33%used
Resets in 3h Resets in 2d Resets in 2d
";
assert_eq!(
window_map(columns)
.into_iter()
.map(|(key, used, _)| (key, used))
.collect::<Vec<_>>(),
vec![
("five_hour".into(), Some(0.0)),
("seven_day".into(), Some(0.18)),
("seven_day_fable".into(), Some(0.33)),
]
);
}
#[test]
fn named_window_keys_include_headers_without_percent() {
let keys = super::named_window_keys(
"Current session\n0%used\nCurrent week (all models)\nCurrent week (Fable)\n",
);
assert_eq!(keys, vec!["five_hour", "seven_day", "seven_day_fable"]);
}