use std::fs;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use vespertide_config::VespertideConfig;
fn read_config(path: &Path) -> Result<VespertideConfig> {
let content = fs::read_to_string(path).context("read vespertide.json")?;
let config: VespertideConfig =
serde_json::from_str(&content).context("parse vespertide.json")?;
Ok(config)
}
pub fn load_config() -> Result<VespertideConfig> {
let path = PathBuf::from("vespertide.json");
if !path.exists() {
anyhow::bail!("vespertide.json not found. Run 'vespertide init' first.");
}
read_config(&path)
}
pub fn load_config_from_path(path: impl AsRef<Path>) -> Result<VespertideConfig> {
let path = path.as_ref();
if !path.exists() {
anyhow::bail!("vespertide.json not found at: {}", path.display());
}
read_config(path)
}
pub fn load_config_or_default(project_root: Option<PathBuf>) -> Result<VespertideConfig> {
let config_path = if let Some(root) = project_root {
root.join("vespertide.json")
} else {
PathBuf::from("vespertide.json")
};
if config_path.exists() {
load_config_from_path(config_path)
} else {
Ok(VespertideConfig::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::{CwdGuard, write_default_config};
use serial_test::serial;
use tempfile::tempdir;
#[test]
#[serial]
fn test_load_config_from_path_success() {
let tmp = tempdir().unwrap();
let config_path = tmp.path().join("vespertide.json");
write_default_config(&config_path);
let result = load_config_from_path(config_path);
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.models_dir, PathBuf::from("models"));
}
#[test]
#[serial]
fn test_load_config_from_path_not_found() {
let tmp = tempdir().unwrap();
let config_path = tmp.path().join("nonexistent.json");
let result = load_config_from_path(config_path.clone());
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(err_msg.contains("vespertide.json not found at:"));
assert!(err_msg.contains(&config_path.display().to_string()));
}
#[test]
#[serial]
fn test_load_config_or_default_with_root() {
let tmp = tempdir().unwrap();
let config_path = tmp.path().join("vespertide.json");
write_default_config(&config_path);
let result = load_config_or_default(Some(tmp.path().to_path_buf()));
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.models_dir, PathBuf::from("models"));
}
#[test]
#[serial]
fn test_load_config_or_default_without_root() {
let tmp = tempdir().unwrap();
let _guard = CwdGuard::new(tmp.path());
let config_path = PathBuf::from("vespertide.json");
write_default_config(&config_path);
let result = load_config_or_default(None);
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.models_dir, PathBuf::from("models"));
}
#[test]
#[serial]
fn test_load_config_or_default_fallback_to_default() {
let tmp = tempdir().unwrap();
let _guard = CwdGuard::new(tmp.path());
let result = load_config_or_default(None);
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.models_dir, PathBuf::from("models"));
}
#[test]
#[serial]
fn test_load_config_success() {
let tmp = tempdir().unwrap();
let _guard = CwdGuard::new(tmp.path());
let config_path = PathBuf::from("vespertide.json");
write_default_config(&config_path);
let result = load_config();
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.models_dir, PathBuf::from("models"));
}
#[test]
#[serial]
fn test_load_config_not_found() {
let tmp = tempdir().unwrap();
let _guard = CwdGuard::new(tmp.path());
let result = load_config();
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(err_msg.contains("vespertide.json not found"));
}
}