vespertide_loader/
config.rs1use std::fs;
2use std::path::PathBuf;
3
4use anyhow::{Context, Result};
5use vespertide_config::VespertideConfig;
6
7pub fn load_config() -> Result<VespertideConfig> {
9 let path = PathBuf::from("vespertide.json");
10 if !path.exists() {
11 anyhow::bail!("vespertide.json not found. Run 'vespertide init' first.");
12 }
13
14 let content = fs::read_to_string(&path).context("read vespertide.json")?;
15 let config: VespertideConfig =
16 serde_json::from_str(&content).context("parse vespertide.json")?;
17 Ok(config)
18}
19
20pub fn load_config_from_path(path: PathBuf) -> Result<VespertideConfig> {
22 let path = path.into_boxed_path();
23 if !path.exists() {
24 anyhow::bail!("vespertide.json not found at: {}", path.display());
25 }
26
27 let content = fs::read_to_string(&path).context("read vespertide.json")?;
28 let config: VespertideConfig =
29 serde_json::from_str(&content).context("parse vespertide.json")?;
30 Ok(config)
31}
32
33pub fn load_config_or_default(project_root: Option<PathBuf>) -> Result<VespertideConfig> {
35 let config_path = if let Some(root) = project_root {
36 root.join("vespertide.json")
37 } else {
38 PathBuf::from("vespertide.json")
39 };
40
41 if config_path.exists() {
42 load_config_from_path(config_path)
43 } else {
44 Ok(VespertideConfig::default())
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use serial_test::serial;
52 use std::fs;
53 use tempfile::tempdir;
54
55 struct CwdGuard {
56 original: PathBuf,
57 }
58
59 impl CwdGuard {
60 fn new(dir: &PathBuf) -> Self {
61 let original = std::env::current_dir().unwrap();
62 std::env::set_current_dir(dir).unwrap();
63 Self { original }
64 }
65 }
66
67 impl Drop for CwdGuard {
68 fn drop(&mut self) {
69 let _ = std::env::set_current_dir(&self.original);
70 }
71 }
72
73 fn write_config(path: &PathBuf) {
74 let cfg = VespertideConfig::default();
75 let text = serde_json::to_string_pretty(&cfg).unwrap();
76 fs::write(path, text).unwrap();
77 }
78
79 #[test]
80 #[serial]
81 fn test_load_config_from_path_success() {
82 let tmp = tempdir().unwrap();
83 let config_path = tmp.path().join("vespertide.json");
84 write_config(&config_path);
85
86 let result = load_config_from_path(config_path);
87 assert!(result.is_ok());
88 let config = result.unwrap();
89 assert_eq!(config.models_dir, PathBuf::from("models"));
90 }
91
92 #[test]
93 #[serial]
94 fn test_load_config_from_path_not_found() {
95 let tmp = tempdir().unwrap();
96 let config_path = tmp.path().join("nonexistent.json");
97
98 let result = load_config_from_path(config_path.clone());
99 assert!(result.is_err());
100 let err_msg = result.unwrap_err().to_string();
101 assert!(err_msg.contains("vespertide.json not found at:"));
102 assert!(err_msg.contains(&config_path.display().to_string()));
103 }
104
105 #[test]
106 #[serial]
107 fn test_load_config_or_default_with_root() {
108 let tmp = tempdir().unwrap();
109 let config_path = tmp.path().join("vespertide.json");
110 write_config(&config_path);
111
112 let result = load_config_or_default(Some(tmp.path().to_path_buf()));
113 assert!(result.is_ok());
114 let config = result.unwrap();
115 assert_eq!(config.models_dir, PathBuf::from("models"));
116 }
117
118 #[test]
119 #[serial]
120 fn test_load_config_or_default_without_root() {
121 let tmp = tempdir().unwrap();
122 let _guard = CwdGuard::new(&tmp.path().to_path_buf());
123 let config_path = PathBuf::from("vespertide.json");
124 write_config(&config_path);
125
126 let result = load_config_or_default(None);
127 assert!(result.is_ok());
128 let config = result.unwrap();
129 assert_eq!(config.models_dir, PathBuf::from("models"));
130 }
131
132 #[test]
133 #[serial]
134 fn test_load_config_or_default_fallback_to_default() {
135 let tmp = tempdir().unwrap();
136 let _guard = CwdGuard::new(&tmp.path().to_path_buf());
137
138 let result = load_config_or_default(None);
139 assert!(result.is_ok());
140 let config = result.unwrap();
141 assert_eq!(config.models_dir, PathBuf::from("models"));
142 }
143
144 #[test]
145 #[serial]
146 fn test_load_config_success() {
147 let tmp = tempdir().unwrap();
148 let _guard = CwdGuard::new(&tmp.path().to_path_buf());
149 let config_path = PathBuf::from("vespertide.json");
150 write_config(&config_path);
151
152 let result = load_config();
153 assert!(result.is_ok());
154 let config = result.unwrap();
155 assert_eq!(config.models_dir, PathBuf::from("models"));
156 }
157
158 #[test]
159 #[serial]
160 fn test_load_config_not_found() {
161 let tmp = tempdir().unwrap();
162 let _guard = CwdGuard::new(&tmp.path().to_path_buf());
163
164 let result = load_config();
165 assert!(result.is_err());
166 let err_msg = result.unwrap_err().to_string();
167 assert!(err_msg.contains("vespertide.json not found"));
168 }
169}