use super::config::{config_path, default_for, set, Config};
use crate::cli::{Binary, ConfigSet};
fn cs(interval: Option<u64>, width: Option<usize>) -> ConfigSet {
ConfigSet {
interval,
width,
..Default::default()
}
}
fn temp_dir(name: &str) -> std::path::PathBuf {
let d = std::env::temp_dir().join(format!("cmduse-test-{name}-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&d);
std::fs::create_dir_all(&d).unwrap();
d
}
#[test]
fn config_defaults_when_missing() {
let d = Config::default();
assert_eq!(d.interval_secs, 5);
assert_eq!(d.bar_width, 20);
assert!(d.burst_enabled, "spend-bursts default ON");
assert_eq!(d.burst_samples, 40);
assert!(d.check_updates, "update check default ON");
assert!(d.dismissed_update.is_none());
}
#[test]
fn ocuse_default_differs_only_in_interval_and_statusline() {
let c = default_for(Binary::Cmduse);
let o = default_for(Binary::Ocuse);
assert_ne!(c.statusline_template, o.statusline_template);
assert_eq!(c.interval_secs, 5);
assert_eq!(o.interval_secs, 10);
let c2 = Config {
statusline_template: o.statusline_template.clone(),
..c
};
assert_eq!(c2.bar_width, o.bar_width);
assert_eq!(c2.burst_enabled, o.burst_enabled);
assert_eq!(c2.burst_samples, o.burst_samples);
assert_eq!(c2.notify_on_cap, o.notify_on_cap);
assert_eq!(c2.statusline_colors, o.statusline_colors);
assert_eq!(c2.statusline_ascii, o.statusline_ascii);
assert_eq!(c2.check_updates, o.check_updates);
assert_eq!(c2.dismissed_update, o.dismissed_update);
}
#[test]
fn config_paths_differ_per_binary() {
let c = config_path(Binary::Cmduse);
let o = config_path(Binary::Ocuse);
assert_ne!(c, o);
assert!(c.ends_with("cmd-usage/config.json"));
assert!(o.ends_with("ocuse/config.json"));
}
#[test]
fn config_parse_valid() {
let c: Config = serde_json::from_str(r#"{"interval_secs": 30, "bar_width": 40}"#).unwrap();
assert_eq!(c.interval_secs, 30);
assert_eq!(c.bar_width, 40);
}
#[test]
fn config_parse_partial_uses_defaults() {
let c: Config = serde_json::from_str(r#"{"interval_secs": 30}"#).unwrap();
assert_eq!(c.interval_secs, 30);
assert_eq!(c.bar_width, 20); assert!(c.burst_enabled);
let c: Config =
serde_json::from_str(r#"{"burst_enabled": false, "burst_samples": 20}"#).unwrap();
assert!(!c.burst_enabled);
assert_eq!(c.burst_samples, 20);
assert_eq!(c.interval_secs, 5);
}
#[test]
fn config_parse_garbage_rejected() {
assert!(serde_json::from_str::<Config>("not json").is_err());
assert!(serde_json::from_str::<Config>("{\"interval_secs\": \"abc\"}").is_err());
}
#[test]
fn config_set_validates_and_persists() {
let dir = temp_dir("set");
let path = dir.join("cmd-usage/config.json");
std::env::set_var("XDG_CONFIG_HOME", &dir);
set(Binary::Cmduse, &cs(Some(15), Some(30))).unwrap();
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(c.interval_secs, 15);
assert_eq!(c.bar_width, 30);
assert!(c.burst_enabled);
set(Binary::Cmduse, &cs(Some(60), None)).unwrap();
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(c.interval_secs, 60);
assert_eq!(c.bar_width, 30);
set(
Binary::Cmduse,
&ConfigSet {
burst_on: Some(false),
notify: Some(false),
..Default::default()
},
)
.unwrap();
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert!(!c.burst_enabled);
assert!(!c.notify_on_cap);
set(
Binary::Cmduse,
&ConfigSet {
update_check: Some(false),
dismissed_update: Some("0.6.8".into()),
..Default::default()
},
)
.unwrap();
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert!(!c.check_updates);
assert_eq!(c.dismissed_update.as_deref(), Some("0.6.8"));
super::config::set_dismissed(Binary::Cmduse, "9.9.9").unwrap();
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(c.dismissed_update.as_deref(), Some("9.9.9"));
assert!(!c.check_updates);
let opath = dir.join("ocuse/config.json");
set(Binary::Ocuse, &cs(Some(20), None)).unwrap();
let oc: Config = serde_json::from_str(&std::fs::read_to_string(&opath).unwrap()).unwrap();
assert_eq!(oc.interval_secs, 20);
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(c.interval_secs, 60, "cmduse config untouched by ocuse set");
assert!(set(Binary::Cmduse, &cs(Some(0), None)).is_err());
assert!(set(Binary::Cmduse, &cs(Some(86_401), None)).is_err());
assert!(set(Binary::Cmduse, &cs(None, Some(4))).is_err()); assert!(set(Binary::Cmduse, &cs(None, Some(201))).is_err()); assert!(set(
Binary::Cmduse,
&ConfigSet {
bursts: Some(3),
..Default::default()
}
)
.is_err()); assert!(set(
Binary::Cmduse,
&ConfigSet {
bursts: Some(241),
..Default::default()
}
)
.is_err()); assert!(set(Binary::Cmduse, &ConfigSet::default()).is_err());
let c: Config = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(c.interval_secs, 60);
assert!(!c.burst_enabled);
assert!(!c.notify_on_cap);
let _ = std::fs::remove_dir_all(&dir);
std::env::remove_var("XDG_CONFIG_HOME");
}