1
0
Fork 0
mirror of https://github.com/imjasonh/testscript-rs synced 2026-07-13 03:18:20 +00:00

Implement network and advanced condition support

Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-09-27 01:56:58 +00:00
parent 8f82c9c11b
commit 26a39e2384
8 changed files with 335 additions and 3 deletions

View file

@ -79,7 +79,7 @@ fn run(params: &mut RunParams, test_data_glob: &str) -> Result<()> {
/// // Simple usage
/// testscript::run("testdata").execute().unwrap();
///
/// // With customization
/// // With customization and advanced conditions
/// testscript::run("testdata")
/// .setup(|env| {
/// // Compile your CLI tool
@ -93,8 +93,28 @@ fn run(params: &mut RunParams, test_data_glob: &str) -> Result<()> {
/// // Custom command implementation
/// Ok(())
/// })
/// .condition("net", check_network_available())
/// .condition("docker", command_exists("docker"))
/// .condition("env:CI", std::env::var("CI").is_ok())
/// .execute()
/// .unwrap();
///
/// // Auto-detect network and programs
/// testscript::run("testdata")
/// .auto_detect_network()
/// .auto_detect_programs(&["docker", "git", "npm"])
/// .execute()
/// .unwrap();
///
/// fn check_network_available() -> bool {
/// // Your network check implementation
/// true
/// }
///
/// fn command_exists(cmd: &str) -> bool {
/// // Your command existence check
/// false
/// }
/// ```
pub struct Builder {
dir: String,
@ -149,6 +169,37 @@ impl Builder {
self
}
/// Automatically detect network availability and set the 'net' condition
///
/// This will attempt to ping reliable hosts to determine if network
/// connectivity is available and set the condition accordingly.
pub fn auto_detect_network(mut self) -> Self {
self.params = self.params.auto_detect_network();
self
}
/// Automatically detect availability of specified programs
///
/// This will check if the given programs are available in PATH and
/// set conditions like `exec:program` for each one.
///
/// # Arguments
/// * `programs` - Slice of program names to check for
///
/// # Examples
/// ```no_run
/// use testscript_rs::testscript;
///
/// testscript::run("testdata")
/// .auto_detect_programs(&["docker", "git", "npm"])
/// .execute()
/// .unwrap();
/// ```
pub fn auto_detect_programs(mut self, programs: &[&str]) -> Self {
self.params = self.params.auto_detect_programs(programs);
self
}
/// Execute all test scripts in the configured directory
///
/// This will discover all `.txt` files in the directory and run them as test scripts.

View file

@ -196,10 +196,16 @@ fn execute_command_inner(
if let Some(ref condition) = command.condition {
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(base_condition) = condition.strip_prefix('!') {
// Handle negated conditions
if let Some(value) = params.conditions.get(base_condition) {
!value
} else if base_condition.starts_with("env:") {
// Dynamic negated environment variable condition
!RunParams::check_env_condition(base_condition)
} else {
return Err(Error::UnknownCondition {
condition: base_condition.to_string(),

View file

@ -86,14 +86,67 @@ impl RunParams {
self
}
/// Check if a program exists in PATH
/// Automatically detect network availability and set the 'net' condition
pub fn auto_detect_network(mut self) -> Self {
self.conditions.insert("net".to_string(), Self::check_network_available());
self
}
/// Automatically detect availability of specified programs
pub fn auto_detect_programs(mut self, programs: &[&str]) -> Self {
for program in programs {
let condition_name = format!("exec:{}", program);
self.conditions.insert(condition_name, Self::program_exists(program));
}
self
}
/// Check if a program exists in PATH (cross-platform)
fn program_exists(program: &str) -> bool {
std::process::Command::new("which")
// Use different commands based on platform
#[cfg(windows)]
let check_cmd = "where";
#[cfg(not(windows))]
let check_cmd = "which";
std::process::Command::new(check_cmd)
.arg(program)
.output()
.map(|output| output.status.success())
.unwrap_or(false)
}
/// Check if network is available by attempting to reach a reliable host
fn check_network_available() -> bool {
// Try multiple reliable hosts to increase reliability
let test_hosts = ["1.1.1.1", "8.8.8.8", "9.9.9.9"];
for host in &test_hosts {
let output = std::process::Command::new("ping")
.args(if cfg!(windows) {
vec!["-n", "1", "-w", "1000", host]
} else {
vec!["-c", "1", "-W", "1", host]
})
.output();
if let Ok(result) = output {
if result.status.success() {
return true;
}
}
}
false
}
/// Check environment variable condition
pub fn check_env_condition(condition: &str) -> bool {
if let Some(env_var) = condition.strip_prefix("env:") {
std::env::var(env_var).is_ok()
} else {
false
}
}
}
impl Default for RunParams {