Skip to content

Commit

Permalink
Allow testing a single file
Browse files Browse the repository at this point in the history
Update the file path argument handling to allow testing a single file.

Error checking during config generation is removed, as we have to check
for missing file/directory errors anyway while running the tests, and
checking the files ahead of time isn't that useful as the file or
directory can disappear between the config generation and running the
tests.
  • Loading branch information
osa1 committed Nov 9, 2024
1 parent 35ff2c4 commit 643d56e
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 95 deletions.
52 changes: 18 additions & 34 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::error::{TestError, TestResult};
use colored::Colorize;
use std::path::PathBuf;

pub struct TestConfig {
/// The binary path to your program, typically "target/debug/myprogram"
pub binary_path: PathBuf,

/// The path to the subdirectory containing your tests. This subdirectory will be
/// searched recursively for all files.
/// The path to the directory containing your tests, or a single test file.
///
/// If this is a directory, it will be searched recursively for all files.
pub test_path: PathBuf,

/// The sequence of characters starting at the beginning of a line that
Expand Down Expand Up @@ -112,7 +111,7 @@ impl TestConfig {
/// If you want to change these default keywords you can also create a TestConfig
/// via `TestConfig::with_custom_keywords` which will allow you to specify each.
#[allow(unused)]
pub fn new<Binary, Tests>(binary_path: Binary, test_path: Tests, test_line_prefix: &str) -> TestResult<TestConfig>
pub fn new<Binary, Tests>(binary_path: Binary, test_path: Tests, test_line_prefix: &str) -> TestConfig
where
Binary: Into<PathBuf>,
Tests: Into<PathBuf>,
Expand Down Expand Up @@ -145,41 +144,26 @@ impl TestConfig {
test_stderr_prefix: &str,
test_exit_status_prefix: &str,
overwrite_tests: bool,
) -> TestResult<TestConfig>
) -> TestConfig
where
Binary: Into<PathBuf>,
Tests: Into<PathBuf>,
{
let (binary_path, test_path) = (binary_path.into(), test_path.into());

if !test_path.exists() {
eprintln!(
"{}",
format!("the given test path '{}' does not exist", test_path.display()).red()
);

Err(TestError::MissingTests(test_path))
} else if !test_path.is_dir() {
eprintln!(
"{}",
format!("the given test path '{}' is not a directory", test_path.display()).red()
);
let binary_path = binary_path.into();
let test_path = test_path.into();

Err(TestError::ExpectedDirectory(test_path))
} else {
let test_line_prefix = test_line_prefix.to_string();
let prefixed = |s| format!("{}{}", test_line_prefix, s);
let test_line_prefix = test_line_prefix.to_string();
let prefixed = |s| format!("{}{}", test_line_prefix, s);

Ok(TestConfig {
binary_path,
test_path,
test_args_prefix: prefixed(test_args_prefix),
test_stdout_prefix: prefixed(test_stdout_prefix),
test_stderr_prefix: prefixed(test_stderr_prefix),
test_exit_status_prefix: prefixed(test_exit_status_prefix),
test_line_prefix,
overwrite_tests,
})
TestConfig {
binary_path,
test_path,
test_args_prefix: prefixed(test_args_prefix),
test_stdout_prefix: prefixed(test_stdout_prefix),
test_stderr_prefix: prefixed(test_stderr_prefix),
test_exit_status_prefix: prefixed(test_exit_status_prefix),
test_line_prefix,
overwrite_tests,
}
}
}
26 changes: 1 addition & 25 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,9 @@
use std::error::Error;
use std::fmt;
use std::path::PathBuf;

use colored::Colorize;

pub type TestResult<T> = Result<T, TestError>;

#[derive(Debug)]
pub enum TestError {
MissingTests(PathBuf),
ExpectedDirectory(PathBuf),
TestErrors,
}

impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TestError::*;
match self {
TestErrors => f.write_str("The expected test output differs"),
MissingTests(path) => write!(f, "Failed to locate test files {}", path.display()),
ExpectedDirectory(path) => {
let msg = "The path given for test files should be a directory ";
write!(f, "{}{}", msg, path.display())
}
}
}
}

impl Error for TestError {}
pub type TestResult<T> = Result<T, ()>;

// Inner test errors shouldn't be visible to the end-user,
// they'll all be reported internally after running the tests
Expand Down
16 changes: 5 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ struct Args {
#[clap(help = "The program to run for each test file")]
binary_path: PathBuf,

#[clap(help = "The directory to search for test files recursively within")]
test_directory: PathBuf,
#[clap(help = "The directory to search for test files recursively within, or a single file to test")]
test_path: PathBuf,

#[clap(
help = "Prefix string for test commands. This is usually the same as the comment syntax in the language you are testing. For example, in C this would be '// '"
Expand Down Expand Up @@ -55,22 +55,16 @@ struct Args {
fn main() {
let args = Args::parse();

let config = match TestConfig::with_custom_keywords(
let config = TestConfig::with_custom_keywords(
args.binary_path,
args.test_directory,
args.test_path,
&args.test_prefix,
&args.args_prefix,
&args.stdout_prefix,
&args.stderr_prefix,
&args.exit_status_prefix,
args.overwrite,
) {
Ok(config) => config,
Err(error) => {
eprintln!("error: {}", error);
return;
}
};
);

config.run_tests().unwrap_or_else(|_| std::process::exit(1));
}
56 changes: 32 additions & 24 deletions src/runner.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::config::TestConfig;
use crate::diff_printer::DiffPrinter;
use crate::error::{InnerTestError, TestError, TestResult};
use crate::error::{InnerTestError, TestResult};

use colored::Colorize;
use similar::TextDiff;
Expand All @@ -14,7 +14,7 @@ use rayon::iter::ParallelIterator;
use indicatif::ProgressBar;

use std::fs::File;
use std::io::{Write, Read};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Output};

Expand All @@ -36,32 +36,35 @@ enum TestParseState {
ReadingExpectedStderr,
}

/// Expects that the given directory is an existing path
fn find_tests(directory: &Path) -> (Vec<PathBuf>, Vec<InnerTestError>) {
fn find_tests(test_path: &Path) -> (Vec<PathBuf>, Vec<InnerTestError>) {
let mut tests = vec![];
let mut errors = vec![];

let read_dir = match std::fs::read_dir(directory) {
Ok(dir) => dir,
Err(err) => return (tests, vec![InnerTestError::IoError(directory.to_owned(), err)]),
};

for entry in read_dir {
let path = match entry {
Ok(entry) => entry.path(),
Err(err) => {
errors.push(InnerTestError::IoError(directory.to_owned(), err));
continue;
}
if test_path.is_dir() {
let read_dir = match std::fs::read_dir(test_path) {
Ok(dir) => dir,
Err(err) => return (tests, vec![InnerTestError::IoError(test_path.to_owned(), err)]),
};

if path.is_dir() {
let (mut more_tests, mut more_errors) = find_tests(&path);
tests.append(&mut more_tests);
errors.append(&mut more_errors);
} else {
tests.push(path);
for entry in read_dir {
let path = match entry {
Ok(entry) => entry.path(),
Err(err) => {
errors.push(InnerTestError::IoError(test_path.to_owned(), err));
continue;
}
};

if path.is_dir() {
let (mut more_tests, mut more_errors) = find_tests(&path);
tests.append(&mut more_tests);
errors.append(&mut more_errors);
} else {
tests.push(path);
}
}
} else {
tests.push(test_path.into());
}

(tests, errors)
Expand Down Expand Up @@ -152,7 +155,12 @@ fn parse_test(test_path: &Path, config: &TestConfig) -> InnerTestResult<Test> {
})
}

fn write_expected_output_for_stream(file: &mut File, prefix: &str, marker: &str, expected: &[u8]) -> std::io::Result<()> {
fn write_expected_output_for_stream(
file: &mut File,
prefix: &str,
marker: &str,
expected: &[u8],
) -> std::io::Result<()> {
// Doesn't handle \r correctly!
// Strip leading and trailing newlines from the output
let expected_stdout = String::from_utf8_lossy(expected).replace("\r", "");
Expand Down Expand Up @@ -384,7 +392,7 @@ impl TestConfig {
}

if failing_tests != 0 {
Err(TestError::TestErrors)
Err(())
} else {
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ use goldentests::{TestConfig, TestResult};

#[test]
fn run_goldentests_example() -> TestResult<()> {
let config = TestConfig::new("python", "examples", "# ")?;
let config = TestConfig::new("python", "examples", "# ");
config.run_tests()
}

0 comments on commit 643d56e

Please sign in to comment.