Skip to content
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
35 changes: 35 additions & 0 deletions src/mutant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ pub enum MutationTarget {
/// A mutation applied to source code.
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Mutant {
/// A precomputed human-readable name for this mutant, including the file,
/// location, and change description.
///
/// This is used in CLI output, filtering, and JSON.
pub name: String,

/// Which file is being mutated.
pub source_file: SourceFile,

Expand Down Expand Up @@ -103,6 +109,34 @@ pub struct Function {
}

impl Mutant {
/// Construct a mutant discovered while walking source code.
///
/// This initializes all fields and precomputes the human-readable `name`
/// (including file path, line/column, and change description) for use in
/// CLI output, filtering, and JSON.
pub(crate) fn new_discovered(
source_file: SourceFile,
function: Option<Arc<Function>>,
span: Span,
short_replaced: Option<String>,
replacement: String,
genre: Genre,
target: Option<MutationTarget>,
) -> Self {
let mut mutant = Mutant {
name: String::new(),
source_file,
function,
span,
short_replaced,
replacement,
genre,
target,
};
mutant.name = mutant.name(true);
mutant
}

/// Return text of the whole file with the mutation applied.
pub fn mutated_code(&self) -> String {
self.span.replace(
Expand Down Expand Up @@ -293,6 +327,7 @@ impl Serialize for Mutant {
{
// custom serialize to omit inessential info
let mut ss = serializer.serialize_struct("Mutant", 7)?;
ss.serialize_field("name", &self.name)?;
ss.serialize_field("package", &self.source_file.package.name)?;
ss.serialize_field("file", &self.source_file.tree_relative_slashes())?;
ss.serialize_field("function", &self.function.as_ref().map(Arc::as_ref))?;
Expand Down
53 changes: 27 additions & 26 deletions src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ pub struct Discovered {
impl Discovered {
pub(crate) fn remove_previously_caught(&mut self, previously_caught: &[String]) {
self.mutants.retain(|m| {
let name = m.name(true);
let c = previously_caught.contains(&name);
let c = previously_caught.contains(&m.name);
if c {
trace!(?name, "skip previously caught mutant");
trace!(name = %m.name, "skip previously caught mutant");
}
!c
});
Expand Down Expand Up @@ -75,6 +74,7 @@ pub fn walk_tree(
mutants.append(&mut package_mutants);
files.append(&mut package_files);
}

progress.finish();
Ok(Discovered { mutants, files })
}
Expand Down Expand Up @@ -318,15 +318,16 @@ impl DiscoveryVisitor<'_> {

/// Record that we generated some mutants.
fn collect_mutant(&mut self, span: Span, replacement: &TokenStream, genre: Genre) {
self.mutants.push(Mutant {
source_file: self.source_file.clone(),
function: self.fn_stack.last().cloned(),
let mutant = Mutant::new_discovered(
self.source_file.clone(),
self.fn_stack.last().cloned(),
span,
short_replaced: None,
replacement: replacement.to_pretty_string(),
None,
replacement.to_pretty_string(),
genre,
target: None,
});
None,
);
self.mutants.push(mutant);
}

fn collect_fn_mutants(&mut self, sig: &Signature, block: &Block) {
Expand Down Expand Up @@ -656,15 +657,15 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> {
continue;
}
let short_replaced = Some(arm.pat.to_pretty_string());
let mutant = Mutant {
source_file: self.source_file.clone(),
function: self.fn_stack.last().cloned(),
span: arm.span().into(),
let mutant = Mutant::new_discovered(
self.source_file.clone(),
self.fn_stack.last().cloned(),
arm.span().into(),
short_replaced,
replacement: String::new(),
genre: Genre::MatchArm,
target: None,
};
String::new(),
Genre::MatchArm,
None,
);
self.mutants.push(mutant);
}
} else {
Expand Down Expand Up @@ -722,18 +723,18 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> {
// No comma, just the field
field.span().into()
};
let mutant = Mutant {
source_file: self.source_file.clone(),
function: self.fn_stack.last().cloned(),
let mutant = Mutant::new_discovered(
self.source_file.clone(),
self.fn_stack.last().cloned(),
span,
short_replaced: None,
replacement: String::new(),
genre: Genre::StructField,
target: Some(MutationTarget::StructLiteralField {
None,
String::new(),
Genre::StructField,
Some(MutationTarget::StructLiteralField {
field_name: field_name_str,
struct_name: struct_name.clone(),
}),
};
);
self.mutants.push(mutant);
}
}
Expand Down
5 changes: 5 additions & 0 deletions tests/snapshots/main__mutants.json.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ expression: mutants_json
---
[
{
"name": "src/bin/factorial.rs:2:5: replace main with ()",
"package": "cargo-mutants-testdata-factorial",
"file": "src/bin/factorial.rs",
"function": {
Expand Down Expand Up @@ -34,6 +35,7 @@ expression: mutants_json
"genre": "FnValue"
},
{
"name": "src/bin/factorial.rs:8:5: replace factorial -> u32 with 0",
"package": "cargo-mutants-testdata-factorial",
"file": "src/bin/factorial.rs",
"function": {
Expand Down Expand Up @@ -64,6 +66,7 @@ expression: mutants_json
"genre": "FnValue"
},
{
"name": "src/bin/factorial.rs:8:5: replace factorial -> u32 with 1",
"package": "cargo-mutants-testdata-factorial",
"file": "src/bin/factorial.rs",
"function": {
Expand Down Expand Up @@ -94,6 +97,7 @@ expression: mutants_json
"genre": "FnValue"
},
{
"name": "src/bin/factorial.rs:10:11: replace *= with += in factorial",
"package": "cargo-mutants-testdata-factorial",
"file": "src/bin/factorial.rs",
"function": {
Expand Down Expand Up @@ -124,6 +128,7 @@ expression: mutants_json
"genre": "BinaryOperator"
},
{
"name": "src/bin/factorial.rs:10:11: replace *= with /= in factorial",
"package": "cargo-mutants-testdata-factorial",
"file": "src/bin/factorial.rs",
"function": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "FnValue",
"name": "src/lib.rs:18:5: replace double -> usize with 0",
"package": "cargo-mutants-testdata-cfg-attr-test-skip",
"replacement": "0",
"span": {
Expand Down Expand Up @@ -50,6 +51,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "FnValue",
"name": "src/lib.rs:18:5: replace double -> usize with 1",
"package": "cargo-mutants-testdata-cfg-attr-test-skip",
"replacement": "1",
"span": {
Expand Down Expand Up @@ -80,6 +82,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "BinaryOperator",
"name": "src/lib.rs:18:7: replace * with + in double",
"package": "cargo-mutants-testdata-cfg-attr-test-skip",
"replacement": "+",
"span": {
Expand Down Expand Up @@ -110,6 +113,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "BinaryOperator",
"name": "src/lib.rs:18:7: replace * with / in double",
"package": "cargo-mutants-testdata-cfg-attr-test-skip",
"replacement": "/",
"span": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "FnValue",
"name": "src/bin/factorial.rs:2:5: replace main with ()",
"package": "cargo-mutants-testdata-factorial",
"replacement": "()",
"span": {
Expand Down Expand Up @@ -50,6 +51,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "FnValue",
"name": "src/bin/factorial.rs:8:5: replace factorial -> u32 with 0",
"package": "cargo-mutants-testdata-factorial",
"replacement": "0",
"span": {
Expand Down Expand Up @@ -80,6 +82,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "FnValue",
"name": "src/bin/factorial.rs:8:5: replace factorial -> u32 with 1",
"package": "cargo-mutants-testdata-factorial",
"replacement": "1",
"span": {
Expand Down Expand Up @@ -110,6 +113,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "BinaryOperator",
"name": "src/bin/factorial.rs:10:11: replace *= with += in factorial",
"package": "cargo-mutants-testdata-factorial",
"replacement": "+=",
"span": {
Expand Down Expand Up @@ -140,6 +144,7 @@ expression: "String::from_utf8_lossy(&output.stdout)"
}
},
"genre": "BinaryOperator",
"name": "src/bin/factorial.rs:10:11: replace *= with /= in factorial",
"package": "cargo-mutants-testdata-factorial",
"replacement": "/=",
"span": {
Expand Down
Loading