#![cfg(feature = "validation")]
use config_lib::validation::{
RangeValidator, RequiredKeyValidator, TypeValidator, ValidationError, ValidationResult,
ValidationRule, ValidationRuleSet, ValidationSeverity, ValueType,
};
use config_lib::Config;
use std::time::Instant;
#[test]
fn test_enterprise_validation_integration() {
let mut config = Config::from_string(
r#"
database_url = "postgresql://localhost:5432/mydb"
server_port = 8080
max_connections = 100
timeout_seconds = 30
ssl_enabled = true
worker_threads = 4
"#,
Some("conf"),
)
.unwrap();
let rules = ValidationRuleSet::new()
.add_rule(TypeValidator::new(ValueType::Integer))
.add_rule(RangeValidator::new(Some(1.0), Some(65535.0)))
.add_rule(RequiredKeyValidator::new(vec![
"database_url".to_string(),
"server_port".to_string(),
]));
config.set_validation_rules(rules);
let errors = config.validate().unwrap();
assert!(!errors.is_empty());
let critical_errors = config.validate_critical_only().unwrap();
assert!(critical_errors.is_empty());
assert!(config.is_valid().unwrap());
}
#[test]
fn test_validation_performance() {
let mut config = Config::new();
for i in 0..1000 {
config.set(&format!("key_{i}"), i as i64).unwrap();
}
let rules = ValidationRuleSet::new()
.add_rule(TypeValidator::new(ValueType::Integer))
.add_rule(RangeValidator::new(Some(0.0), Some(2000.0)));
let _ = rules;
let start = Instant::now();
let errors = config.validate().unwrap();
let duration = start.elapsed();
assert!(
duration.as_millis() < 100,
"Validation took {}ms, expected <100ms",
duration.as_millis()
);
assert!(errors.is_empty());
println!("Validated 1000 keys in {}μs", duration.as_micros());
}
#[test]
fn test_validation_error_reporting() {
let mut config = Config::from_string(
r#"
invalid_port = 99999
negative_timeout = -5
string_as_number = "not_a_number"
"#,
Some("conf"),
)
.unwrap();
let rules = ValidationRuleSet::new().add_rule(RangeValidator::new(Some(1.0), Some(65535.0)));
config.set_validation_rules(rules);
let errors = config.validate().unwrap();
assert!(!errors.is_empty());
for error in &errors {
assert!(!error.path.is_empty());
assert!(!error.rule.is_empty());
assert!(!error.message.is_empty());
println!("Validation error: {error}");
}
}
#[test]
fn test_type_validator_comprehensive() {
let string_validator = TypeValidator::new(ValueType::String);
let int_validator = TypeValidator::new(ValueType::Integer);
let bool_validator = TypeValidator::new(ValueType::Boolean);
let result = string_validator.validate("test", &config_lib::Value::String("hello".to_string()));
assert_eq!(result, ValidationResult::Valid);
let result = string_validator.validate("test", &config_lib::Value::Integer(42));
assert!(matches!(result, ValidationResult::Invalid(_)));
let result = int_validator.validate("test", &config_lib::Value::Integer(42));
assert_eq!(result, ValidationResult::Valid);
let result = int_validator.validate("test", &config_lib::Value::String("42".to_string()));
assert_eq!(result, ValidationResult::Valid);
let result = int_validator.validate(
"test",
&config_lib::Value::String("not_a_number".to_string()),
);
assert!(matches!(result, ValidationResult::Invalid(_)));
let result = bool_validator.validate("test", &config_lib::Value::Bool(true));
assert_eq!(result, ValidationResult::Valid);
let result = bool_validator.validate("test", &config_lib::Value::Integer(1));
assert!(matches!(result, ValidationResult::Invalid(_)));
}
#[test]
fn test_range_validator_edge_cases() {
let validator = RangeValidator::new(Some(10.0), Some(100.0));
let result = validator.validate("test", &config_lib::Value::Integer(10));
assert_eq!(result, ValidationResult::Valid);
let result = validator.validate("test", &config_lib::Value::Integer(100));
assert_eq!(result, ValidationResult::Valid);
let result = validator.validate("test", &config_lib::Value::Integer(9));
assert!(matches!(result, ValidationResult::Invalid(_)));
let result = validator.validate("test", &config_lib::Value::Integer(101));
assert!(matches!(result, ValidationResult::Invalid(_)));
let result = validator.validate("test", &config_lib::Value::Float(50.5));
assert_eq!(result, ValidationResult::Valid);
let result = validator.validate("test", &config_lib::Value::Float(150.5));
assert!(matches!(result, ValidationResult::Invalid(_)));
let result = validator.validate("test", &config_lib::Value::String("test".to_string()));
assert_eq!(result, ValidationResult::Valid);
}
#[test]
fn test_required_key_validation() {
let validator = RequiredKeyValidator::new(vec![
"database_url".to_string(),
"api_key".to_string(),
"service_port".to_string(),
]);
let mut config = std::collections::BTreeMap::new();
config.insert(
"database_url".to_string(),
config_lib::Value::String("localhost".to_string()),
);
config.insert(
"api_key".to_string(),
config_lib::Value::String("secret".to_string()),
);
config.insert("service_port".to_string(), config_lib::Value::Integer(8080));
config.insert(
"optional_setting".to_string(),
config_lib::Value::Bool(true),
);
let errors = validator.validate_config(&config);
assert!(errors.is_empty());
config.remove("api_key");
let errors = validator.validate_config(&config);
assert_eq!(errors.len(), 1);
assert_eq!(errors[0].severity, ValidationSeverity::Critical);
assert!(errors[0].message.contains("api_key"));
config.remove("database_url");
let errors = validator.validate_config(&config);
assert_eq!(errors.len(), 2);
}
#[test]
fn test_validation_rule_priority() {
let mut rule_set = ValidationRuleSet::new()
.add_rule(TypeValidator::new(ValueType::Integer)) .add_rule(RangeValidator::new(Some(1.0), Some(100.0))) .add_rule(RequiredKeyValidator::new(vec!["test".to_string()]));
let errors = rule_set.validate("test", &config_lib::Value::String("invalid".to_string()));
assert!(!errors.is_empty());
assert_eq!(errors[0].rule, "type_validator");
}
#[test]
fn test_validation_severity_levels() {
let error = ValidationError::new("path", "rule", "message");
assert_eq!(error.severity, ValidationSeverity::Error);
let critical_error = error.with_severity(ValidationSeverity::Critical);
assert_eq!(critical_error.severity, ValidationSeverity::Critical);
assert!(ValidationSeverity::Critical > ValidationSeverity::Error);
assert!(ValidationSeverity::Error > ValidationSeverity::Warning);
assert!(ValidationSeverity::Warning > ValidationSeverity::Info);
}
#[test]
fn test_enterprise_configuration_scenario() {
let mut config = Config::from_string(
r#"
# Database Configuration
database_host = "prod-db-cluster.company.com"
database_port = 5432
database_max_connections = 50
database_timeout = 30
# API Configuration
api_port = 8080
api_workers = 8
api_rate_limit = 1000
# Security Configuration
ssl_enabled = true
jwt_secret = "super-secret-key-2024"
session_timeout = 3600
# Monitoring Configuration
metrics_enabled = true
log_level = "INFO"
health_check_interval = 60
"#,
Some("conf"),
)
.unwrap();
let rules = ValidationRuleSet::new()
.add_rule(RangeValidator::new(Some(1.0), Some(65535.0)))
.add_rule(RequiredKeyValidator::new(vec![
"database_host".to_string(),
"database_port".to_string(),
"api_port".to_string(),
"ssl_enabled".to_string(),
]));
let _ = rules;
let errors = config.validate().unwrap();
let critical_errors = config.validate_critical_only().unwrap();
assert!(
critical_errors.is_empty(),
"Enterprise config should have no critical errors"
);
assert!(
config.is_valid().unwrap(),
"Enterprise config should be valid"
);
println!(
"Enterprise configuration validation: {} total errors, {} critical",
errors.len(),
critical_errors.len()
);
}
#[test]
fn test_concurrent_validation() {
use std::thread;
let config_data = r#"
test_value_1 = 42
test_value_2 = 100
test_value_3 = 200
"#;
let handles: Vec<_> = (0..10)
.map(|_| {
let data = config_data.to_string();
thread::spawn(move || {
let mut config = Config::from_string(&data, Some("conf")).unwrap();
let rules =
ValidationRuleSet::new().add_rule(RangeValidator::new(Some(1.0), Some(300.0)));
let _ = rules;
let errors = config.validate().unwrap();
assert!(errors.is_empty());
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn benchmark_validation_performance() {
let mut config = Config::new();
let settings = [
(
"database_host",
config_lib::Value::String("localhost".to_string()),
),
("database_port", config_lib::Value::Integer(5432)),
("api_port", config_lib::Value::Integer(8080)),
("worker_threads", config_lib::Value::Integer(4)),
("max_memory_mb", config_lib::Value::Integer(1024)),
];
for i in 0..20 {
for (key, value) in &settings {
config.set(&format!("{key}_{i}"), value.clone()).unwrap();
}
}
let rules = ValidationRuleSet::new()
.add_rule(TypeValidator::new(ValueType::Integer))
.add_rule(RangeValidator::new(Some(1.0), Some(100000.0)));
let _ = rules;
let iterations = 100;
let start = Instant::now();
for _ in 0..iterations {
let _ = config.validate().unwrap();
}
let total_duration = start.elapsed();
let avg_duration = total_duration / iterations;
println!("Average validation time: {}μs", avg_duration.as_micros());
println!(
"Validations per second: {}",
1_000_000 / avg_duration.as_micros().max(1)
);
assert!(
avg_duration.as_millis() < 1,
"Validation took {}μs, expected <1000μs",
avg_duration.as_micros()
);
}