Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add output directory config via environment variable and config file #463

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion book/src/mutants-out.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The `mutants.out` directory

A `mutants.out` directory is created in the original source directory. You can put the output directory elsewhere with the `--output` option.
A `mutants.out` directory is created in the original source directory. You can put the output directory elsewhere with the `--output` option
or using `CARGO_MUTANTS_OUTPUT` environment variable or via `output` directive in the config file.

On each run, any existing `mutants.out` is renamed to `mutants.out.old`, and any
existing `mutants.out.old` is deleted.
Expand Down
4 changes: 3 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::path::Path;
use std::str::FromStr;

use anyhow::Context;
use camino::Utf8Path;
use camino::{Utf8Path, Utf8PathBuf};
use serde::Deserialize;

use crate::options::TestTool;
Expand Down Expand Up @@ -45,6 +45,8 @@ pub struct Config {
pub additional_cargo_test_args: Vec<String>,
/// Minimum test timeout, in seconds, as a floor on the autoset value.
pub minimum_test_timeout: Option<f64>,
/// Output directory.
pub output: Option<Utf8PathBuf>,
/// Cargo profile.
pub profile: Option<String>,
/// Skip calls to functions or methods with these names.
Expand Down
7 changes: 6 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,12 @@ pub struct Args {
line_col: bool,

/// Create mutants.out within this directory.
#[arg(long, short = 'o', help_heading = "Output")]
#[arg(
long,
short = 'o',
env = "CARGO_MUTANTS_OUTPUT",
help_heading = "Output"
)]
output: Option<Utf8PathBuf>,

/// Include only mutants in code touched by this diff.
Expand Down
2 changes: 1 addition & 1 deletion src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl Options {
jobserver_tasks: args.jobserver_tasks,
leak_dirs: args.leak_dirs,
minimum_test_timeout,
output_in_dir: args.output.clone(),
output_in_dir: args.output.clone().or(config.output.clone()),
print_caught: args.caught,
print_unviable: args.unviable,
profile: args.profile.as_ref().or(config.profile.as_ref()).cloned(),
Expand Down
48 changes: 48 additions & 0 deletions tests/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,51 @@ fn additional_cargo_test_args() {
.assert()
.success();
}

#[test]
/// Set the `--output` directory via `output` config directive.
fn output_option_use_config() {
let output_tmpdir = TempDir::new().unwrap();
let output_via_config = output_tmpdir.path().join("output_via_config");
let testdata = copy_of_testdata("factorial");

let out_path_str = output_via_config
.to_string_lossy()
.escape_default()
.to_string();
write_config_file(&testdata, &format!("output = \"{out_path_str}\""));

assert!(
!testdata.path().join("mutants.out").exists(),
"mutants.out should not be in a clean copy of the test data"
);

run()
.arg("mutants")
.args(["--check", "--no-times"])
.arg("-d")
.arg(testdata.path())
.assert()
.success();

assert!(
!testdata.path().join("mutants.out").exists(),
"mutants.out should not be in the source directory"
);
let mutants_out = output_via_config.join("mutants.out");
assert!(
mutants_out.exists(),
"mutants.out is in changed `output` directory"
);
for name in [
"mutants.json",
"debug.log",
"outcomes.json",
"missed.txt",
"caught.txt",
"timeout.txt",
"unviable.txt",
] {
assert!(mutants_out.join(name).is_file(), "{name} is in mutants.out",);
}
}
40 changes: 40 additions & 0 deletions tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,46 @@ fn output_option() {
}
}

#[test]
/// Set the `--output` directory via environment variable `CARGO_MUTANTS_OUTPUT`
fn output_option_use_env() {
let tmp_src_dir = copy_of_testdata("factorial");
let output_tmpdir = TempDir::new().unwrap();
let output_via_env = output_tmpdir.path().join("output_via_env");
assert!(
!tmp_src_dir.path().join("mutants.out").exists(),
"mutants.out should not be in a clean copy of the test data"
);
run()
.env("CARGO_MUTANTS_OUTPUT", &output_via_env)
.arg("mutants")
.args(["--check", "--no-times"])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.success();
assert!(
!tmp_src_dir.path().join("mutants.out").exists(),
"mutants.out should not be in the source directory"
);
let mutants_out = output_via_env.join("mutants.out");
assert!(
mutants_out.exists(),
"mutants.out is in $CARGO_MUTANTS_OUTPUT directory"
);
for name in [
"mutants.json",
"debug.log",
"outcomes.json",
"missed.txt",
"caught.txt",
"timeout.txt",
"unviable.txt",
] {
assert!(mutants_out.join(name).is_file(), "{name} is in mutants.out",);
}
}

#[test]
fn check_succeeds_in_tree_that_builds_but_fails_tests() {
// --check doesn't actually run the tests so won't discover that they fail.
Expand Down