1use std::path::PathBuf;
2
3use crate::model::Config;
4
5#[derive(Debug, thiserror::Error)]
6pub enum ConfigError {
7 #[error("TOML parse error: {0}")]
8 Parse(#[from] toml::de::Error),
9 #[error("IO error: {0}")]
10 Io(#[from] std::io::Error),
11 #[error("cannot determine config directory")]
12 NoConfigDir,
13}
14
15pub fn parse_config(s: &str) -> Result<Config, ConfigError> {
17 let config: Config = toml::from_str(s)?;
18 Ok(config)
19}
20
21pub fn default_config_path() -> Result<PathBuf, ConfigError> {
24 if let Ok(p) = std::env::var("RUNEX_CONFIG") {
25 return Ok(PathBuf::from(p));
26 }
27 let dir = dirs::config_dir().ok_or(ConfigError::NoConfigDir)?;
28 Ok(dir.join("runex").join("config.toml"))
29}
30
31pub fn load_config(path: &std::path::Path) -> Result<Config, ConfigError> {
33 let content = std::fs::read_to_string(path)?;
34 parse_config(&content)
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn parse_minimal_toml() {
43 let toml = r#"
44version = 1
45
46[[abbr]]
47key = "gcm"
48expand = "git commit -m"
49"#;
50 let config = parse_config(toml).unwrap();
51 assert_eq!(config.version, 1);
52 assert_eq!(config.abbr.len(), 1);
53 assert_eq!(config.abbr[0].key, "gcm");
54 assert_eq!(config.abbr[0].expand, "git commit -m");
55 }
56
57 #[test]
58 fn parse_with_when_command_exists() {
59 let toml = r#"
60version = 1
61
62[[abbr]]
63key = "ls"
64expand = "lsd"
65when_command_exists = ["lsd"]
66"#;
67 let config = parse_config(toml).unwrap();
68 assert_eq!(
69 config.abbr[0].when_command_exists,
70 Some(vec!["lsd".to_string()])
71 );
72 }
73
74 #[test]
75 fn parse_missing_version_is_err() {
76 let toml = r#"
77[[abbr]]
78key = "gcm"
79expand = "git commit -m"
80"#;
81 assert!(parse_config(toml).is_err());
82 }
83
84 #[test]
85 fn parse_empty_abbr_list() {
86 let toml = "version = 1\n";
87 let config = parse_config(toml).unwrap();
88 assert!(config.abbr.is_empty());
89 }
90
91 #[test]
92 fn load_config_from_file() {
93 let dir = std::env::temp_dir().join("runex_test_load");
94 std::fs::create_dir_all(&dir).unwrap();
95 let path = dir.join("config.toml");
96 std::fs::write(
97 &path,
98 r#"
99version = 1
100
101[[abbr]]
102key = "gcm"
103expand = "git commit -m"
104"#,
105 )
106 .unwrap();
107
108 let config = load_config(&path).unwrap();
109 assert_eq!(config.version, 1);
110 assert_eq!(config.abbr[0].key, "gcm");
111
112 std::fs::remove_dir_all(&dir).ok();
113 }
114
115 #[test]
116 fn default_config_path_env_override() {
117 std::env::set_var("RUNEX_CONFIG", "/tmp/custom.toml");
118 let path = default_config_path().unwrap();
119 assert_eq!(path, PathBuf::from("/tmp/custom.toml"));
120 std::env::remove_var("RUNEX_CONFIG");
121 }
122}