use std::path::PathBuf;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use crate::display::DisplayPreference;
use crate::fs_util::atomic_write;
#[derive(Serialize, Deserialize, Default)]
pub struct Config {
#[serde(default)]
pub display_mode: DisplayPreference,
}
fn config_path() -> Result<PathBuf> {
let dir = dirs::config_dir()
.ok_or_else(|| anyhow::anyhow!("could not determine config directory"))?
.join("aip");
Ok(dir.join("config.json"))
}
impl Config {
pub fn load() -> Self {
config_path()
.ok()
.and_then(|p| std::fs::read_to_string(p).ok())
.and_then(|s| serde_json::from_str(&s).ok())
.unwrap_or_default()
}
pub fn save(&self) -> Result<()> {
let path = config_path()?;
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let json = serde_json::to_string_pretty(self)?;
atomic_write(&path, &json)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_config_has_default_display_mode() {
let config = Config::default();
assert_eq!(config.display_mode, DisplayPreference::Default);
}
#[test]
fn round_trip_serialization() {
let config = Config {
display_mode: DisplayPreference::Left,
};
let json = serde_json::to_string(&config).unwrap();
let loaded: Config = serde_json::from_str(&json).unwrap();
assert_eq!(loaded.display_mode, DisplayPreference::Left);
}
#[test]
fn deserialize_with_missing_field_uses_default() {
let config: Config = serde_json::from_str("{}").unwrap();
assert_eq!(config.display_mode, DisplayPreference::Default);
}
#[test]
fn save_and_load_via_file() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("aip").join("config.json");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
let config = Config {
display_mode: DisplayPreference::Used,
};
let json = serde_json::to_string_pretty(&config).unwrap();
atomic_write(&path, &json).unwrap();
let loaded: Config =
serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
assert_eq!(loaded.display_mode, DisplayPreference::Used);
}
}