use std::{fs, path::PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct Config {
pub language: String,
pub default_width: u32,
pub default_game: String,
pub show_card_by_default: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
language: "en".to_string(),
default_width: 0,
default_game: String::new(),
show_card_by_default: false,
}
}
}
impl Config {
pub fn load() -> Self {
let Some(path) = config_path() else {
return Self::default();
};
match fs::read_to_string(&path) {
Ok(text) => match toml::from_str::<Config>(&text) {
Ok(c) => c,
Err(e) => {
eprintln!(
"zukan: warning: failed to parse {} (using defaults): {e}",
path.display()
);
Self::default()
}
},
Err(_) => Self::default(),
}
}
}
pub fn config_path() -> Option<PathBuf> {
dirs::config_dir().map(|d| d.join("zukan").join("config.toml"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_are_sane() {
let c = Config::default();
assert_eq!(c.language, "en");
assert_eq!(c.default_width, 0);
assert!(c.default_game.is_empty());
assert!(!c.show_card_by_default);
}
#[test]
fn parse_partial_uses_defaults_for_missing() {
let c: Config = toml::from_str("language = \"ja\"").unwrap();
assert_eq!(c.language, "ja");
assert_eq!(c.default_width, 0);
assert!(!c.show_card_by_default);
}
#[test]
fn parse_full_config() {
let text = r#"
language = "zh"
default_width = 32
default_game = "mhwilds"
show_card_by_default = true
"#;
let c: Config = toml::from_str(text).unwrap();
assert_eq!(c.language, "zh");
assert_eq!(c.default_width, 32);
assert_eq!(c.default_game, "mhwilds");
assert!(c.show_card_by_default);
}
#[test]
fn unknown_keys_are_ignored() {
let c: Config = toml::from_str("language = \"en\"\nfuture_key = 42").unwrap();
assert_eq!(c.language, "en");
}
#[test]
fn roundtrip_serialization() {
let c = Config {
language: "ja".into(),
default_width: 24,
default_game: "mhw".into(),
show_card_by_default: true,
};
let text = toml::to_string(&c).unwrap();
let back: Config = toml::from_str(&text).unwrap();
assert_eq!(back.language, c.language);
assert_eq!(back.default_width, c.default_width);
assert_eq!(back.default_game, c.default_game);
assert_eq!(back.show_card_by_default, c.show_card_by_default);
}
}