Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mutation Operators

Mutation operators are the rules that match patterns of program code, and produce corresponding mutations.

The active set of mutation operators can be controlled using the --mutation-operators argument (default: all), by specifying a comma-seperated list of mutation operator names.

cargo mutest --mutation-operators call_delete,call_value_default_shadow run

The following list of mutation operators is currently implemented in mutest-rs, with detailed descriptions and examples below:

Mutation OperatorShort Description
arg_default_shadowIgnore argument by shadowing it with Default::default().
bit_op_or_and_swapSwap bitwise OR for bitwise AND and vice versa.
bit_op_or_xor_swapSwap bitwise OR for bitwise XOR and vice versa.
bit_op_shift_dir_swapSwap the direction of bitwise shift operator.
bit_op_xor_and_swapSwap bitwise XOR for bitwise AND and vice versa.
bool_expr_negateNegate boolean expression.
call_deleteDelete call and replace it with Default::default().
call_value_default_shadowIgnore return value of call by shadowing it with Default::default().
continue_break_swapSwap continue for break and vice versa.
eq_op_invertInvert equality check.
logical_op_and_or_swapSwap logical and for logical or and vice versa.
math_op_add_mul_swapSwap addition for multiplication and vice versa.
math_op_add_sub_swapSwap addition for subtraction and vice versa.
math_op_div_rem_swapSwap division for modulus and vice versa.
math_op_mul_div_swapSwap multiplication for division and vice versa.
range_limit_swapSwap limit (inclusivity) of range expression.
relational_op_eq_swapInclude or remove the boundary (equality) of relational operator.
relational_op_invertInvert relation operator.

NOTE: The following replacements are illustrative and are meant to show how code behaviour effectively changes with each mutation.

arg_default_shadow

Replace the provided arguments of functions with Default::default() to check if each parameter is tested with meaningful values.

This is done by rebinding parameters at the beginning of the function.

Replaces

fn foo(hash: u64) {

with

fn foo(hash: u64) { let hash: u64 = Default::default();

bit_op_or_and_swap

Swap bitwise OR for bitwise AND and vice versa.

Replaces

byte & (0x1 << 2)

with

byte | (0x1 << 2)

bit_op_or_xor_swap

Swap bitwise OR for bitwise XOR and vice versa.

Replaces

bytes[i] |= 0x1 << 3

with

bytes[i] ^= 0x1 << 3

bit_op_shift_dir_swap

Swap the direction of bitwise shift operators.

Replaces

byte & (0x1 << i)

with

byte & (0x1 >> i)

bit_op_xor_and_swap

Swap bitwise XOR for bitwise AND and vice versa.

Replaces

byte & (0x1 << 2)

with

byte ^ (0x1 << 2)

bool_expr_negate

Negate boolean expressions.

Replaces

if !handle.is_active() { drop(handle);

with

if handle.is_active() { drop(handle);

call_delete

Delete function calls and replace them with Default::default() to test whether inner calls are meaningfully tested, without retaining any side-effects of the callees.

Replaces

let existing = map.insert(Id(123), 0);

with

let existing: Option<usize> = Default::default();

call_value_default_shadow

Replace the return value of function calls with Default::default() to test whether the return values of inner calls are meaningfully tested, while retaining expected side-effects of the callees.

Replaces

let existing = map.insert(Id(123), 0);

with

let existing: Option<usize> = { let _existing = map.insert(Id(123), 0); Default::default() };

continue_break_swap

Swap continue expressions for break expressions and vice versa.

Replaces

for other in mutations { if conflicts.contains(&(mutation, other)) { continue; }

with

for other in mutations { if conflicts.contains(&(mutation, other)) { break; }

eq_op_invert

Invert equality checks.

Replaces

if buffer.len() == 0 { buffer.reserve(1024);

with

if buffer.len() != 0 { buffer.reserve(1024);

logical_op_and_or_swap

Swap logical && for logical || and vice versa.

Replaces

self.len() <= other.len() && self.iter().all(|v| other.contains(v))

with

self.len() <= other.len() || self.iter().all(|v| other.contains(v))

math_op_add_mul_swap

Swap addition for multiplication and vice versa.

Replaces

let offset = size_of::<DeclarativeEnvironment>() * index;

with

let offset = size_of::<DeclarativeEnvironment>() + index;

math_op_add_sub_swap

Swap addition for subtraction and vice versa.

Replaces

let center = Point::new(x + (width / 2), y + (height / 2));

with

let center = Point::new(x - (width / 2), y + (height / 2));

math_op_div_rem_swap

Swap division for modulus and vice versa.

Replaces

let evens = 0..100.filter(|v| v % 2 == 0);

with

let evens = 0..100.filter(|v| v / 2 == 0);

math_op_mul_div_swap

Swap multiplication for division and vice versa.

Replaces

let v = f64::sin(t * freq) * magnitude;

with

let v = f64::sin(t / freq) * magnitude;

range_limit_swap

Invert the limits (inclusivity) of range expressions.

Replaces

for i in 0..buffer.len() {

with

for i in 0..=buffer.len() {

relational_op_eq_swap

Include or remove the boundary (equality) of relational operators.

Replaces

if self.len() <= other.len() {

with

if self.len() < other.len() {

relational_op_invert

Completely invert relation operators.

Replaces

while i < buffer.len() {

with

while i >= buffer.len() {