#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub mod env;
pub mod file;
mod cache;
mod error;
mod hf;
pub use cache::CacheConfig;
pub use error::ConfigError;
pub use hf::HfConfig;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(default, deny_unknown_fields)]
#[non_exhaustive]
pub struct VoxoraConfig {
pub cache: CacheConfig,
pub hf: HfConfig,
}
impl VoxoraConfig {
pub fn new(cache: CacheConfig, hf: HfConfig) -> Self {
Self { cache, hf }
}
pub fn cache_root(&self) -> std::path::PathBuf {
self.cache.resolve()
}
pub fn hf_token(&self) -> Option<String> {
self.hf.token()
}
pub fn hf_base_url(&self) -> String {
self.hf.base_url()
}
pub fn hf_default_revision(&self) -> String {
self.hf.default_revision()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_roundtrip_via_toml() {
let cfg = VoxoraConfig::default();
let text = toml::to_string(&cfg).expect("toml::to_string");
let parsed = VoxoraConfig::from_str(&text, std::path::Path::new("inline")).expect("parse");
assert_eq!(cfg, parsed);
}
#[test]
fn unknown_field_is_rejected() {
let bad = r#"
cache.root = "/tmp/cache"
hf.token = "abc"
bogus_field = "should-error"
"#;
let err = VoxoraConfig::from_str(bad, std::path::Path::new("inline"))
.expect_err("deny_unknown_fields");
assert!(matches!(err, ConfigError::FileParse { .. }));
}
#[test]
fn cache_root_matches_inner_resolve() {
let cfg = VoxoraConfig::default();
assert_eq!(cfg.cache_root(), cfg.cache.resolve());
}
#[test]
fn hf_token_propagates_from_inner() {
let cfg = VoxoraConfig {
hf: HfConfig {
token: Some("xyz".into()),
..HfConfig::default()
},
..VoxoraConfig::default()
};
assert_eq!(cfg.hf_token().as_deref(), Some("xyz"));
}
#[test]
fn new_matches_struct_expression() {
let cache = CacheConfig::new(Some(std::path::PathBuf::from("/tmp/c")));
let hf = HfConfig::new(Some("t".into()), None, None);
assert_eq!(
VoxoraConfig::new(cache.clone(), hf.clone()),
VoxoraConfig { cache, hf }
);
}
}