From fe0cd8ccecef9e62d4c51f7619c312c69817f799 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Fri, 25 Nov 2022 08:40:36 -0800 Subject: [PATCH] Configure cargo args --- Cargo.toml | 1 + NEWS.md | 4 +- README.md | 6 ++- src/config.rs | 4 ++ src/options.rs | 14 ++++- .../tree/fails_without_feature/Cargo.toml | 16 ++++++ testdata/tree/fails_without_feature/README.md | 5 ++ .../src/bin/factorial.rs | 27 ++++++++++ tests/cli/config.rs | 53 +++++++++++++++++++ ...li__list_mutants_in_all_trees_as_json.snap | 15 ++++++ ...li__list_mutants_in_all_trees_as_text.snap | 6 +++ 11 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 testdata/tree/fails_without_feature/Cargo.toml create mode 100644 testdata/tree/fails_without_feature/README.md create mode 100644 testdata/tree/fails_without_feature/src/bin/factorial.rs diff --git a/Cargo.toml b/Cargo.toml index 68eb0f8a..9fcac345 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ exclude = [ "testdata/tree/dependency", "testdata/tree/everything_skipped", "testdata/tree/factorial", + "testdata/tree/fails_without_feature", "testdata/tree/hang_avoided_by_attr/", "testdata/tree/hang_when_mutated", "testdata/tree/insta", diff --git a/NEWS.md b/NEWS.md index ebe23081..f5ba922d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,8 +7,8 @@ - Fixed: `--exclude-re` and `--re` can match against the return type as shown in `--list`. -- New: a `.cargo/mutants.toml` file can be used to configure standard filters - for a project. +- New: A `.cargo/mutants.toml` file can be used to configure standard filters + and cargo args for a project. ## 1.1.1 diff --git a/README.md b/README.md index 811e92ef..31a696ed 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,8 @@ flags the function for cargo-mutants. cargo-mutants looks for a `.cargo/mutants.toml` file in the root of the source directory. If a config file exists, the values are appended to the corresponding -command-line arguments. +command-line arguments. (This may cause problems if you use `--` twice on the +command line to pass arguments to the inner test binary.) Configured exclusions may be particularly important when there are modules that are inherently hard to test, and the project has made a decision to accept lower @@ -232,6 +233,9 @@ examine_globs = ["src/important/*.rs"] # same as -f, test *only* these files exclude_re = ["impl Debug"] # same as -E examine_re = ["impl Serialize", "impl Deserialize"] # same as -F, test *only* matches + +additional_cargo_args = ["--all-features"] +additional_cargo_test_args = ["--jobs=1"] ``` ### Exit codes diff --git a/src/config.rs b/src/config.rs index 35966836..d31a38a3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,6 +33,10 @@ pub struct Config { pub exclude_re: Vec, /// Examine only mutants matching these regexps. pub examine_re: Vec, + /// Pass extra args to every cargo invocation. + pub additional_cargo_args: Vec, + /// Pass extra args to cargo test. + pub additional_cargo_test_args: Vec, } impl Config { diff --git a/src/options.rs b/src/options.rs index 65720e7e..e1546ad1 100644 --- a/src/options.rs +++ b/src/options.rs @@ -74,8 +74,18 @@ impl Options { } Ok(Options { - additional_cargo_args: args.cargo_arg.clone(), - additional_cargo_test_args: args.cargo_test_args.clone(), + additional_cargo_args: args + .cargo_arg + .iter() + .cloned() + .chain(config.additional_cargo_args.iter().cloned()) + .collect(), + additional_cargo_test_args: args + .cargo_test_args + .iter() + .cloned() + .chain(config.additional_cargo_test_args.iter().cloned()) + .collect(), check_only: args.check, examine_names: Some( RegexSet::new(args.examine_re.iter().chain(config.examine_re.iter())) diff --git a/testdata/tree/fails_without_feature/Cargo.toml b/testdata/tree/fails_without_feature/Cargo.toml new file mode 100644 index 00000000..18011329 --- /dev/null +++ b/testdata/tree/fails_without_feature/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "cargo-mutants-testdata-fails-without-feature" +version = "0.0.0" +edition = "2021" +authors = ["Martin Pool"] +publish = false + +[dependencies.mutants] +version = "0.0.3" + +[features] +needed = [] + +[[bin]] +name = "factorial" +doctest = false diff --git a/testdata/tree/fails_without_feature/README.md b/testdata/tree/fails_without_feature/README.md new file mode 100644 index 00000000..581086f6 --- /dev/null +++ b/testdata/tree/fails_without_feature/README.md @@ -0,0 +1,5 @@ +# `fails_without_feature` + +The crates for this test fail unless a feature is turned on. + +(Not a good style perhaps, but a good way to test that Cargo features can be passed through.) diff --git a/testdata/tree/fails_without_feature/src/bin/factorial.rs b/testdata/tree/fails_without_feature/src/bin/factorial.rs new file mode 100644 index 00000000..6051cb23 --- /dev/null +++ b/testdata/tree/fails_without_feature/src/bin/factorial.rs @@ -0,0 +1,27 @@ +#[mutants::skip] +fn main() { + for i in 1..=6 { + println!("{}! = {}", i, factorial(i)); + } +} + +#[cfg(feature = "needed")] +fn factorial(n: u32) -> u32 { + let mut a = 1; + for i in 2..=n { + a *= i; + } + a +} + +#[cfg(not(feature = "needed"))] +#[mutants::skip] +fn factorial(_n: u32) -> u32 { + panic!("needed feature is not enabled"); +} + +#[test] +fn test_factorial() { + println!("factorial({}) = {}", 6, factorial(6)); // This line is here so we can see it in --nocapture + assert_eq!(factorial(6), 720); +} diff --git a/tests/cli/config.rs b/tests/cli/config.rs index 55e5d199..f20ee6bf 100644 --- a/tests/cli/config.rs +++ b/tests/cli/config.rs @@ -119,3 +119,56 @@ fn list_with_config_file_regexps() { "src/simple_fns.rs:17: replace divisible_by_three -> bool with false\n", )); } + +#[test] +fn tree_fails_without_needed_feature() { + // The point of this tree is to check that Cargo features can be turned on, + // but let's make sure it does fail as intended if they're not. + let testdata = copy_of_testdata("fails_without_feature"); + run_assert_cmd() + .args(["mutants", "-d"]) + .arg(testdata.path()) + .assert() + .failure() + .stdout(predicates::str::contains( + "test failed in an unmutated tree", + )); +} + +#[test] +fn additional_cargo_args() { + // The point of this tree is to check that Cargo features can be turned on, + // but let's make sure it does fail as intended if they're not. + let testdata = copy_of_testdata("fails_without_feature"); + write_config_file( + &testdata, + r#" + additional_cargo_args = ["--features", "needed"] + "#, + ); + run_assert_cmd() + .args(["mutants", "-d"]) + .arg(testdata.path()) + .assert() + .success() + .stdout(predicates::str::contains("1 caught")); +} + +#[test] +fn additional_cargo_test_args() { + // The point of this tree is to check that Cargo features can be turned on, + // but let's make sure it does fail as intended if they're not. + let testdata = copy_of_testdata("fails_without_feature"); + write_config_file( + &testdata, + r#" + additional_cargo_test_args = ["--all-features", ] + "#, + ); + run_assert_cmd() + .args(["mutants", "-d"]) + .arg(testdata.path()) + .assert() + .success() + .stdout(predicates::str::contains("1 caught")); +} diff --git a/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_json.snap b/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_json.snap index e44cd428..621e309d 100644 --- a/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_json.snap +++ b/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_json.snap @@ -127,6 +127,21 @@ expression: buf ] ``` +## testdata/tree/fails_without_feature + +```json +[ + { + "package": "cargo-mutants-testdata-fails-without-feature", + "file": "src/bin/factorial.rs", + "line": 9, + "function": "factorial", + "return_type": "-> u32", + "replacement": "Default::default()" + } +] +``` + ## testdata/tree/hang_avoided_by_attr ```json diff --git a/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_text.snap b/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_text.snap index 57b24225..ff9b45da 100644 --- a/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_text.snap +++ b/tests/cli/snapshots/cli__list_mutants_in_all_trees_as_text.snap @@ -55,6 +55,12 @@ src/bin/factorial.rs:1: replace main with () src/bin/factorial.rs:7: replace factorial -> u32 with Default::default() ``` +## testdata/tree/fails_without_feature + +``` +src/bin/factorial.rs:9: replace factorial -> u32 with Default::default() +``` + ## testdata/tree/hang_avoided_by_attr ```