use mecha10_cli::*;
use serial_test::serial;
use std::env;
use std::path::PathBuf;
fn clear_test_env() {
env::remove_var("REDIS_URL");
env::remove_var("MECHA10_REDIS_URL");
env::remove_var("DATABASE_URL");
env::remove_var("POSTGRES_URL");
env::remove_var("DEV_MODE");
env::remove_var("MECHA10_DEV_MODE");
}
#[test]
#[serial]
fn test_builder_defaults() {
clear_test_env();
let ctx = CliContextBuilder::new().build().unwrap();
assert_eq!(ctx.redis_url(), "redis://localhost:6379");
assert_eq!(ctx.postgres_url(), None);
assert!(!ctx.is_verbose());
assert!(!ctx.is_dev_mode());
assert_eq!(ctx.log_level, Level::INFO);
}
#[test]
fn test_builder_explicit_values() {
let ctx = CliContextBuilder::new()
.redis_url("redis://custom:1234".to_string())
.postgres_url(Some("postgres://test".to_string()))
.verbose(true)
.dev_mode(true)
.log_level(Level::DEBUG)
.build()
.unwrap();
assert_eq!(ctx.redis_url(), "redis://custom:1234");
assert_eq!(ctx.postgres_url(), Some("postgres://test"));
assert!(ctx.is_verbose());
assert!(ctx.is_dev_mode());
assert_eq!(ctx.log_level, Level::DEBUG);
}
#[test]
#[serial]
fn test_builder_env_precedence() {
clear_test_env();
env::set_var("REDIS_URL", "redis://from-env:6379");
env::set_var("DATABASE_URL", "postgres://from-env");
env::set_var("MECHA10_DEV_MODE", "true");
let ctx = CliContextBuilder::new().build().unwrap();
assert_eq!(ctx.redis_url(), "redis://from-env:6379");
assert_eq!(ctx.postgres_url(), Some("postgres://from-env"));
assert!(ctx.is_dev_mode());
clear_test_env();
}
#[test]
#[serial]
fn test_builder_explicit_overrides_env() {
env::set_var("REDIS_URL", "redis://from-env:6379");
let ctx = CliContextBuilder::new()
.redis_url("redis://explicit:1234".to_string())
.build()
.unwrap();
assert_eq!(ctx.redis_url(), "redis://explicit:1234");
env::remove_var("REDIS_URL");
}
#[test]
#[serial]
fn test_builder_mecha10_env_priority() {
env::set_var("MECHA10_REDIS_URL", "redis://mecha10:6379");
env::set_var("REDIS_URL", "redis://generic:6379");
let ctx = CliContextBuilder::new().build().unwrap();
assert_eq!(ctx.redis_url(), "redis://mecha10:6379");
env::remove_var("MECHA10_REDIS_URL");
env::remove_var("REDIS_URL");
}
#[test]
#[serial]
fn test_convenience_methods() {
clear_test_env();
let ctx = CliContextBuilder::new()
.verbose(true)
.dev_mode(false)
.redis_url("redis://test:6379".to_string())
.build()
.unwrap();
assert!(ctx.is_verbose());
assert!(!ctx.is_dev_mode());
assert_eq!(ctx.redis_url(), "redis://test:6379");
assert_eq!(ctx.postgres_url(), None);
}
#[test]
fn test_project_path() {
let working_dir = PathBuf::from("/test/project");
let ctx = CliContextBuilder::new()
.working_dir(working_dir.clone())
.build()
.unwrap();
assert_eq!(ctx.project_path("config"), PathBuf::from("/test/project/config"));
assert_eq!(
ctx.project_path("nodes/camera"),
PathBuf::from("/test/project/nodes/camera")
);
}
#[test]
#[serial]
fn test_dev_mode_env_variations() {
clear_test_env();
env::set_var("DEV_MODE", "1");
let ctx = CliContextBuilder::new().build().unwrap();
assert!(ctx.is_dev_mode());
clear_test_env();
env::set_var("DEV_MODE", "true");
let ctx = CliContextBuilder::new().build().unwrap();
assert!(ctx.is_dev_mode());
clear_test_env();
env::set_var("DEV_MODE", "True");
let ctx = CliContextBuilder::new().build().unwrap();
assert!(ctx.is_dev_mode());
clear_test_env();
env::set_var("DEV_MODE", "false");
let ctx = CliContextBuilder::new().build().unwrap();
assert!(!ctx.is_dev_mode());
clear_test_env();
env::set_var("DEV_MODE", "0");
let ctx = CliContextBuilder::new().build().unwrap();
assert!(!ctx.is_dev_mode());
clear_test_env();
}
#[test]
fn test_config_path_default() {
let working_dir = PathBuf::from("/test/project");
let ctx = CliContextBuilder::new()
.working_dir(working_dir.clone())
.build()
.unwrap();
assert_eq!(ctx.config_path, PathBuf::from("/test/project/mecha10.json"));
}
#[test]
fn test_config_path_explicit() {
let custom_path = PathBuf::from("/custom/config.json");
let ctx = CliContextBuilder::new()
.config_path(Some(custom_path.clone()))
.build()
.unwrap();
assert_eq!(ctx.config_path, custom_path);
}
#[test]
#[serial]
fn test_default_context() {
clear_test_env();
let ctx = CliContext::default();
assert_eq!(ctx.log_level, Level::INFO);
assert_eq!(ctx.redis_url(), "redis://localhost:6379");
assert!(!ctx.is_verbose());
assert!(!ctx.is_dev_mode());
}
#[test]
fn test_template_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _template1 = ctx.template();
let _template2 = ctx.template();
}
#[test]
fn test_simulation_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _sim1 = ctx.simulation();
let _sim2 = ctx.simulation();
}
#[test]
fn test_process_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _proc1 = ctx.process();
let _proc2 = ctx.process();
}
#[test]
fn test_docker_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _docker1 = ctx.docker();
let _docker2 = ctx.docker();
}
#[test]
fn test_deployment_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _deploy1 = ctx.deployment();
let _deploy2 = ctx.deployment();
}
#[test]
fn test_component_catalog_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _catalog1 = ctx.component_catalog();
let _catalog2 = ctx.component_catalog();
}
#[test]
fn test_discovery_service_lazy_init() {
let mut ctx = CliContextBuilder::new().build().unwrap();
let _discovery1 = ctx.discovery();
let _discovery2 = ctx.discovery();
}
#[test]
fn test_is_ci() {
let ctx = CliContextBuilder::new().build().unwrap();
let ci_was_set = env::var("CI").is_ok();
env::set_var("CI", "true");
assert!(ctx.is_ci());
env::remove_var("CI");
env::set_var("GITHUB_ACTIONS", "true");
assert!(ctx.is_ci());
env::remove_var("GITHUB_ACTIONS");
env::set_var("GITLAB_CI", "true");
assert!(ctx.is_ci());
env::remove_var("GITLAB_CI");
if !ci_was_set {
env::remove_var("CI");
}
}
#[test]
fn test_path_helpers() {
let working_dir = PathBuf::from("/test/project");
let ctx = CliContextBuilder::new()
.working_dir(working_dir.clone())
.build()
.unwrap();
assert_eq!(ctx.logs_dir(), PathBuf::from("/test/project/logs"));
assert_eq!(ctx.data_dir(), PathBuf::from("/test/project/data"));
assert_eq!(ctx.recordings_dir(), PathBuf::from("/test/project/data/recordings"));
assert_eq!(ctx.maps_dir(), PathBuf::from("/test/project/data/maps"));
assert_eq!(ctx.telemetry_dir(), PathBuf::from("/test/project/data/telemetry"));
assert_eq!(ctx.simulation_dir(), PathBuf::from("/test/project/simulation"));
assert_eq!(ctx.target_debug_dir(), PathBuf::from("/test/project/target/debug"));
assert_eq!(ctx.target_release_dir(), PathBuf::from("/test/project/target/release"));
assert_eq!(ctx.packages_dir(), PathBuf::from("/test/project/target/packages"));
}
#[test]
fn test_ensure_dir() {
use tempfile::TempDir;
let temp = TempDir::new().unwrap();
let ctx = CliContextBuilder::new()
.working_dir(temp.path().to_path_buf())
.build()
.unwrap();
let test_dir = temp.path().join("test_dir");
assert!(!test_dir.exists());
ctx.ensure_dir(&test_dir).unwrap();
assert!(test_dir.exists());
ctx.ensure_dir(&test_dir).unwrap();
assert!(test_dir.exists());
}
#[test]
fn test_validate_project_structure_not_initialized() {
use tempfile::TempDir;
let temp = TempDir::new().unwrap();
let ctx = CliContextBuilder::new()
.working_dir(temp.path().to_path_buf())
.build()
.unwrap();
let result = ctx.validate_project_structure();
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("not initialized"));
}
#[test]
fn test_validate_project_structure_missing_dirs() {
use tempfile::TempDir;
let temp = TempDir::new().unwrap();
let ctx = CliContextBuilder::new()
.working_dir(temp.path().to_path_buf())
.build()
.unwrap();
std::fs::write(temp.path().join("mecha10.json"), "{}").unwrap();
let result = ctx.validate_project_structure();
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("nodes"));
}
#[test]
fn test_validate_project_structure_success() {
use tempfile::TempDir;
let temp = TempDir::new().unwrap();
let ctx = CliContextBuilder::new()
.working_dir(temp.path().to_path_buf())
.build()
.unwrap();
std::fs::write(temp.path().join("mecha10.json"), "{}").unwrap();
std::fs::create_dir(temp.path().join("nodes")).unwrap();
std::fs::create_dir(temp.path().join("drivers")).unwrap();
let result = ctx.validate_project_structure();
assert!(result.is_ok());
}