use anyhow::Result;
use crate::config::Config;
use crate::utils::SMirrorsError;
pub fn validate_directories(config: &Config) -> Result<()> {
let data_dir = Config::data_dir()?;
let cache_dir = Config::cache_dir()?;
if !data_dir.exists() {
std::fs::create_dir_all(&data_dir)
.map_err(|e| SMirrorsError::ConfigError(
format!("Cannot create data directory {:?}: {}", data_dir, e)
))?;
}
if !cache_dir.exists() {
std::fs::create_dir_all(&cache_dir)
.map_err(|e| SMirrorsError::ConfigError(
format!("Cannot create cache directory {:?}: {}", cache_dir, e)
))?;
}
let test_file = data_dir.join(".write_test");
std::fs::write(&test_file, "test")
.map_err(|e| SMirrorsError::ConfigError(
format!("Data directory {:?} is not writable: {}", data_dir, e)
))?;
std::fs::remove_file(&test_file).ok();
Ok(())
}
pub fn validate_static_mirrors(config: &Config) -> Result<()> {
for (name, url) in &config.static_mirrors {
url::Url::parse(url)
.map_err(|e| SMirrorsError::ConfigError(
format!("Invalid static mirror URL for '{}': {} - {}", name, url, e)
))?;
}
Ok(())
}
pub fn validate_logging(config: &Config) -> Result<()> {
let valid_levels = ["trace", "debug", "info", "warn", "error"];
if !valid_levels.contains(&config.logging.level.to_lowercase().as_str()) {
return Err(SMirrorsError::ConfigError(
format!("Invalid log level '{}'. Must be one of: trace, debug, info, warn, error",
config.logging.level)
).into());
}
let valid_formats = ["json", "pretty", "compact"];
if !valid_formats.contains(&config.logging.format.to_lowercase().as_str()) {
return Err(SMirrorsError::ConfigError(
format!("Invalid log format '{}'. Must be one of: json, pretty, compact",
config.logging.format)
).into());
}
if let Some(log_file) = &config.logging.file {
if let Some(parent) = log_file.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent)
.map_err(|e| SMirrorsError::ConfigError(
format!("Cannot create log directory {:?}: {}", parent, e)
))?;
}
}
}
Ok(())
}
pub fn validate_complete(config: &Config) -> Result<()> {
config.validate()?;
validate_directories(config)?;
validate_static_mirrors(config)?;
validate_logging(config)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_default_config() {
let config = Config::default();
assert!(config.validate().is_ok());
}
#[test]
fn test_validate_invalid_weights() {
let mut config = Config::default();
config.testing.speed_weight = 0.5;
config.testing.latency_weight = 0.3;
assert!(config.validate().is_err());
}
#[test]
fn test_validate_negative_weights() {
let mut config = Config::default();
config.testing.speed_weight = -0.1;
assert!(config.validate().is_err());
}
#[test]
fn test_validate_invalid_min_score() {
let mut config = Config::default();
config.testing.min_score = 1.5;
assert!(config.validate().is_err());
}
#[test]
fn test_validate_invalid_concurrent_tests() {
let mut config = Config::default();
config.general.concurrent_tests = 0;
assert!(config.validate().is_err());
config.general.concurrent_tests = 101;
assert!(config.validate().is_err());
}
}