1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
// Copyright 2023 Martin Pool
//! Tests for error value mutations, from `--error-value` etc.
use std::{
env,
fs::{create_dir_all, rename},
};
use indoc::indoc;
use predicates::prelude::*;
mod util;
use tempfile::TempDir;
use util::{copy_of_testdata, run};
#[test]
fn error_value_catches_untested_ok_case() {
// By default this tree should fail because it's configured to
// generate an error value, and the tests forgot to check that
// the code under test does return Ok.
let tmp = copy_of_testdata("error_value");
run()
.arg("mutants")
.args(["-v", "-V", "--no-times", "--no-shuffle"])
.arg("-d")
.arg(tmp.path())
.assert()
.code(2)
.stderr("");
}
#[test]
fn no_config_option_disables_config_file_so_error_value_is_not_generated() {
// In this case, the config file is not loaded. Error values are not
// generated by default (because we don't know what a good value for
// this tree would be), so no mutants are caught.
let tmp_src_dir = copy_of_testdata("error_value");
run()
.arg("mutants")
.args(["-v", "-V", "--no-times", "--no-shuffle", "--no-config"])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.code(0)
.stderr("")
.stdout(predicate::function(|stdout: &str| {
insta::assert_snapshot!(stdout);
true
}));
}
#[test]
fn list_mutants_with_error_value_from_command_line_list() {
// This is not a good error mutant for this tree, which uses
// anyhow, but it's a good test of the command line option.
let tmp_src_dir = copy_of_testdata("error_value");
run()
.arg("mutants")
.args([
"--no-times",
"--no-shuffle",
"--no-config",
"--list",
"--error=::eyre::eyre!(\"mutant\")",
])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.code(0)
.stderr("")
.stdout(predicate::function(|stdout: &str| {
insta::assert_snapshot!(stdout);
true
}));
}
#[test]
fn warn_if_error_value_starts_with_err() {
// Users might misunderstand what should be passed to --error,
// so give a warning.
let tmp_src_dir = copy_of_testdata("error_value");
run()
.arg("mutants")
.args([
"--no-times",
"--no-shuffle",
"--no-config",
"--list",
"--error=Err(anyhow!(\"mutant\"))",
])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.code(0)
.stderr(predicate::str::contains(
"error_value option gives the value of the error, and probably should not start with Err(: got Err(anyhow!(\"mutant\"))"
));
}
#[test]
fn warn_unresolved_module() {
let tmp_src_dir = copy_of_testdata("dangling_mod");
run()
.arg("mutants")
.args(["--no-times", "--no-shuffle", "--no-config", "--list"])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.code(0)
.stderr(predicate::str::contains(
r#"referent of mod not found definition_site="src/main.rs:3:1" mod_name=nonexistent"#,
));
}
#[test]
fn warn_module_outside_of_tree() {
// manually copy tree, so that external path still resolves correctly for `cargo`
//
// [TEMP]/dangling_mod/*
// [TEMP]/nested_mod/src/paths_in_main/a/foo.rs
//
let tree_name = "dangling_mod";
let tmp_src_dir_parent = TempDir::with_prefix("warn_module_outside_of_tree").unwrap();
let tmp_src_dir = tmp_src_dir_parent.path().join("dangling_mod");
cp_r::CopyOptions::new()
.filter(|path, _stat| {
Ok(["target", "mutants.out", "mutants.out.old"]
.iter()
.all(|p| !path.starts_with(p)))
})
.copy_tree(
std::path::Path::new("testdata").join(tree_name),
&tmp_src_dir,
)
.unwrap();
rename(
tmp_src_dir.join("Cargo_test.toml"),
tmp_src_dir.join("Cargo.toml"),
)
.unwrap();
let external_file_path = tmp_src_dir_parent
.path()
.join("nested_mod/src/paths_in_main/a");
create_dir_all(&external_file_path).unwrap();
std::fs::copy(
std::path::Path::new("testdata/nested_mod/src/paths_in_main/a/foo.rs"),
external_file_path.join("foo.rs"),
)
.unwrap();
run()
.arg("mutants")
.args(["--no-times", "--no-shuffle", "--no-config", "--list"])
.arg("-d")
.arg(tmp_src_dir)
.assert()
.code(0)
.stderr(predicate::str::contains(
r#"skipping source outside of tree: "src/../../nested_mod/src/paths_in_main/a/foo.rs""#,
));
}
#[test]
fn fail_when_error_value_does_not_parse() {
let tmp_src_dir = copy_of_testdata("error_value");
run()
.arg("mutants")
.args([
"--no-times",
"--no-shuffle",
"--no-config",
"--list",
"--error=shouldn't work",
])
.arg("-d")
.arg(tmp_src_dir.path())
.assert()
.code(1)
.stderr(predicate::str::contains(indoc! { "
Error: Failed to parse error value \"shouldn\'t work\"
Caused by:
unexpected token
"}))
.stdout(predicate::str::is_empty());
}
|