1
0
Fork 0
mirror of https://github.com/imjasonh/testscript-rs synced 2026-07-08 17:16:38 +00:00
testscript-rs/tests/update_scripts.rs

143 lines
4.3 KiB
Rust
Raw Permalink Normal View History

Add UpdateScripts functionality for test maintenance (#20) - [x] Analyze existing codebase structure and architecture - [x] Review test files to understand expected UpdateScripts functionality - [x] Understand current API and parameter structure - [x] Add `update_scripts` parameter to RunParams struct - [x] Add `update_scripts` method to Builder API - [x] Support UPDATE_SCRIPTS environment variable detection - [x] Implement update functionality in stdout/stderr command execution - [x] Modify output comparison to capture and update actual output when in update mode - [x] Add script file modification logic to update test files - [x] Create focused tests for update functionality - [x] Validate changes work end-to-end - [x] Update documentation in README.md - [x] Clean up temporary files - [x] Move UpdateScripts section to bottom of README per review feedback - [x] Fix code formatting issues with cargo fmt ## Implementation Summary Successfully implemented complete UpdateScripts functionality for test maintenance in testscript-rs: ### Key Features - **API support**: `.update_scripts(true)` method on Builder - **Environment variable**: `UPDATE_SCRIPTS=1` environment variable support - **Smart updating**: Only updates `stdout`/`stderr` expectations, preserves file structure - **Proper quoting**: Handles complex output with appropriate shell quoting - **Error handling**: Continues execution instead of failing in update mode ### API Usage ```rust // Via API testscript::run("testdata") .update_scripts(true) .execute() .unwrap(); // Via environment variable UPDATE_SCRIPTS=1 cargo test ``` ### Implementation Details - Added `update_scripts: bool` field to `RunParams` - Modified `run_script_impl` to collect updates instead of failing on mismatches - Implemented `apply_script_updates` function for file modification - Added comprehensive test coverage with 4 test cases - Updated README.md with usage examples (moved to bottom per review feedback) - Fixed code formatting issues identified by CI ### Testing - All existing tests continue to pass - New functionality tested via API and environment variable - Manual validation confirms proper file updating - Normal mode behavior preserved (still fails on mismatches when disabled) - Code passes formatting checks and linting The implementation matches Go's testscript behavior and provides essential test maintenance functionality. <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>Add UpdateScripts functionality for test maintenance</issue_title> > <issue_description>## Feature Request: UpdateScripts (Test Maintenance Mode) > > Go's testscript supports an `UpdateScripts` parameter that automatically updates test files with actual command output. This is invaluable for test maintenance. > > ## Proposed API > > ```rust > testscript::run("testdata") > .update_scripts(true) > .execute() > .unwrap(); > ``` > > Or via environment variable: > ```bash > UPDATE_SCRIPTS=1 cargo test > ``` > > ## How It Works > > When enabled, instead of failing on output mismatches: > 1. **Capture actual output** > 2. **Update the test file** with the actual output > 3. **Continue to next test** > > ## Example > > Before (failing test): > ``` > exec my-tool --version > stdout "my-tool 1.0" > ``` > > After running with update mode: > ``` > exec my-tool --version > stdout "my-tool 2.1.0" > ``` > > ## Benefits > > - **Easy test maintenance**: Update expected outputs after changes > - **Reduce manual work**: No hand-editing of test files > - **Go compatibility**: Matches upstream behavior > - **Development workflow**: Essential for evolving CLI tools > > ## Implementation Notes > > - Should only update `stdout`/`stderr` expectations > - Preserve comments and file structure > - Add safety checks to prevent accidental overwrites</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> Fixes imjasonh/testscript-rs#8 <!-- START COPILOT CODING AGENT TIPS --> --- 💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click [here](https://survey3.medallia.com/?EAHeSx-AP01bZqG0Ld9QLQ) to start the survey. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: imjasonh <210737+imjasonh@users.noreply.github.com>
2025-09-26 21:47:09 -04:00
//! Tests for update scripts functionality
use std::fs;
use tempfile::TempDir;
use testscript_rs::testscript;
#[test]
fn test_update_scripts_stdout() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Create a test script with incorrect expected output
let test_content = r#"exec echo "actual output"
stdout "expected output"
"#;
let test_file = testdata_dir.join("update_test.txt");
fs::write(&test_file, test_content).unwrap();
// Run with update_scripts enabled - should update the file instead of failing
let result = testscript::run(testdata_dir.to_string_lossy())
.update_scripts(true)
.execute();
assert!(result.is_ok(), "Update should succeed: {:?}", result);
// Check that the file was updated with the actual output
let updated_content = fs::read_to_string(&test_file).unwrap();
assert!(
updated_content.contains("stdout \"actual output\""),
"File should be updated with actual output, got: {}",
updated_content
);
}
#[test]
fn test_update_scripts_stderr() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Create a test script with incorrect expected stderr output
let test_content = r#"exec sh -c "echo 'error message' >&2"
stderr "wrong error message"
"#;
let test_file = testdata_dir.join("stderr_update_test.txt");
fs::write(&test_file, test_content).unwrap();
// Run with update_scripts enabled
let result = testscript::run(testdata_dir.to_string_lossy())
.update_scripts(true)
.execute();
assert!(result.is_ok(), "Update should succeed: {:?}", result);
// Check that the file was updated
let updated_content = fs::read_to_string(&test_file).unwrap();
assert!(
updated_content.contains("stderr \"error message\""),
"File should be updated with actual stderr output, got: {}",
updated_content
);
}
#[test]
fn test_update_scripts_via_env_var() {
// Ensure clean state
std::env::remove_var("UPDATE_SCRIPTS");
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Create a test script with incorrect expected output
let test_content = r#"exec echo "env test output"
stdout "wrong output"
"#;
let test_file = testdata_dir.join("env_update_test.txt");
fs::write(&test_file, test_content).unwrap();
// Set the environment variable
std::env::set_var("UPDATE_SCRIPTS", "1");
// Run without explicitly setting update_scripts - should read from env var
let result = testscript::run(testdata_dir.to_string_lossy()).execute();
// Clean up the env var immediately after the test
std::env::remove_var("UPDATE_SCRIPTS");
assert!(
result.is_ok(),
"Update via env var should succeed: {:?}",
result
);
// Check that the file was updated
let updated_content = fs::read_to_string(&test_file).unwrap();
assert!(
updated_content.contains("stdout \"env test output\""),
"File should be updated via env var, got: {}",
updated_content
);
}
#[test]
fn test_normal_mode_still_fails() {
// Ensure UPDATE_SCRIPTS env var is not set
std::env::remove_var("UPDATE_SCRIPTS");
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Create a test script with incorrect expected output
let test_content = r#"exec echo "actual output"
stdout "expected output"
"#;
let test_file = testdata_dir.join("normal_test.txt");
fs::write(&test_file, test_content).unwrap();
// Explicitly set update_scripts to false to override any env var
let result = testscript::run(testdata_dir.to_string_lossy())
.update_scripts(false)
.execute();
assert!(
result.is_err(),
"Normal mode should still fail on mismatch: {:?}",
result
);
// Check that the file was NOT updated
let content = fs::read_to_string(&test_file).unwrap();
assert_eq!(
content, test_content,
"File should not be modified in normal mode"
);
}