Skip to content

Commit

Permalink
Mutate assignment ops
Browse files Browse the repository at this point in the history
  • Loading branch information
sourcefrog committed Dec 17, 2023
1 parent eb9c3bf commit dbf18c9
Show file tree
Hide file tree
Showing 28 changed files with 1,112 additions and 46 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

- Improved: Better documentation about `-j`, with stronger recommendations not to set it too high.

- Mutate `+, -, *, /, %` binary ops.
- New: Mutate `+, -, *, /, %, &, ^, |, <<, >>` binary ops, and their corresponding assignment ops like `+=`.

## 23.12.1

Expand Down
4 changes: 2 additions & 2 deletions src/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ mod test {
let mutants = workspace
.mutants(&PackageFilter::All, &options, &Console::new())
.unwrap();
assert_eq!(mutants.len(), 3);
assert_eq!(mutants.len(), 5);
assert_eq!(
format!("{:#?}", mutants[0]),
indoc! {
Expand Down Expand Up @@ -332,7 +332,7 @@ mod test {
&Options::default(),
&Console::new(),
)?;
assert_eq!(mutants.len(), 3);
assert_eq!(mutants.len(), 5);

let mutated_code = mutants[0].mutated_code();
assert_eq!(mutants[0].function.as_ref().unwrap().function_name, "main");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ src/console.rs: replace Console::walk_tree_done with ()
src/console.rs: replace Console::scenario_started -> Result<()> with Ok(())
src/console.rs: replace Console::scenario_started -> Result<()> with Err(::anyhow::anyhow!("mutated!"))
src/console.rs: replace Console::scenario_finished with ()
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace += with -= in Console::scenario_finished
src/console.rs: replace += with *= in Console::scenario_finished
src/console.rs: replace || with && in Console::scenario_finished
src/console.rs: replace || with == in Console::scenario_finished
src/console.rs: replace || with != in Console::scenario_finished
Expand Down Expand Up @@ -78,6 +92,8 @@ src/console.rs: replace <impl Write for DebugLogWriter>::flush -> io::Result<()>
src/console.rs: replace <impl Write for DebugLogWriter>::flush -> io::Result<()> with Err(::anyhow::anyhow!("mutated!"))
src/console.rs: replace <impl Model for LabModel>::render -> String with String::new()
src/console.rs: replace <impl Model for LabModel>::render -> String with "xyzzy".into()
src/console.rs: replace += with -= in <impl Model for LabModel>::render
src/console.rs: replace += with *= in <impl Model for LabModel>::render
src/console.rs: replace > with == in <impl Model for LabModel>::render
src/console.rs: replace > with < in <impl Model for LabModel>::render
src/console.rs: replace > with == in <impl Model for LabModel>::render
Expand Down Expand Up @@ -146,6 +162,10 @@ src/console.rs: replace plural -> String with "xyzzy".into()
src/console.rs: replace == with != in plural
src/copy_tree.rs: replace copy_tree -> Result<TempDir> with Ok(Default::default())
src/copy_tree.rs: replace copy_tree -> Result<TempDir> with Err(::anyhow::anyhow!("mutated!"))
src/copy_tree.rs: replace += with -= in copy_tree
src/copy_tree.rs: replace += with *= in copy_tree
src/copy_tree.rs: replace += with -= in copy_tree
src/copy_tree.rs: replace += with *= in copy_tree
src/copy_tree.rs: replace copy_symlink -> Result<()> with Ok(())
src/copy_tree.rs: replace copy_symlink -> Result<()> with Err(::anyhow::anyhow!("mutated!"))
src/fnvalue.rs: replace return_type_replacements -> Vec<TokenStream> with vec![]
Expand Down Expand Up @@ -202,8 +222,12 @@ src/in_diff.rs: replace strip_patch_path -> &Utf8Path with &Default::default()
src/in_diff.rs: replace affected_lines -> Vec<usize> with vec![]
src/in_diff.rs: replace affected_lines -> Vec<usize> with vec![0]
src/in_diff.rs: replace affected_lines -> Vec<usize> with vec![1]
src/in_diff.rs: replace += with -= in affected_lines
src/in_diff.rs: replace += with *= in affected_lines
src/in_diff.rs: replace < with == in affected_lines
src/in_diff.rs: replace < with > in affected_lines
src/in_diff.rs: replace += with -= in affected_lines
src/in_diff.rs: replace += with *= in affected_lines
src/in_diff.rs: replace && with || in affected_lines
src/in_diff.rs: replace && with == in affected_lines
src/in_diff.rs: replace && with != in affected_lines
Expand All @@ -220,6 +244,8 @@ src/in_diff.rs: replace partial_new_file -> Vec<(usize, &'d str)> with vec![(0,
src/in_diff.rs: replace partial_new_file -> Vec<(usize, &'d str)> with vec![(0, "xyzzy")]
src/in_diff.rs: replace partial_new_file -> Vec<(usize, &'d str)> with vec![(1, "")]
src/in_diff.rs: replace partial_new_file -> Vec<(usize, &'d str)> with vec![(1, "xyzzy")]
src/in_diff.rs: replace += with -= in partial_new_file
src/in_diff.rs: replace += with *= in partial_new_file
src/interrupt.rs: replace install_handler with ()
src/lab.rs: replace test_mutants -> Result<LabOutcome> with Ok(Default::default())
src/lab.rs: replace test_mutants -> Result<LabOutcome> with Err(::anyhow::anyhow!("mutated!"))
Expand Down Expand Up @@ -334,6 +360,20 @@ src/outcome.rs: replace Phase::name -> &'static str with "xyzzy"
src/outcome.rs: replace <impl Display for Phase>::fmt -> fmt::Result with Ok(Default::default())
src/outcome.rs: replace <impl Display for Phase>::fmt -> fmt::Result with Err(::anyhow::anyhow!("mutated!"))
src/outcome.rs: replace LabOutcome::add with ()
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace += with -= in LabOutcome::add
src/outcome.rs: replace += with *= in LabOutcome::add
src/outcome.rs: replace LabOutcome::exit_code -> i32 with 0
src/outcome.rs: replace LabOutcome::exit_code -> i32 with 1
src/outcome.rs: replace LabOutcome::exit_code -> i32 with -1
Expand Down Expand Up @@ -427,7 +467,11 @@ src/path.rs: replace ascent -> isize with 0
src/path.rs: replace ascent -> isize with 1
src/path.rs: replace ascent -> isize with -1
src/path.rs: replace == with != in ascent
src/path.rs: replace += with -= in ascent
src/path.rs: replace += with *= in ascent
src/path.rs: replace != with == in ascent
src/path.rs: replace -= with += in ascent
src/path.rs: replace -= with /= in ascent
src/path.rs: replace > with == in ascent
src/path.rs: replace > with < in ascent
src/path.rs: replace <impl Utf8PathSlashes for Utf8Path>::to_slash_path -> String with String::new()
Expand All @@ -453,6 +497,8 @@ src/pretty.rs: replace == with != in <impl ToPrettyString for T>::to_pretty_stri
src/pretty.rs: replace || with && in <impl ToPrettyString for T>::to_pretty_string
src/pretty.rs: replace || with == in <impl ToPrettyString for T>::to_pretty_string
src/pretty.rs: replace || with != in <impl ToPrettyString for T>::to_pretty_string
src/pretty.rs: replace += with -= in <impl ToPrettyString for T>::to_pretty_string
src/pretty.rs: replace += with *= in <impl ToPrettyString for T>::to_pretty_string
src/process.rs: replace Process::run -> Result<ProcessStatus> with Ok(Default::default())
src/process.rs: replace Process::run -> Result<ProcessStatus> with Err(::anyhow::anyhow!("mutated!"))
src/process.rs: replace Process::start -> Result<Process> with Ok(Default::default())
Expand Down Expand Up @@ -523,9 +569,13 @@ src/span.rs: replace == with != in Span::extract
src/span.rs: replace < with == in Span::extract
src/span.rs: replace < with > in Span::extract
src/span.rs: replace == with != in Span::extract
src/span.rs: replace += with -= in Span::extract
src/span.rs: replace += with *= in Span::extract
src/span.rs: replace > with == in Span::extract
src/span.rs: replace > with < in Span::extract
src/span.rs: replace == with != in Span::extract
src/span.rs: replace += with -= in Span::extract
src/span.rs: replace += with *= in Span::extract
src/span.rs: replace && with || in Span::extract
src/span.rs: replace && with == in Span::extract
src/span.rs: replace && with != in Span::extract
Expand Down Expand Up @@ -565,7 +615,11 @@ src/span.rs: replace && with != in Span::replace
src/span.rs: replace == with != in Span::replace
src/span.rs: replace >= with < in Span::replace
src/span.rs: replace == with != in Span::replace
src/span.rs: replace += with -= in Span::replace
src/span.rs: replace += with *= in Span::replace
src/span.rs: replace == with != in Span::replace
src/span.rs: replace += with -= in Span::replace
src/span.rs: replace += with *= in Span::replace
src/span.rs: replace && with || in Span::replace
src/span.rs: replace && with == in Span::replace
src/span.rs: replace && with != in Span::replace
Expand Down
11 changes: 11 additions & 0 deletions src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use std::collections::VecDeque;
use std::sync::Arc;
use std::vec;

use anyhow::Context;
use proc_macro2::{Ident, TokenStream};
Expand Down Expand Up @@ -368,15 +369,25 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> {
BinOp::Le(_) => vec![quote! {>}],
BinOp::Ge(_) => vec![quote! {<}],
BinOp::Add(_) => vec![quote! {-}, quote! {*}],
BinOp::AddAssign(_) => vec![quote! {-=}, quote! {*=}],
BinOp::Sub(_) => vec![quote! {+}, quote! {/}],
BinOp::SubAssign(_) => vec![quote! {+=}, quote! {/=}],
BinOp::Mul(_) => vec![quote! {+}, quote! {/}],
BinOp::MulAssign(_) => vec![quote! {+=}, quote! {/=}],
BinOp::Div(_) => vec![quote! {%}, quote! {*}],
BinOp::DivAssign(_) => vec![quote! {%=}, quote! {*=}],
BinOp::Rem(_) => vec![quote! {/}, quote! {+}],
BinOp::RemAssign(_) => vec![quote! {/=}, quote! {+=}],
BinOp::Shl(_) => vec![quote! {>>}],
BinOp::ShlAssign(_) => vec![quote! {>>=}],
BinOp::Shr(_) => vec![quote! {<<}],
BinOp::ShrAssign(_) => vec![quote! {<<=}],
BinOp::BitAnd(_) => vec![quote! {|}, quote! {^}],
BinOp::BitAndAssign(_) => vec![quote! {|=}, quote! {^=}],
BinOp::BitOr(_) => vec![quote! {&}, quote! {^}],
BinOp::BitOrAssign(_) => vec![quote! {&=}, quote! {^=}],
BinOp::BitXor(_) => vec![quote! {|}, quote! {&}],
BinOp::BitXorAssign(_) => vec![quote! {|=}, quote! {&=}],
_ => {
trace!(
op = i.op.to_pretty_string(),
Expand Down
12 changes: 4 additions & 8 deletions tests/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ fn exclude_re_overrides_config() {
String::from_utf8_lossy(&cmd.get_output().stdout),
@r###"
src/simple_fns.rs: replace returns_unit with ()
src/simple_fns.rs: replace += with -= in returns_unit
src/simple_fns.rs: replace += with *= in returns_unit
src/simple_fns.rs: replace == with != in divisible_by_three
src/simple_fns.rs: replace % with / in divisible_by_three
src/simple_fns.rs: replace % with + in divisible_by_three
Expand All @@ -230,8 +232,6 @@ fn tree_fails_without_needed_feature() {

#[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,
Expand All @@ -243,14 +243,11 @@ fn additional_cargo_args() {
.args(["mutants", "-d"])
.arg(testdata.path())
.assert()
.success()
.stdout(predicates::str::contains("2 caught"));
.success();
}

#[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,
Expand All @@ -262,6 +259,5 @@ fn additional_cargo_test_args() {
.args(["mutants", "-d"])
.arg(testdata.path())
.assert()
.success()
.stdout(predicates::str::contains("2 caught"));
.success();
}
2 changes: 1 addition & 1 deletion tests/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ fn list_diff_json_contains_diffs() {
println!("{}", String::from_utf8_lossy(&out.stdout));
let out_json = serde_json::from_slice::<serde_json::Value>(&out.stdout).unwrap();
let mutants_json = out_json.as_array().expect("json output is array");
assert_eq!(mutants_json.len(), 3);
assert_eq!(mutants_json.len(), 5);
assert!(mutants_json.iter().all(|e| e.as_object().unwrap()["diff"]
.as_str()
.unwrap()
Expand Down
6 changes: 4 additions & 2 deletions tests/cli/snapshots/cli__cdylib_tree_is_well_tested.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
source: tests/cli/main.rs
expression: stdout
---
Found 2 mutants to test
Found 4 mutants to test
ok Unmutated baseline
caught src/entry.rs:2:5: replace factorial -> u32 with 0
caught src/entry.rs:2:5: replace factorial -> u32 with 1
2 mutants tested: 2 caught
caught src/entry.rs:4:11: replace *= with += in factorial
caught src/entry.rs:4:11: replace *= with /= in factorial
4 mutants tested: 4 caught

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
source: tests/cli/main.rs
expression: stdout
---
Found 2 mutants to test
Found 4 mutants to test
ok Unmutated baseline
ok src/lib.rs:2:5: replace factorial -> u32 with 0
ok src/lib.rs:2:5: replace factorial -> u32 with 1
2 mutants tested: 2 succeeded
ok src/lib.rs:4:11: replace *= with += in factorial
ok src/lib.rs:4:11: replace *= with /= in factorial
4 mutants tested: 4 succeeded

2 changes: 2 additions & 0 deletions tests/cli/snapshots/cli__factorial__log_names.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ expression: "&names"
---
[
"baseline.log",
"src__bin__factorial.rs_line_10_col_11.log",
"src__bin__factorial.rs_line_10_col_11_001.log",
"src__bin__factorial.rs_line_2_col_5.log",
"src__bin__factorial.rs_line_8_col_5.log",
"src__bin__factorial.rs_line_8_col_5_001.log",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
source: tests/cli/main.rs
expression: stdout
---
Found 3 mutants to test
Found 5 mutants to test
ok Unmutated baseline
MISSED src/bin/factorial.rs:2:5: replace main with ()
3 mutants tested: 1 missed, 2 caught
5 mutants tested: 1 missed, 4 caught

Loading

0 comments on commit dbf18c9

Please sign in to comment.