use serde::Deserialize;
use std::path::Path;
#[derive(Debug, Deserialize)]
pub struct Config {
#[serde(default)]
pub http: HttpConfig,
}
#[derive(Debug, Deserialize)]
pub struct HttpConfig {
#[serde(default = "default_bind")]
pub bind: String,
#[serde(default)]
pub mcp_key: String,
}
impl Default for HttpConfig {
fn default() -> Self {
Self {
bind: default_bind(),
mcp_key: String::new(),
}
}
}
fn default_bind() -> String {
"127.0.0.1:8080".to_string()
}
impl Config {
pub fn load(path: &Path) -> anyhow::Result<Self> {
let content = std::fs::read_to_string(path)?;
let config: Self = toml::from_str(&content)?;
Ok(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
#[test]
fn test_default_http_config() {
let cfg = HttpConfig::default();
assert_eq!(cfg.bind, "127.0.0.1:8080");
assert_eq!(cfg.mcp_key, "");
}
#[test]
fn test_parse_empty_config() {
let config: Config = toml::from_str("").unwrap();
assert_eq!(config.http.bind, "127.0.0.1:8080");
assert_eq!(config.http.mcp_key, "");
}
#[test]
fn test_parse_full_config() {
let toml = r#"
[http]
bind = "0.0.0.0:9090"
mcp_key = "secret123"
"#;
let config: Config = toml::from_str(toml).unwrap();
assert_eq!(config.http.bind, "0.0.0.0:9090");
assert_eq!(config.http.mcp_key, "secret123");
}
#[test]
fn test_parse_partial_config() {
let toml = r#"
[http]
mcp_key = "mykey"
"#;
let config: Config = toml::from_str(toml).unwrap();
assert_eq!(config.http.bind, "127.0.0.1:8080");
assert_eq!(config.http.mcp_key, "mykey");
}
#[test]
fn test_load_from_file() {
let mut tmp = tempfile::NamedTempFile::new().unwrap();
writeln!(
tmp,
r#"
[http]
bind = "127.0.0.1:3000"
mcp_key = "test-key"
"#
)
.unwrap();
let config = Config::load(tmp.path()).unwrap();
assert_eq!(config.http.bind, "127.0.0.1:3000");
assert_eq!(config.http.mcp_key, "test-key");
}
#[test]
fn test_load_nonexistent_file() {
let result = Config::load(Path::new("/nonexistent/config.toml"));
assert!(result.is_err());
}
}