1use std::path::{Path, PathBuf};
2
3use serde::{Deserialize, Serialize};
4
5use crate::TokuError;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(default)]
10pub struct TokuConfig {
11 pub default_format: String,
13 pub color: String,
15 pub metadata_source: String,
17}
18
19impl Default for TokuConfig {
20 fn default() -> Self {
21 Self {
22 default_format: "table".to_string(),
23 color: "auto".to_string(),
24 metadata_source: "openlibrary".to_string(),
25 }
26 }
27}
28
29const CONFIG_FILENAME: &str = "config.toml";
30
31impl TokuConfig {
32 pub fn config_path(data_dir: &Path) -> PathBuf {
34 data_dir.join(CONFIG_FILENAME)
35 }
36
37 pub fn load(data_dir: &Path) -> Result<Self, TokuError> {
40 let path = Self::config_path(data_dir);
41 if !path.exists() {
42 return Ok(Self::default());
43 }
44 let contents =
45 std::fs::read_to_string(&path).map_err(|e| TokuError::Config(e.to_string()))?;
46 let config: TokuConfig =
47 toml::from_str(&contents).map_err(|e| TokuError::Config(e.to_string()))?;
48 Ok(config)
49 }
50
51 pub fn save(&self, data_dir: &Path) -> Result<(), TokuError> {
54 std::fs::create_dir_all(data_dir).map_err(|e| TokuError::Config(e.to_string()))?;
55 let contents =
56 toml::to_string_pretty(self).map_err(|e| TokuError::Config(e.to_string()))?;
57 let path = Self::config_path(data_dir);
58 std::fs::write(&path, contents).map_err(|e| TokuError::Config(e.to_string()))?;
59 Ok(())
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn default_has_sensible_values() {
69 let cfg = TokuConfig::default();
70 assert_eq!(cfg.default_format, "table");
71 assert_eq!(cfg.color, "auto");
72 assert_eq!(cfg.metadata_source, "openlibrary");
73 }
74
75 #[test]
76 fn load_missing_file_returns_defaults() {
77 let dir = std::env::temp_dir().join("toku-test-config-missing");
78 let _ = std::fs::remove_file(TokuConfig::config_path(&dir));
80 let cfg = TokuConfig::load(&dir).expect("load should succeed");
81 assert_eq!(cfg, TokuConfig::default());
82 }
83
84 #[test]
85 fn save_and_load_roundtrip() {
86 let dir = std::env::temp_dir().join("toku-test-config-roundtrip");
87 let _ = std::fs::remove_dir_all(&dir);
88
89 let cfg = TokuConfig {
90 default_format: "json".to_string(),
91 color: "never".to_string(),
92 metadata_source: "google".to_string(),
93 };
94 cfg.save(&dir).expect("save should succeed");
95
96 let loaded = TokuConfig::load(&dir).expect("load should succeed");
97 assert_eq!(loaded, cfg);
98
99 let _ = std::fs::remove_dir_all(&dir);
101 }
102}