goldentests 1.4.1

A golden file testing library where tests can be configured within the same test file
Documentation
mod config;
mod config_file;
mod diff_printer;
mod error;
mod runner;

use crate::config::TestConfig;
use clap::Parser;
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
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, 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 '// '"
    )]
    test_prefix: String,

    #[clap(
        long,
        default_value = "args:",
        help = "Prefix string for the command line arguments to be passed to the command, before the program file path."
    )]
    args_prefix: String,

    #[clap(
        long,
        default_value = "args after:",
        help = "Prefix string for the command line arguments to be passed to the command, after the program file path."
    )]
    args_after_prefix: String,

    #[clap(
        long,
        default_value = "expected stdout:",
        help = "The program to run for each test file"
    )]
    stdout_prefix: String,

    #[clap(
        long,
        default_value = "expected stderr:",
        help = "The program to run for each test file"
    )]
    stderr_prefix: String,

    #[clap(
        long,
        default_value = "expected exit status:",
        help = "The program to run for each test file"
    )]
    exit_status_prefix: String,

    #[clap(
        long,
        default_value = "",
        help = "Arguments to add before the file name when running every test file"
    )]
    base_args: String,

    #[clap(
        long,
        default_value = "",
        help = "Arguments to add after the file name when running every test file"
    )]
    base_args_after: String,

    #[clap(flatten)]
    cli_args: CliOnlyArgs,

    #[cfg(feature = "parallel")]
    #[clap(short, long, help = "Number of max. parallel jobs")]
    jobs: Option<usize>,
}

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct CliOnlyArgs {
    #[clap(
        long,
        help = "Update the expected output of each test file to match the actual output"
    )]
    overwrite: bool,
}

fn main() {
    let mut config = match config_file::read_config_file(None) {
        Some(mut config) => {
            let args = CliOnlyArgs::parse();
            config.overwrite_tests = args.overwrite;
            config
        }
        None => {
            let args = Args::parse();

            #[cfg(feature = "parallel")]
            if let Some(max_jobs) = args.jobs {
                rayon::ThreadPoolBuilder::new().num_threads(max_jobs).build_global().unwrap();
            }

            Args::parse().into_test_config()
        }
    };

    let test_line_prefix = config.test_line_prefix.to_string();
    let prefixed = |s| format!("{}{}", test_line_prefix, s);
    config.test_args_prefix = prefixed(config.test_args_prefix);
    config.test_args_after_prefix = prefixed(config.test_args_after_prefix);
    config.test_stdout_prefix = prefixed(config.test_stdout_prefix);
    config.test_stderr_prefix = prefixed(config.test_stderr_prefix);
    config.test_exit_status_prefix = prefixed(config.test_exit_status_prefix);

    config.run_tests().unwrap_or_else(|_| std::process::exit(1));
}

impl Args {
    fn into_test_config(self) -> TestConfig {
        TestConfig {
            binary_path: self.binary_path,
            test_path: self.test_path,
            test_line_prefix: self.test_prefix,
            test_args_prefix: self.args_prefix,
            test_args_after_prefix: self.args_after_prefix,
            test_stdout_prefix: self.stdout_prefix,
            test_stderr_prefix: self.stderr_prefix,
            test_exit_status_prefix: self.exit_status_prefix,
            overwrite_tests: self.cli_args.overwrite,
            base_args: self.base_args,
            base_args_after: self.base_args_after,
        }
    }
}