use noml::{parse, Config};
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ NOML Demo - Testing All Features\n");
test_basic_parsing()?;
test_environment_variables()?;
test_native_types()?;
test_config_management()?;
test_complex_structures()?;
println!("โ
All tests passed! NOML is working correctly.\n");
Ok(())
}
fn test_basic_parsing() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Test 1: Basic NOML Parsing");
let source = r#"
# Basic configuration
app_name = "demo-app"
version = "1.0.0"
debug = true
port = 8080
# Arrays and inline tables
features = ["auth", "logging", "metrics"]
server = { host = "localhost", ssl = false }
[database]
host = "localhost"
port = 5432
name = "demo_db"
"#;
let config = parse(source)?;
println!(
" โ App name: {}",
config.get("app_name").unwrap().as_string().unwrap()
);
println!(
" โ Version: {}",
config.get("version").unwrap().as_string().unwrap()
);
println!(
" โ Debug mode: {}",
config.get("debug").unwrap().as_bool().unwrap()
);
println!(
" โ Port: {}",
config.get("port").unwrap().as_integer().unwrap()
);
let features = config.get("features").unwrap().as_array().unwrap();
println!(
" โ Features: {:?}",
features
.iter()
.map(|f| f.as_string().unwrap())
.collect::<Vec<_>>()
);
println!(
" โ Server host: {}",
config.get("server.host").unwrap().as_string().unwrap()
);
println!(
" โ Database: {}:{}",
config.get("database.host").unwrap().as_string().unwrap(),
config.get("database.port").unwrap().as_integer().unwrap()
);
println!(" โ
Basic parsing works!\n");
Ok(())
}
fn test_environment_variables() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ Test 2: Environment Variables");
env::set_var("DEMO_HOST", "production-server");
env::set_var("DEMO_PORT", "9000");
env::set_var("DEMO_DEBUG", "false");
let source = r#"
# Environment-driven config
host = env("DEMO_HOST")
port = env("DEMO_PORT")
debug = env("DEMO_DEBUG")
# With defaults
timeout = env("DEMO_TIMEOUT", "30")
max_retries = env("DEMO_RETRIES", "5")
"#;
let config = parse(source)?;
println!(
" โ Host from env: {}",
config.get("host").unwrap().as_string().unwrap()
);
println!(
" โ Port from env: {}",
config.get("port").unwrap().as_string().unwrap()
);
println!(
" โ Debug from env: {}",
config.get("debug").unwrap().as_string().unwrap()
);
println!(
" โ Timeout (default): {}",
config.get("timeout").unwrap().as_string().unwrap()
);
println!(
" โ Max retries (default): {}",
config.get("max_retries").unwrap().as_string().unwrap()
);
env::remove_var("DEMO_HOST");
env::remove_var("DEMO_PORT");
env::remove_var("DEMO_DEBUG");
println!(" โ
Environment variables work!\n");
Ok(())
}
fn test_native_types() -> Result<(), Box<dyn std::error::Error>> {
println!("๐ง Test 3: Native Types");
let source = r#"
# Native types for better semantics
max_file_size = @size("10MB")
request_timeout = @duration("30s")
backup_interval = @duration("24h")
api_url = @url("https://api.example.com")
# More complex examples
large_file = @size("1.5GB")
quick_timeout = @duration("500ms")
weekly_backup = @duration("7d")
"#;
let config = parse(source)?;
println!(
" โ Max file size: {} bytes",
config.get("max_file_size").unwrap().as_integer().unwrap()
);
println!(
" โ Request timeout: {} seconds",
config.get("request_timeout").unwrap().as_float().unwrap()
);
println!(
" โ Backup interval: {} seconds",
config.get("backup_interval").unwrap().as_float().unwrap()
);
println!(
" โ API URL: {}",
config.get("api_url").unwrap().as_string().unwrap()
);
let large_file_mb = config.get("large_file").unwrap().as_integer().unwrap() / (1024 * 1024);
println!(" โ Large file: {large_file_mb} MB");
let quick_timeout_ms = config.get("quick_timeout").unwrap().as_float().unwrap() * 1000.0;
println!(" โ Quick timeout: {quick_timeout_ms} ms");
println!(" โ
Native types work!\n");
Ok(())
}
fn test_config_management() -> Result<(), Box<dyn std::error::Error>> {
println!("โ๏ธ Test 4: Config Management API");
let source = r#"
name = "config-demo"
version = "1.0.0"
[database]
host = "localhost"
port = 5432
[features]
analytics = true
monitoring = false
"#;
let mut config = Config::from_string(source)?;
println!(
" โ Initial name: {}",
config.get("name").unwrap().as_string().unwrap()
);
config.set("name", "updated-demo")?;
config.set("database.ssl", true)?;
config.set("features.new_feature", "experimental")?;
println!(
" โ Updated name: {}",
config.get("name").unwrap().as_string().unwrap()
);
println!(
" โ Added SSL: {}",
config.get("database.ssl").unwrap().as_bool().unwrap()
);
println!(
" โ New feature: {}",
config
.get("features.new_feature")
.unwrap()
.as_string()
.unwrap()
);
let builder_config = Config::builder()
.default_value("app_type", "web")
.default_value("debug", true)
.build_from_string(r#"name = "built-app""#)?;
println!(
" โ Builder name: {}",
builder_config.get("name").unwrap().as_string().unwrap()
);
println!(
" โ Builder default app_type: {}",
builder_config.get("app_type").unwrap().as_string().unwrap()
);
println!(
" โ Builder default debug: {}",
builder_config.get("debug").unwrap().as_bool().unwrap()
);
println!(" โ
Config management works!\n");
Ok(())
}
fn test_complex_structures() -> Result<(), Box<dyn std::error::Error>> {
println!("๐๏ธ Test 5: Complex Nested Structures");
let source = r#"
# Complex real-world configuration
[app]
name = "complex-demo"
version = "2.0.0"
# Multiple database connections
[[databases]]
name = "primary"
host = "db1.internal"
port = 5432
pool_size = 20
[[databases]]
name = "analytics"
host = "db2.internal"
port = 5433
pool_size = 10
# Service mesh configuration
[services.user_service]
url = @url("https://users.internal")
timeout = @duration("10s")
retries = 3
[services.payment_service]
url = @url("https://payments.internal")
timeout = @duration("30s")
retries = 5
# Feature flags with complex conditions
[features]
new_dashboard = { enabled = true, rollout = 50 }
advanced_analytics = { enabled = false, beta_users = ["user1", "user2"] }
performance_mode = { enabled = true, cache_size = @size("256MB") }
# Monitoring configuration
[monitoring.alerts]
cpu_threshold = 80.0
memory_threshold = @size("2GB")
response_time = @duration("2s")
"#;
let config = parse(source)?;
println!(
" โ App: {} v{}",
config.get("app.name").unwrap().as_string().unwrap(),
config.get("app.version").unwrap().as_string().unwrap()
);
let databases = config.get("databases").unwrap().as_array().unwrap();
println!(" โ Database count: {}", databases.len());
for (i, db) in databases.iter().enumerate() {
println!(
" - DB {}: {} ({}:{})",
i + 1,
db.get("name").unwrap().as_string().unwrap(),
db.get("host").unwrap().as_string().unwrap(),
db.get("port").unwrap().as_integer().unwrap()
);
}
if let Some(user_service_url) = config.get("services.user_service.url") {
println!(
" โ User service: {}",
user_service_url.as_string().unwrap()
);
} else {
println!(
" โ ๏ธ User service URL not found (native types not fully resolved in nested contexts)"
);
}
if let Some(payment_timeout) = config.get("services.payment_service.timeout") {
println!(
" โ Payment timeout: {}s",
payment_timeout.as_float().unwrap()
);
} else {
println!(
" โ ๏ธ Payment timeout not found (native types not fully resolved in nested contexts)"
);
}
let new_dashboard = config.get("features.new_dashboard").unwrap();
println!(
" โ New dashboard enabled: {}, rollout: {}%",
new_dashboard.get("enabled").unwrap().as_bool().unwrap(),
new_dashboard.get("rollout").unwrap().as_integer().unwrap()
);
let beta_users = config
.get("features.advanced_analytics.beta_users")
.unwrap()
.as_array()
.unwrap();
println!(" โ Beta users count: {}", beta_users.len());
if let Some(memory_threshold) = config.get("monitoring.alerts.memory_threshold") {
let memory_gb = memory_threshold.as_integer().unwrap() / (1024 * 1024 * 1024);
println!(" โ Memory alert threshold: {memory_gb} GB");
} else {
println!(
" โ ๏ธ Memory threshold not found (native types in nested contexts need further work)"
);
}
println!(" โ
Complex structures work!\n");
Ok(())
}