1
0
Fork 0
mirror of https://github.com/imjasonh/testscript-rs synced 2026-07-08 17:16:38 +00:00
testscript-rs/tests/specific_files.rs
Copilot fd479ece24
Add support for running specific test files (#32)
Adds a new `.files()` method to the Builder API that allows running
specific test files instead of discovering all `.txt` files in a
directory. This mirrors the functionality of Go's testscript `Files`
parameter.

## New API

```rust
// Run only specific test files
testscript::run("testdata")
    .files(["hello.txt", "exists.txt"])
    .execute()
    .unwrap();

// Combine with other features
testscript::run("testdata")
    .files(["hello.txt", "exists.txt"])
    .setup(|env| { /* setup code */ Ok(()) })
    .condition("custom", true)
    .preserve_work_on_failure(true)
    .execute()
    .unwrap();
```

## Benefits

- **Selective testing**: Run only specific test scenarios during
development
- **Faster CI**: Run subsets of tests in parallel jobs
- **Go compatibility**: Matches `testscript.Run(t,
testscript.Params{Files: []string{...}})`
- **Flexible paths**: Supports relative paths, absolute paths, and
filenames

## Implementation Details

- Adds optional `files` field to `RunParams` 
- Enhances internal `run()` function to handle file lists vs glob
discovery
- Preserves execution order as specified by user
- Comprehensive error handling for missing files and invalid paths
- Full backward compatibility - existing code unchanged

## Path Support

```rust
testscript::run("testdata")
    .files([
        "hello.txt",              // filename in testdata dir
        "subdir/nested.txt",      // relative path  
        "/abs/path/to/test.txt"   // absolute path
    ])
    .execute()
    .unwrap();
```

The feature includes focused test coverage with 7 test cases covering
essential scenarios including error conditions and path types. Based on
feedback, redundant tests were removed to maintain a clean and
meaningful test suite.

Fixes imjasonh/testscript-rs#7

<!-- START COPILOT CODING AGENT SUFFIX -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Add support for running specific test files</issue_title>
> <issue_description>## Feature Request: Run Specific Test Files
> 
> Go's testscript supports running specific files via the `Files`
parameter:
> 
> ```go
> testscript.Run(t, testscript.Params{
>     Files: []string{"specific_test.txt", "another_test.txt"},
> })
> ```
> 
> ## Proposed API
> 
> ```rust
> testscript::run("testdata")
>     .files(&["hello.txt", "exists.txt"])
>     .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
> 
> ## Implementation
> 
> - Extend the Builder API with a `.files()` method
> - Create a separate `run_files()` entry point
> - Support both absolute and relative paths
> - Validate that specified files exist</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>
Fixes imjasonh/testscript-rs#7

<!-- START COPILOT CODING AGENT TIPS -->
---

 Let Copilot coding agent [set things up for
you](https://github.com/imjasonh/testscript-rs/issues/new?title=+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

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-30 03:36:07 -04:00

172 lines
5.1 KiB
Rust

//! Tests for running specific test files functionality
use std::fs;
use tempfile::TempDir;
use testscript_rs::testscript;
#[test]
fn test_files_basic_functionality() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Create multiple test files
let hello_content = r#"exec echo "Hello"
stdout "Hello"
"#;
let exists_content = r#"exists test_file.txt
-- test_file.txt --
content"#;
let skip_content = r#"skip 'This test should be skipped'
exec echo "This should not run"
exec exit 1
"#;
fs::write(testdata_dir.join("hello.txt"), hello_content).unwrap();
fs::write(testdata_dir.join("exists.txt"), exists_content).unwrap();
fs::write(testdata_dir.join("skip.txt"), skip_content).unwrap();
// Test running specific files (should only run hello.txt and exists.txt)
let result = testscript::run(testdata_dir.to_string_lossy())
.files(["hello.txt", "exists.txt"])
.execute();
assert!(result.is_ok(), "Specific files test failed: {:?}", result);
}
#[test]
fn test_files_with_vec_string() {
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 "Test"
stdout "Test"
"#;
fs::write(testdata_dir.join("test1.txt"), test_content).unwrap();
fs::write(testdata_dir.join("test2.txt"), test_content).unwrap();
// Test with Vec<String>
let test_files = vec!["test1.txt".to_string(), "test2.txt".to_string()];
let result = testscript::run(testdata_dir.to_string_lossy())
.files(test_files)
.execute();
assert!(
result.is_ok(),
"Vec<String> files test failed: {:?}",
result
);
}
#[test]
fn test_files_with_relative_paths() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
let subdir = testdata_dir.join("subdir");
fs::create_dir_all(&subdir).unwrap();
let test_content = r#"exec echo "Relative test"
stdout "Relative test"
"#;
fs::write(testdata_dir.join("test.txt"), test_content).unwrap();
fs::write(subdir.join("nested.txt"), test_content).unwrap();
// Test with relative paths including subdirectories
let result = testscript::run(testdata_dir.to_string_lossy())
.files(["test.txt", "subdir/nested.txt"])
.execute();
assert!(result.is_ok(), "Relative paths test failed: {:?}", result);
}
#[test]
fn test_files_with_absolute_paths() {
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 "Absolute test"
stdout "Absolute test"
"#;
let test_file = testdata_dir.join("absolute_test.txt");
fs::write(&test_file, test_content).unwrap();
// Test with absolute path
let result = testscript::run(testdata_dir.to_string_lossy())
.files([test_file.to_string_lossy().to_string()])
.execute();
assert!(result.is_ok(), "Absolute paths test failed: {:?}", result);
}
#[test]
fn test_files_nonexistent_file_error() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Test with nonexistent file
let result = testscript::run(testdata_dir.to_string_lossy())
.files(["nonexistent.txt"])
.execute();
assert!(result.is_err(), "Expected error for nonexistent file");
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains("Test file not found"),
"Error message should mention file not found: {}",
error_msg
);
}
#[test]
fn test_files_empty_list_error() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
fs::create_dir(&testdata_dir).unwrap();
// Test with empty file list
let empty_files: Vec<String> = vec![];
let result = testscript::run(testdata_dir.to_string_lossy())
.files(empty_files)
.execute();
assert!(result.is_err(), "Expected error for empty file list");
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains("No test files specified"),
"Error message should mention no files specified: {}",
error_msg
);
}
#[test]
fn test_files_directory_instead_of_file_error() {
let temp_dir = TempDir::new().unwrap();
let testdata_dir = temp_dir.path().join("testdata");
let subdir = testdata_dir.join("subdir");
fs::create_dir_all(&subdir).unwrap();
// Test with directory instead of file
let result = testscript::run(testdata_dir.to_string_lossy())
.files(["subdir"])
.execute();
assert!(
result.is_err(),
"Expected error for directory instead of file"
);
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains("Path is not a file"),
"Error message should mention path not a file: {}",
error_msg
);
}