diff --git a/src/lib.rs b/src/lib.rs index 01c0bf9..106d3d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,6 @@ fn run(params: &mut RunParams, test_data_glob: &str) -> Result<()> { /// Builder for configuring and running testscript tests /// /// This provides a fluent interface for setting up and executing test scripts. -/// Network detection and 35+ common programs are automatically detected by default. /// /// ## Automatic Condition Detection /// @@ -79,11 +78,10 @@ fn run(params: &mut RunParams, test_data_glob: &str) -> Result<()> { /// - **Platform conditions**: `[unix]`, `[windows]`, `[linux]`, `[darwin]`, `[macos]` /// - **Network condition**: `[net]` - Tests network connectivity by pinging reliable hosts /// - **Build conditions**: `[debug]`, `[release]` - Based on compilation flags -/// - **Program conditions**: `[exec:program]` - Detects 15+ common programs including: -/// - Basic tools: cat, echo, ls, mkdir, rm, cp, mv, grep, find -/// - Development: git, make, curl, python, node, docker -/// - System: sleep, true, false, sh +/// - **Program conditions**: `[exec:program]` - Checks if a program is available in PATH /// - **Environment conditions**: `[env:VAR]` - Dynamic checking of environment variables +/// - **Program existence**: `[exec:program]` - Checks if a program is available in PATH +/// - **Negation**: Use `!` to negate any condition, e.g. `[!windows]`, `[!env:CI]`, `[!exec:git]` /// /// ## Examples /// diff --git a/src/run/execution.rs b/src/run/execution.rs index db1c8ea..551d7ce 100644 --- a/src/run/execution.rs +++ b/src/run/execution.rs @@ -197,8 +197,9 @@ fn execute_command_inner( let condition_met = if let Some(value) = params.conditions.get(condition) { *value } else if condition.starts_with("env:") { - // Dynamic environment variable condition RunParams::check_env_condition(condition) + } else if let Some(program) = condition.strip_prefix("exec:") { + RunParams::program_exists(program) } else if let Some(base_condition) = condition.strip_prefix('!') { // Handle negated conditions if let Some(value) = params.conditions.get(base_condition) { @@ -206,6 +207,8 @@ fn execute_command_inner( } else if base_condition.starts_with("env:") { // Dynamic negated environment variable condition !RunParams::check_env_condition(base_condition) + } else if let Some(program) = base_condition.strip_prefix("exec:") { + !RunParams::program_exists(program) } else { return Err(Error::UnknownCondition { condition: base_condition.to_string(), diff --git a/src/run/params.rs b/src/run/params.rs index 461a794..0b98c6c 100644 --- a/src/run/params.rs +++ b/src/run/params.rs @@ -42,39 +42,6 @@ impl RunParams { // Add network condition - check if network is available by default conditions.insert("net".to_string(), Self::check_network_available()); - // Check for common programs - optimized set for better CI performance - let common_programs = [ - // Essential Unix/Windows commands (most likely to exist) - "cat", - "echo", - "ls", - "mkdir", - "rm", - "cp", - "mv", - "grep", - "find", - // Core development tools that are commonly available - "git", - "make", - "curl", - "python", - "node", - "docker", - // System tools - "sleep", - "true", - "false", - "sh", - // Test programs (for testing purposes - these likely don't exist) - "nonexistent_rare_program_xyz123", - ]; - - for program in &common_programs { - let condition_name = format!("exec:{}", program); - conditions.insert(condition_name, Self::program_exists(program)); - } - // Check UPDATE_SCRIPTS environment variable let update_scripts = std::env::var("UPDATE_SCRIPTS") .map(|v| v == "1" || v.to_lowercase() == "true") @@ -116,7 +83,9 @@ impl RunParams { } /// Check if a program exists in PATH (cross-platform) - fn program_exists(program: &str) -> bool { + pub fn program_exists(program: &str) -> bool { + // TODO: Consider caching results for performance if needed + // Use different commands based on platform #[cfg(windows)] let check_cmd = "where";