- [x] Add `workdir_root` field to `RunParams` struct - [x] Add `workdir_root` method to `Builder` API - [x] Modify `TestEnvironment::new()` to accept optional root directory - [x] Update `TestEnvironment::new()` to use `tempfile::TempDir::new_in()` when root is specified - [x] Add validation for root directory existence and writability - [x] Add tests for the new workdir_root functionality - [x] Update documentation and examples - [x] Address PR feedback: remove unnecessary files and improve tests - [x] Fix code formatting with cargo fmt - [x] Add rustfmt.toml configuration and update CLAUDE.md - [x] Improve basic test to verify actual workdir usage ## Recent Changes **Enhanced basic functionality test:** - Modified `test_workdir_root_basic_functionality` to induce a failure and use `preserve_work_on_failure(true)` - Test now verifies that the workdir was actually created in the custom root directory - Validates that test files exist in the preserved workdir with expected content - **Removed** redundant `test_workdir_root_with_preserve_work` test as the functionality is now covered by the improved basic test The test suite is now more meaningful and comprehensive, with 4 focused tests that provide real validation of the workdir_root functionality: - Basic functionality with actual workdir verification - Error handling for nonexistent directories - Error handling for non-directory paths - API chaining validation All tests pass and the implementation properly validates that custom workdir roots are used as expected. <!-- 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. --------- 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>
3.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
testscript-rs is a Rust crate for testing CLI tools using filesystem-based script files in the .txtar format. It mirrors the functionality of Go's github.com/rogpeppe/go-internal/testscript package.
Development Commands
# Run all tests
cargo test
# Run specific test suite
cargo test --test integration
cargo test --test builtin_commands
cargo test parser::tests::
# Run single test
cargo test test_basic_api
# Format code (always run before committing)
cargo fmt
# Check code formatting
cargo fmt --check
# Check code quality
cargo clippy --all-targets -- -D warnings
cargo check
# Build and run examples
cargo run --example test_runner
# Test the sample CLI example
cd examples/sample-cli && cargo test
Architecture
The crate is organized into three main modules that work together:
Core Modules
parser.rs - Parses .txtar format files into structured representations:
Scriptstruct contains commands and files from a test scriptCommandstruct represents individual command lines with args, conditions, negationTxtarFilerepresents file blocks embedded in the script- Handles quoted arguments, escape sequences, conditions (
[unix]), negation (!), and background processes (&)
run.rs - Execution environment and command dispatch:
TestEnvironmentmanages isolated temporary directories for each testRunParamsconfigures the test runner (internal, used by Builder)- Built-in command implementations (exec, cmp, stdout, stderr, exists, mkdir, cp, mv, rm, chmod, env, cmpenv, stdin, etc.)
- Custom command dispatch system
- Background process management
error.rs - Error types using thiserror for structured error handling
Public API
The main public API is the testscript module with a builder pattern:
testscript::run("testdata")
.setup(|env| { /* compile CLI tool */ })
.command("custom", |env, args| { /* custom logic */ })
.condition("feature", true)
.execute()
Key Implementation Details
Script Parsing: The parser handles complex .txtar format with file blocks, command parsing with proper quoting, and conditional execution markers.
Test Isolation: Each test script runs in a completely isolated temporary directory with its own environment variables and file system.
Command System: Built-in commands are implemented as methods on TestEnvironment. Custom commands are function pointers stored in a HashMap and checked before built-ins during dispatch.
Background Processes: Commands ending with & spawn processes stored in a HashMap by name, managed with wait and kill commands.
Environment Variables: Full support including $WORK (working directory), custom variables, and substitution in file comparisons (cmpenv) and output patterns.
Test Structure
tests/integration.rs- Main API tests including custom command usagetests/builtin_commands.rs- Tests for all built-in commandstests/edge_cases.rs- Parser edge cases and error conditionstests/integration_tests.rs- Original integration teststests/setup_hook.rs- Setup functionality teststestdata/- Go testscript compatibility test files (40 files from upstream)
Built-in Commands
Core: exec, cmp, stdout, stderr, cd, wait, exists, mkdir, cp, mv, rm, chmod, env, cmpenv, stdin, skip, stop, kill, unquote, grep, symlink
The command dispatch checks custom commands first, then falls back to built-ins, enabling easy extension.