use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Once; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; static COUNTER: AtomicUsize = AtomicUsize::new(0); static BUILD_ONCE: Once = Once::new(); fn bin_path() -> PathBuf { if let Ok(exe) = std::env::var("CARGO_BIN_EXE_dcr") { return PathBuf::from(exe); } ensure_bin_built(); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("target"); path.push("debug"); path.push(format!("dcr{}", std::env::consts::EXE_SUFFIX)); path } fn unique_sandbox_dir(prefix: &str) -> PathBuf { let pid = std::process::id(); let n = COUNTER.fetch_add(1, Ordering::SeqCst); let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_nanos(); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("sandbox"); path.push("cli-tests"); path.push(format!("dcr_{prefix}_{pid}_{n}_{now}")); std::fs::create_dir_all(&path).expect("failed to create temp dir"); path } fn run_dcr_env(args: &[&str], cwd: &Path, envs: &[(&str, &str)]) -> std::process::Output { let mut cmd = Command::new(bin_path()); cmd.args(args).current_dir(cwd); for (k, v) in envs { cmd.env(k, v); } cmd.output().expect("failed to run dcr") } fn ensure_bin_built() { BUILD_ONCE.call_once(|| { let status = Command::new("cargo") .arg("build") .current_dir(env!("CARGO_MANIFEST_DIR")) .status() .expect("failed to run cargo build"); assert!(status.success(), "cargo build failed"); }); } #[test] fn lint_command_runs() { let dir = unique_sandbox_dir("lint"); let out = run_dcr_env(&["init"], &dir, &[]); assert!(out.status.success(), "dcr init should succeed"); // Linting a clean project should succeed or at least run without crashing let tidy_ok = Command::new("clang-tidy") .arg("--version") .output() .map(|o| o.status.success()) .unwrap_or(false); if !tidy_ok { eprintln!("clang-tidy not found; skipping lint test"); return; } let out = run_dcr_env(&["lint"], &dir, &[]); assert!( out.status.success(), "dcr lint should run on clean project:\nstdout: {}\nstderr: {}", String::from_utf8_lossy(&out.stdout), String::from_utf8_lossy(&out.stderr) ); }