use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
pub port: u16,
pub host: String,
pub database_url: String,
pub log_level: String,
pub request_timeout_secs: u32,
}
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub valid: bool,
pub errors: Vec<String>,
}
impl ValidationResult {
pub fn valid() -> Self {
Self {
valid: true,
errors: Vec::new(),
}
}
pub fn invalid(errors: Vec<String>) -> Self {
Self {
valid: false,
errors,
}
}
pub fn with_error(mut self, error: String) -> Self {
self.valid = false;
self.errors.push(error);
self
}
}
pub fn validate_config(config: &ServerConfig) -> ValidationResult {
let mut errors = Vec::new();
if config.port == 0 {
errors.push("Port must not be zero".to_string());
}
if config.host.is_empty() {
errors.push("Host must not be empty".to_string());
}
if config.database_url.is_empty() {
errors.push("Database URL must not be empty".to_string());
}
let valid_levels = ["debug", "info", "warn", "error"];
if !valid_levels.contains(&config.log_level.as_str()) {
errors.push(format!(
"Invalid log level: {}. Must be one of: {:?}",
config.log_level, valid_levels
));
}
if config.request_timeout_secs == 0 {
errors.push("Request timeout must be greater than zero".to_string());
}
if errors.is_empty() {
ValidationResult::valid()
} else {
ValidationResult::invalid(errors)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_config() {
let config = ServerConfig {
port: 8080,
host: "0.0.0.0".to_string(),
database_url: "postgres://localhost/db".to_string(),
log_level: "info".to_string(),
request_timeout_secs: 30,
};
let result = validate_config(&config);
assert!(result.valid);
assert!(result.errors.is_empty());
}
#[test]
fn test_invalid_config() {
let config = ServerConfig {
port: 0,
host: "".to_string(),
database_url: "".to_string(),
log_level: "invalid".to_string(),
request_timeout_secs: 0,
};
let result = validate_config(&config);
assert!(!result.valid);
assert!(!result.errors.is_empty());
}
}