2025-09-26 18:41:14 -04:00
|
|
|
//! # testscript-rs
|
|
|
|
|
//!
|
|
|
|
|
//! A Rust crate for testing command-line tools using filesystem-based script files,
|
|
|
|
|
//! mirroring the functionality of Go's `rogpeppe/go-internal/testscript`.
|
|
|
|
|
//!
|
|
|
|
|
//! This crate provides a framework for writing integration tests for CLI tools
|
|
|
|
|
//! using `.txtar` format files that contain both test scripts and file contents.
|
|
|
|
|
|
|
|
|
|
pub mod error;
|
|
|
|
|
pub mod parser;
|
|
|
|
|
pub mod run;
|
|
|
|
|
|
|
|
|
|
pub use error::{Error, Result};
|
|
|
|
|
pub use parser::{Command, Script, TxtarFile};
|
2025-09-26 21:17:45 -04:00
|
|
|
pub use run::{CommandFn, RunParams, SetupFn, TestEnvironment};
|
2025-09-26 18:41:14 -04:00
|
|
|
|
|
|
|
|
// Re-export for advanced users who need direct access
|
|
|
|
|
pub use run::run_test;
|
|
|
|
|
|
|
|
|
|
// Internal function used by the Builder - not part of public API
|
2025-09-26 21:17:45 -04:00
|
|
|
fn run(params: &mut RunParams, test_data_glob: &str) -> Result<()> {
|
2025-09-26 18:41:14 -04:00
|
|
|
use walkdir::WalkDir;
|
|
|
|
|
|
2025-09-30 07:21:26 +00:00
|
|
|
let mut test_files = Vec::new();
|
2025-09-26 18:41:14 -04:00
|
|
|
|
2025-09-30 07:21:26 +00:00
|
|
|
// If specific files are provided, use them directly
|
|
|
|
|
if let Some(ref files) = params.files {
|
|
|
|
|
// Parse the base directory from the glob pattern
|
|
|
|
|
let base_dir = if let Some(slash_pos) = test_data_glob.rfind('/') {
|
|
|
|
|
&test_data_glob[..slash_pos]
|
|
|
|
|
} else {
|
|
|
|
|
"."
|
|
|
|
|
};
|
2025-09-26 18:41:14 -04:00
|
|
|
|
2025-09-30 07:21:26 +00:00
|
|
|
for file in files {
|
|
|
|
|
let file_path = if file.starts_with('/') {
|
|
|
|
|
// Absolute path - use as-is
|
|
|
|
|
std::path::PathBuf::from(file)
|
|
|
|
|
} else if file.contains('/') {
|
|
|
|
|
// Relative path - resolve relative to base directory
|
|
|
|
|
std::path::PathBuf::from(base_dir).join(file)
|
|
|
|
|
} else {
|
|
|
|
|
// Just a filename - look in the base directory
|
|
|
|
|
std::path::PathBuf::from(base_dir).join(file)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Validate that the file exists
|
|
|
|
|
if !file_path.exists() {
|
|
|
|
|
return Err(Error::Generic(format!(
|
|
|
|
|
"Test file not found: {}",
|
|
|
|
|
file_path.display()
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !file_path.is_file() {
|
|
|
|
|
return Err(Error::Generic(format!(
|
|
|
|
|
"Path is not a file: {}",
|
|
|
|
|
file_path.display()
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test_files.push(file_path);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Use the original glob-based discovery
|
|
|
|
|
let (base_dir, pattern) = if let Some(slash_pos) = test_data_glob.rfind('/') {
|
|
|
|
|
let base_dir = &test_data_glob[..slash_pos];
|
|
|
|
|
let pattern = &test_data_glob[slash_pos + 1..];
|
|
|
|
|
(base_dir, pattern)
|
|
|
|
|
} else {
|
|
|
|
|
(".", test_data_glob)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Convert glob pattern to a simple matcher
|
|
|
|
|
let pattern_regex = pattern.replace("*", ".*");
|
|
|
|
|
let regex = regex::Regex::new(&format!("^{}$", pattern_regex))?;
|
2025-09-26 18:41:14 -04:00
|
|
|
|
2025-09-30 07:21:26 +00:00
|
|
|
// Walk the directory and collect matching files
|
|
|
|
|
for entry in WalkDir::new(base_dir).min_depth(1).max_depth(1) {
|
|
|
|
|
let entry = entry?;
|
|
|
|
|
if entry.file_type().is_file() {
|
|
|
|
|
if let Some(file_name) = entry.file_name().to_str() {
|
|
|
|
|
if regex.is_match(file_name) {
|
|
|
|
|
test_files.push(entry.path().to_path_buf());
|
|
|
|
|
}
|
2025-09-26 18:41:14 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort test files for consistent execution order
|
|
|
|
|
test_files.sort();
|
|
|
|
|
|
|
|
|
|
if test_files.is_empty() {
|
2025-09-30 07:21:26 +00:00
|
|
|
if params.files.is_some() {
|
|
|
|
|
return Err(Error::Generic("No test files specified".to_string()));
|
|
|
|
|
} else {
|
|
|
|
|
return Err(Error::Generic(format!(
|
|
|
|
|
"No test files found matching pattern: {}",
|
|
|
|
|
test_data_glob
|
|
|
|
|
)));
|
|
|
|
|
}
|
2025-09-26 18:41:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run each test file
|
|
|
|
|
for test_file in test_files {
|
|
|
|
|
run::run_script(&test_file, params)
|
|
|
|
|
.map_err(|e| Error::Generic(format!("Test '{}' failed: {}", test_file.display(), e)))?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Builder for configuring and running testscript tests
|
|
|
|
|
///
|
|
|
|
|
/// This provides a fluent interface for setting up and executing test scripts.
|
|
|
|
|
///
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// ## Automatic Condition Detection
|
2025-09-26 18:41:14 -04:00
|
|
|
///
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// The following conditions are automatically available without any setup:
|
|
|
|
|
///
|
|
|
|
|
/// - **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]` - 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
|
|
|
|
|
///
|
|
|
|
|
/// ### Basic Usage
|
2025-09-26 18:41:14 -04:00
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// // Simple usage - all conditions detected automatically
|
2025-09-26 18:41:14 -04:00
|
|
|
/// testscript::run("testdata").execute().unwrap();
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// ```
|
|
|
|
|
///
|
2025-09-30 07:21:26 +00:00
|
|
|
/// ### Running Specific Test Files
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// // Run only specific test files instead of all .txt files
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .files(["hello.txt", "exists.txt"])
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
2025-09-27 19:03:10 +00:00
|
|
|
/// ### With Custom Setup and Work Directory Preservation
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
2025-09-26 18:41:14 -04:00
|
|
|
///
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .setup(|env| {
|
|
|
|
|
/// // Compile your CLI tool
|
|
|
|
|
/// std::process::Command::new("cargo")
|
|
|
|
|
/// .args(["build", "--bin", "my-cli"])
|
|
|
|
|
/// .status()
|
|
|
|
|
/// .expect("Failed to build");
|
|
|
|
|
/// Ok(())
|
|
|
|
|
/// })
|
|
|
|
|
/// .command("my-cmd", |_env, _args| {
|
|
|
|
|
/// // Custom command implementation
|
|
|
|
|
/// Ok(())
|
|
|
|
|
/// })
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// .condition("custom", my_custom_check())
|
2025-09-27 19:03:10 +00:00
|
|
|
/// .preserve_work_on_failure(true) // Preserve work directory on test failure
|
2025-09-26 18:41:14 -04:00
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
///
|
|
|
|
|
/// fn my_custom_check() -> bool {
|
|
|
|
|
/// // Your custom condition logic
|
|
|
|
|
/// true
|
|
|
|
|
/// }
|
2025-09-26 18:41:14 -04:00
|
|
|
/// ```
|
2025-09-30 06:57:10 +00:00
|
|
|
///
|
|
|
|
|
/// ### With Custom Work Directory Root
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// // Use a custom location for test working directories
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .workdir_root("/tmp/my-app-tests")
|
|
|
|
|
/// .preserve_work_on_failure(true) // Combine features
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
/// ```
|
2025-09-26 18:41:14 -04:00
|
|
|
pub struct Builder {
|
|
|
|
|
dir: String,
|
2025-09-26 21:17:45 -04:00
|
|
|
params: RunParams,
|
2025-09-26 18:41:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Builder {
|
|
|
|
|
/// Create a new builder for the given test directory
|
|
|
|
|
fn new(dir: impl Into<String>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
dir: dir.into(),
|
2025-09-26 21:17:45 -04:00
|
|
|
params: RunParams::new(),
|
2025-09-26 18:41:14 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Add a setup function that runs before each test script
|
|
|
|
|
///
|
|
|
|
|
/// The setup function receives a reference to the test environment and can
|
|
|
|
|
/// perform actions like compiling binaries or setting up test data.
|
|
|
|
|
pub fn setup<F>(mut self, func: F) -> Self
|
|
|
|
|
where
|
|
|
|
|
F: Fn(&TestEnvironment) -> Result<()> + 'static,
|
|
|
|
|
{
|
|
|
|
|
self.params = self.params.setup(func);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Add a custom command that can be used in test scripts
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * `name` - The command name as it will appear in test scripts
|
|
|
|
|
/// * `func` - The function to execute when the command is called
|
|
|
|
|
pub fn command(mut self, name: &str, func: CommandFn) -> Self {
|
|
|
|
|
self.params = self.params.command(name, func);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set a condition value for conditional command execution
|
|
|
|
|
///
|
Add network and advanced condition support with automatic detection and CI optimization (#21)
## Add Network and Advanced Condition Support with Automatic Detection -
COMPLETE ✅
This PR implements comprehensive network and advanced condition support
for testscript-rs, bringing feature parity with Go's testscript package
with automatic detection like the original.
### Core Features Implemented ✨
#### 1. **Network Conditions (`[net]`) - Always Available &
CI-Optimized**
- Auto-detects network availability with CI-optimized approach:
- **TCP-first detection**: Tries TCP connection to DNS servers (faster
than ping)
- **Ping fallback**: Uses ping with shorter timeouts if TCP fails
- Cross-platform implementation optimized for CI environments
- Available by default like Go testscript - no manual setup required
- Can be used in test scripts as `[net]` for network-required tests or
`[!net]` to skip when offline
#### 2. **Environment Variable Conditions (`[env:VAR]`)**
- Dynamic condition checking for environment variables at execution time
- No pre-registration required - conditions are evaluated when
encountered
- Supports negation: `[!env:MISSING_VAR]` to test when variables are not
set
- Perfect for CI-specific tests: `[env:CI] exec deploy --dry-run`
#### 3. **Optimized Program Detection - Built-in Like Go**
- **15+ essential programs detected automatically** including:
- **Basic commands**: cat, echo, ls, mkdir, rm, cp, mv, grep, find
- **Core development tools**: git, make, curl, python, node, docker
- **System tools**: sleep, true, false, sh
- Cross-platform program existence checking (uses `where` on Windows,
`which` on Unix)
- Optimized for CI performance with reduced startup time
- No manual configuration needed - works exactly like Go testscript
### API Simplification
**Simple, Go-like API** - everything detected automatically:
```rust
testscript::run("testdata")
.execute() // Network + 15+ programs detected automatically
.unwrap();
```
**Manual conditions still supported** for custom scenarios:
```rust
testscript::run("testdata")
.condition("custom", my_custom_check())
.execute()
.unwrap();
```
### CI Optimization
- **Network detection**: TCP-first approach with 500ms timeouts (vs
1000ms+ ping)
- **Program list**: Optimized from 35+ to 15+ essential programs for
faster startup
- **Better reliability**: Handles restricted CI network environments
- **Ubuntu CI compatibility**: Resolved timeout and network access
issues
### Real-World Use Cases
This enables powerful testing scenarios that work out of the box:
```
# Network-dependent API tests (automatic detection, CI-optimized)
[net] exec curl https://api.example.com/health
[net] stdout "OK"
# Tool-specific tests (automatic detection)
[exec:docker] exec docker run --rm hello-world
[exec:docker] stdout "Hello from Docker!"
[exec:git] exec git status
[exec:python] exec python --version
# Environment-based behavior
[env:CI] exec deploy --dry-run --verbose
[!env:PRODUCTION] exec run-dangerous-test
# Platform + environment combinations
[unix] [env:DISPLAY] exec gui-test --headless
[windows] [exec:powershell] exec Get-Process
```
### Implementation Details
- **Network detection**: Multi-approach detection (TCP + ping fallback)
optimized for CI reliability
- **Program detection**: Essential program list covering most common
development tools
- **Dynamic evaluation**: Environment conditions are checked at
execution time, not initialization
- **Error handling**: Clear error messages for unknown conditions
- **Cross-platform**: Works consistently across Windows, macOS, and
Linux with CI optimizations
### Go Testscript Compatibility ✅
This implementation now matches Go testscript's behavior:
- All common conditions available by default without setup
- Network condition automatically detected with CI optimization
- Essential program detection built-in with performance focus
- Clean, simple API that "just works"
- Environment variable conditions work dynamically
- CI-friendly performance characteristics
### Testing
Added comprehensive test coverage with 7 new test cases covering:
- Network condition detection (automatic, CI-optimized)
- Environment variable condition parsing and evaluation
- Optimized program detection (automatic)
- Condition combination scenarios
- Cross-platform compatibility
- Helper function validation
All existing tests continue to pass (47 total), ensuring no regressions.
### Backward Compatibility
This is a purely additive change. All existing functionality is
preserved:
- Platform conditions (`[unix]`, `[windows]`, `[linux]`, `[darwin]`)
- Build type conditions (`[debug]`, `[release]`)
- Manual `.condition()` API still works for custom conditions
- All existing test scripts continue to work unchanged
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT SUFFIX -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>Add network and advanced condition support</issue_title>
> <issue_description>## Feature Request: Advanced Condition Support
>
> Go's testscript supports advanced conditions beyond platform
detection:
>
> ## Missing Conditions
>
> 1. **Network conditions**: `[net]` - Test network availability
> 2. **Advanced platform conditions**: More granular OS/arch detection
> 3. **Environment-based conditions**: Custom environment variable
conditions
>
> ## Proposed API
>
> ```rust
> testscript::run("testdata")
> .condition("net", check_network_available())
> .condition("docker", command_exists("docker"))
> .condition("env:CI", std::env::var("CI").is_ok())
> .execute()
> .unwrap();
> ```
>
> ## Built-in Condition Helpers
>
> ```rust
> // Automatic network detection
> testscript::run("testdata")
> .auto_detect_network()
> .auto_detect_programs(&["docker", "git", "npm"])
> .execute()
> .unwrap();
> ```
>
> ## Implementation Notes
>
> - Network detection could ping a reliable host
> - Program detection should use cross-platform approach (not just
`which`)
> - Environment conditions could support pattern matching
> - Consider caching condition results for performance
>
> ## Use Cases
>
> - **Docker tests**: `[docker] exec docker run hello-world`
> - **Network tests**: `[net] exec curl example.com`
> - **CI-specific tests**: `[env:CI] exec deploy
--dry-run`</issue_description>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> </comments>
>
</details>
Fixes imjasonh/testscript-rs#10
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Signed-off-by: Jason Hall <jason@chainguard.dev>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
Co-authored-by: Jason Hall <jason@chainguard.dev>
2025-09-27 17:00:36 +00:00
|
|
|
/// Use this to add custom conditions beyond the built-in ones.
|
|
|
|
|
/// Many common conditions are automatically detected (see Builder docs for details).
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * `name` - The condition name (use in scripts as `[name]`)
|
|
|
|
|
/// * `value` - Whether the condition is met
|
|
|
|
|
///
|
|
|
|
|
/// # Built-in Conditions (automatically available)
|
|
|
|
|
/// - `net` - Network connectivity
|
|
|
|
|
/// - `unix`, `windows`, `linux`, `darwin` - Platform detection
|
|
|
|
|
/// - `debug`, `release` - Build type
|
|
|
|
|
/// - `exec:program` - Program availability (35+ programs)
|
|
|
|
|
/// - `env:VAR` - Environment variables (dynamic)
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .condition("feature_enabled", cfg!(feature = "advanced"))
|
|
|
|
|
/// .condition("has_gpu", check_gpu_available())
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
///
|
|
|
|
|
/// fn check_gpu_available() -> bool {
|
|
|
|
|
/// // Your GPU detection logic
|
|
|
|
|
/// false
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
2025-09-26 18:41:14 -04:00
|
|
|
pub fn condition(mut self, name: &str, value: bool) -> Self {
|
|
|
|
|
self.params = self.params.condition(name, value);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-26 21:47:09 -04:00
|
|
|
/// Enable or disable updating test scripts with actual output
|
|
|
|
|
///
|
|
|
|
|
/// When enabled, instead of failing on output mismatches, the test files
|
|
|
|
|
/// will be updated with the actual command output.
|
|
|
|
|
pub fn update_scripts(mut self, update: bool) -> Self {
|
|
|
|
|
self.params = self.params.update_scripts(update);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-27 19:03:10 +00:00
|
|
|
/// Enable or disable preserving working directories when tests fail
|
|
|
|
|
///
|
|
|
|
|
/// When enabled, if a test fails, the working directory will be preserved
|
|
|
|
|
/// and its path will be printed to stderr for debugging purposes.
|
|
|
|
|
/// This matches the behavior of Go's testscript TestWork functionality.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .preserve_work_on_failure(true)
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// When a test fails, you'll see output like:
|
|
|
|
|
/// ```text
|
|
|
|
|
/// Test failed. Work directory preserved at: /tmp/testscript-work-abc123
|
|
|
|
|
/// You can inspect the test environment:
|
|
|
|
|
/// cd /tmp/testscript-work-abc123
|
|
|
|
|
/// ls -la
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn preserve_work_on_failure(mut self, preserve: bool) -> Self {
|
|
|
|
|
self.params = self.params.preserve_work_on_failure(preserve);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-30 06:57:10 +00:00
|
|
|
/// Set the root directory for test working directories
|
|
|
|
|
///
|
|
|
|
|
/// When specified, test directories will be created inside this root directory
|
|
|
|
|
/// instead of the system default temporary directory. This is useful for:
|
|
|
|
|
/// - **Debugging**: Use a known location for test directories
|
|
|
|
|
/// - **Performance**: Use faster storage (e.g., tmpfs on Linux)
|
|
|
|
|
/// - **CI environments**: Use specific temp locations
|
|
|
|
|
/// - **Security**: Isolate test directories to specific paths
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * `root` - The directory path where test working directories should be created
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// // Use custom location for test directories
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .workdir_root("/tmp/my-app-tests")
|
|
|
|
|
/// .preserve_work_on_failure(true) // Combine with other features
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This creates test directories like `/tmp/my-app-tests/testscript-abc123/`.
|
|
|
|
|
///
|
|
|
|
|
/// # Notes
|
|
|
|
|
/// - The root directory must exist and be writable
|
|
|
|
|
/// - If not specified, uses the system default temporary directory
|
|
|
|
|
/// - Each test still gets its own isolated subdirectory
|
|
|
|
|
pub fn workdir_root<P: Into<std::path::PathBuf>>(mut self, root: P) -> Self {
|
|
|
|
|
self.params = self.params.workdir_root(root);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-30 07:21:26 +00:00
|
|
|
/// Run only specific test files instead of discovering all .txt files
|
|
|
|
|
///
|
|
|
|
|
/// When specified, only these files will be executed instead of discovering
|
|
|
|
|
/// all .txt files in the directory. Files can be specified as:
|
|
|
|
|
/// - Relative paths (relative to the test directory): `"hello.txt"`
|
|
|
|
|
/// - Absolute paths: `"/path/to/test.txt"`
|
|
|
|
|
/// - Just filenames: `"test.txt"` (looked up in the test directory)
|
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
/// * `files` - An iterator of file paths to run
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// // Run specific test files
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .files(["hello.txt", "exists.txt"])
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
///
|
|
|
|
|
/// // Using Vec<String>
|
|
|
|
|
/// let test_files = vec!["hello.txt".to_string(), "exists.txt".to_string()];
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .files(test_files)
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Benefits
|
|
|
|
|
/// - **Selective testing**: Run only specific test scenarios
|
|
|
|
|
/// - **Faster development**: Skip unrelated tests during development
|
|
|
|
|
/// - **CI optimization**: Run subsets of tests in different jobs
|
|
|
|
|
/// - **Go compatibility**: Match Go testscript functionality
|
|
|
|
|
pub fn files<I, S>(mut self, files: I) -> Self
|
|
|
|
|
where
|
|
|
|
|
I: IntoIterator<Item = S>,
|
|
|
|
|
S: Into<String>,
|
|
|
|
|
{
|
|
|
|
|
self.params = self.params.files(files);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-26 18:41:14 -04:00
|
|
|
/// Execute all test scripts in the configured directory
|
|
|
|
|
///
|
|
|
|
|
/// This will discover all `.txt` files in the directory and run them as test scripts.
|
|
|
|
|
/// Each test runs in isolation with its own temporary directory.
|
|
|
|
|
///
|
|
|
|
|
/// # Returns
|
|
|
|
|
/// `Ok(())` if all tests pass, or the first error encountered.
|
|
|
|
|
pub fn execute(mut self) -> Result<()> {
|
|
|
|
|
let pattern = format!("{}/*.txt", self.dir);
|
|
|
|
|
run(&mut self.params, &pattern)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create a new testscript builder for the given directory
|
|
|
|
|
///
|
|
|
|
|
/// This is the main entry point for running testscript tests.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// use testscript_rs::testscript;
|
|
|
|
|
///
|
|
|
|
|
/// // Run all tests in testdata directory
|
|
|
|
|
/// testscript::run("testdata").execute().unwrap();
|
2025-09-30 07:21:26 +00:00
|
|
|
///
|
|
|
|
|
/// // Run only specific test files
|
|
|
|
|
/// testscript::run("testdata")
|
|
|
|
|
/// .files(["hello.txt", "exists.txt"])
|
|
|
|
|
/// .execute()
|
|
|
|
|
/// .unwrap();
|
2025-09-26 18:41:14 -04:00
|
|
|
/// ```
|
|
|
|
|
pub mod testscript {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
/// Create a new testscript builder for the given directory
|
|
|
|
|
pub fn run(dir: impl Into<String>) -> Builder {
|
|
|
|
|
Builder::new(dir)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn basic_integration_test() {
|
|
|
|
|
// Test the parser directly with a simple script
|
|
|
|
|
let script_content = r#"exec echo hello
|
|
|
|
|
stdout hello
|
|
|
|
|
|
|
|
|
|
-- file.txt --
|
|
|
|
|
content"#;
|
|
|
|
|
|
|
|
|
|
let script = crate::parser::parse(script_content).unwrap();
|
|
|
|
|
assert_eq!(script.commands.len(), 2);
|
|
|
|
|
assert_eq!(script.files.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_example() {
|
|
|
|
|
use std::fs;
|
|
|
|
|
use tempfile::TempDir;
|
|
|
|
|
|
|
|
|
|
let temp_dir = TempDir::new().unwrap();
|
|
|
|
|
let testdata_dir = temp_dir.path().join("testdata");
|
|
|
|
|
fs::create_dir(&testdata_dir).unwrap();
|
|
|
|
|
|
|
|
|
|
let test_content = r#"exec echo "API works!"
|
|
|
|
|
stdout "API works!"
|
|
|
|
|
|
|
|
|
|
-- test.txt --
|
|
|
|
|
content"#;
|
|
|
|
|
|
|
|
|
|
fs::write(testdata_dir.join("api_test.txt"), test_content).unwrap();
|
|
|
|
|
|
|
|
|
|
let result = testscript::run(testdata_dir.to_string_lossy()).execute();
|
|
|
|
|
assert!(result.is_ok(), "API example failed: {:?}", result);
|
|
|
|
|
}
|
|
|
|
|
}
|