Skip to content

Commit c0ffee5

Browse files
feat: basic reporting
1 parent c0ffeec commit c0ffee5

File tree

5 files changed

+124
-17
lines changed

5 files changed

+124
-17
lines changed

cache/solidity-files-cache.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"_format":"","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"src","tests":"test","scripts":"script","libraries":["lib"]},"files":{"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol":{"lastModificationDate":1743434619281,"contentHash":"409e7881b1f12b7eda886da0aadf38bd","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_BitNot/src/Counter.sol/Counter.json","build_id":"be8655b2c799b17ac6647f61ab46ccef"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol":{"lastModificationDate":1743434619272,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol/CounterTest.json","build_id":"be8655b2c799b17ac6647f61ab46ccef"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol":{"lastModificationDate":1743434619281,"contentHash":"23ec06146f4e636071d9d2f687bb39b8","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_PostDec/src/Counter.sol/Counter.json","build_id":"574e4c1c455d00a029d3589da294e5fa"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol":{"lastModificationDate":1743434619272,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol/CounterTest.json","build_id":"574e4c1c455d00a029d3589da294e5fa"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol":{"lastModificationDate":1743434619281,"contentHash":"fa61ead0fe3f3d3cf9a74043ca8a1cca","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"src/Counter.sol/Counter.json","build_id":"afce877b209389cf1cf46e71f0c4b713"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreDec/test/CounterTest.t.sol":{"lastModificationDate":1743434619272,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreDec/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"test/CounterTest.t.sol/CounterTest.json","build_id":"afce877b209389cf1cf46e71f0c4b713"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol":{"lastModificationDate":1743434619280,"contentHash":"1129c6e517e1881612a094060e2866bd","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"Counter.sol/Counter.json","build_id":"503faaace5bbb52d3cdc012c25721426"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreInc/test/CounterTest.t.sol":{"lastModificationDate":1743434619272,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreInc/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpT6r94g/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"CounterTest.t.sol/CounterTest.json","build_id":"503faaace5bbb52d3cdc012c25721426"}}}},"seenByCompiler":true}},"builds":["503faaace5bbb52d3cdc012c25721426","574e4c1c455d00a029d3589da294e5fa","afce877b209389cf1cf46e71f0c4b713","be8655b2c799b17ac6647f61ab46ccef"],"profiles":{"default":{"solc":{"optimizer":{"enabled":false,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"cancun","viaIR":false,"libraries":{}},"vyper":{"evmVersion":"cancun","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}}}}}}
1+
{"_format":"","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"src","tests":"test","scripts":"script","libraries":["lib"]},"files":{"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol":{"lastModificationDate":1743435364548,"contentHash":"409e7881b1f12b7eda886da0aadf38bd","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_BitNot/src/Counter.sol/Counter.json","build_id":"611b06cf8f63cf633d8f3e1cf644bbfe"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol":{"lastModificationDate":1743435364534,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_BitNot/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_BitNot/test/CounterTest.t.sol/CounterTest.json","build_id":"611b06cf8f63cf633d8f3e1cf644bbfe"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol":{"lastModificationDate":1743435364548,"contentHash":"23ec06146f4e636071d9d2f687bb39b8","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_PostDec/src/Counter.sol/Counter.json","build_id":"b733849b9e35a95f8a64b14dda9151ef"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol":{"lastModificationDate":1743435364534,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PostDec/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"mutation_211_203_UnaryOperator_PostDec/test/CounterTest.t.sol/CounterTest.json","build_id":"b733849b9e35a95f8a64b14dda9151ef"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol":{"lastModificationDate":1743435364548,"contentHash":"fa61ead0fe3f3d3cf9a74043ca8a1cca","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"src/Counter.sol/Counter.json","build_id":"2068d3446326d754b730a2df5ea568f8"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreDec/test/CounterTest.t.sol":{"lastModificationDate":1743435364534,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreDec/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreDec/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"test/CounterTest.t.sol/CounterTest.json","build_id":"2068d3446326d754b730a2df5ea568f8"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol":{"lastModificationDate":1743435364548,"contentHash":"1129c6e517e1881612a094060e2866bd","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol","imports":[],"versionRequirement":"^0.8.13","artifacts":{"Counter":{"0.8.28":{"default":{"path":"Counter.sol/Counter.json","build_id":"32fa3bbd0fbf144bf1fd0af3ea20e90e"}}}},"seenByCompiler":true},"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreInc/test/CounterTest.t.sol":{"lastModificationDate":1743435364534,"contentHash":"7ca0c40d195ed5b4cdc882be42cba837","sourceName":"/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreInc/test/CounterTest.t.sol","imports":["/private/var/folders/zt/hvj1qf5j1fv7vrdb2c8hxr7m0000gn/T/.tmpADxVq0/Counter_sol/mutation_211_203_UnaryOperator_PreInc/src/Counter.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterTest":{"0.8.28":{"default":{"path":"CounterTest.t.sol/CounterTest.json","build_id":"32fa3bbd0fbf144bf1fd0af3ea20e90e"}}}},"seenByCompiler":true}},"builds":["2068d3446326d754b730a2df5ea568f8","32fa3bbd0fbf144bf1fd0af3ea20e90e","611b06cf8f63cf633d8f3e1cf644bbfe","b733849b9e35a95f8a64b14dda9151ef"],"profiles":{"default":{"solc":{"optimizer":{"enabled":false,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"cancun","viaIR":false,"libraries":{}},"vyper":{"evmVersion":"cancun","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}}}}}}

crates/forge/src/cmd/test/mod.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
decode::decode_console_logs,
44
gas_report::GasReport,
55
multi_runner::matches_contract,
6-
mutation::MutationHandler,
6+
mutation::{MutationHandler, MutationReporter, MutationsSummary},
77
result::{SuiteResult, TestOutcome, TestStatus},
88
traces::{
99
debug::{ContractSources, DebugTraceIdentifier},
@@ -486,6 +486,8 @@ impl TestArgs {
486486
};
487487

488488
sh_println!("Running mutation tests...").unwrap();
489+
let mut mutation_summary = MutationsSummary::new();
490+
489491
for path in mutate_paths {
490492
let mut handler = MutationHandler::new(path, config.clone());
491493

@@ -495,7 +497,7 @@ impl TestArgs {
495497

496498
let mutants = handler.generate_and_compile().await;
497499

498-
// @todo multithread here? -> tests are async already
500+
// @todo ugly - needs to be refactored
499501
for mutant in mutants {
500502
if let Some(compile_output) = mutant.1 {
501503
let mutant_path = mutant.0.path.clone();
@@ -528,17 +530,16 @@ impl TestArgs {
528530
let results = runner.test_collect(&new_filter);
529531

530532
let outcome = TestOutcome::new(results, self.allow_failure);
531-
532-
if outcome.failed() != 0 {
533-
sh_println!("Mutation: Dead")?;
534-
} else {
535-
sh_println!("Mutation: Survived")?;
536-
}
533+
mutation_summary.update_valid_mutant(&outcome);
537534
} else {
538-
sh_println!("Mutation: Invalid")?;
535+
mutation_summary.update_invalid_mutant();
539536
}
540537
}
541538
}
539+
540+
MutationReporter::new().report(&mutation_summary);
541+
542+
outcome = TestOutcome::empty(true);
542543
}
543544

544545
Ok(outcome)

crates/forge/src/mutation/mod.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod mutant;
22
mod mutators;
3+
mod reporter;
34
mod visitor;
45

56
// Generate mutants then run tests (reuse the whole unit test flow for now, including compilation to
@@ -12,25 +13,79 @@ use std::sync::Arc;
1213

1314
use crate::mutation::{mutant::Mutant, visitor::MutantVisitor};
1415

15-
pub use crate::mutation::mutant::MutationResult;
16+
pub use crate::mutation::reporter::MutationReporter;
17+
18+
use crate::result::TestOutcome;
1619
use foundry_compilers::{project::ProjectCompiler, ProjectCompileOutput};
1720
use foundry_config::Config;
1821
use rayon::prelude::*;
1922
use solar_parse::ast::visit::Visit;
2023
use std::path::{Path, PathBuf};
2124
use tempfile::TempDir;
25+
pub struct MutationsSummary {
26+
total: usize,
27+
dead: usize,
28+
survived: usize,
29+
invalid: usize,
30+
}
31+
32+
impl MutationsSummary {
33+
pub fn new() -> Self {
34+
Self { total: 0, dead: 0, survived: 0, invalid: 0 }
35+
}
36+
37+
pub fn update_valid_mutant(&mut self, outcome: &TestOutcome) {
38+
self.total += 1;
39+
40+
if outcome.failures().count() > 0 {
41+
self.dead += 1;
42+
} else {
43+
self.survived += 1;
44+
}
45+
}
46+
47+
pub fn update_invalid_mutant(&mut self) {
48+
self.total += 1;
49+
self.invalid += 1;
50+
}
51+
52+
pub fn total(&self) -> usize {
53+
self.total
54+
}
55+
56+
pub fn dead(&self) -> usize {
57+
self.dead
58+
}
59+
60+
pub fn survived(&self) -> usize {
61+
self.survived
62+
}
63+
64+
pub fn invalid(&self) -> usize {
65+
self.invalid
66+
}
67+
}
68+
2269
pub struct MutationHandler {
2370
contract_to_mutate: PathBuf,
2471
src: Arc<String>,
2572
mutations: Vec<Mutant>,
2673
config: Arc<foundry_config::Config>,
74+
report: MutationsSummary,
2775
// Ensure we don't clean it between creation and mutant generation (been there, done that)
2876
temp_dir: Option<TempDir>,
2977
}
3078

3179
impl MutationHandler {
3280
pub fn new(contract_to_mutate: PathBuf, config: Arc<foundry_config::Config>) -> Self {
33-
Self { contract_to_mutate, src: Arc::default(), mutations: vec![], config, temp_dir: None }
81+
Self {
82+
contract_to_mutate,
83+
src: Arc::default(),
84+
mutations: vec![],
85+
config,
86+
temp_dir: None,
87+
report: MutationsSummary::new(),
88+
}
3489
}
3590

3691
/// Keep the source contract in memory (in the hashmap), as we'll use it to create the mutants

crates/forge/src/mutation/reporter.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use crate::mutation::MutationsSummary;
2+
use comfy_table::{modifiers::UTF8_ROUND_CORNERS, Attribute, Cell, Color, Row, Table};
3+
pub struct MutationReporter {
4+
table: Table,
5+
}
6+
7+
impl MutationReporter {
8+
pub fn new() -> Self {
9+
let mut table = Table::new();
10+
11+
table.apply_modifier(UTF8_ROUND_CORNERS);
12+
13+
table.set_header(vec![
14+
Cell::new("Status"),
15+
Cell::new("# Mutants"),
16+
Cell::new("% of Total"),
17+
]);
18+
19+
Self { table }
20+
}
21+
22+
pub fn report(&mut self, summary: &MutationsSummary) {
23+
let mut row = Row::new();
24+
row.add_cell(Cell::new("Survived").fg(Color::Red))
25+
.add_cell(Cell::new(summary.survived().to_string()))
26+
.add_cell(Cell::new(format!(
27+
"{:.2}%",
28+
summary.survived() as f64 / summary.total() as f64 * 100.
29+
)));
30+
self.table.add_row(row);
31+
32+
row = Row::new();
33+
row.add_cell(Cell::new("Dead").fg(Color::Green))
34+
.add_cell(Cell::new(summary.dead().to_string()))
35+
.add_cell(Cell::new(format!(
36+
"{:.2}%",
37+
summary.dead() as f64 / summary.total() as f64 * 100.
38+
)));
39+
self.table.add_row(row);
40+
41+
row = Row::new();
42+
row.add_cell(Cell::new("Invalid").fg(Color::Green))
43+
.add_cell(Cell::new(summary.invalid().to_string()))
44+
.add_cell(Cell::new(format!(
45+
"{:.2}%",
46+
summary.invalid() as f64 / summary.total() as f64 * 100.
47+
)));
48+
self.table.add_row(row);
49+
50+
sh_println!("Total number of mutants generated: {}", summary.total());
51+
sh_println!("\n{}", self.table);
52+
}
53+
}

crates/forge/tests/it/mutation.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use forge::mutation::MutationHandler;
22
use forge_script::ScriptArgs;
3-
use foundry_common::shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbosity};
4-
use foundry_config::Config;
5-
use foundry_evm::opts::EvmOpts;
6-
use std::{path::PathBuf, sync::Arc};
3+
use foundry_common::shell::{ColorChoice, OutputFormat, OutputMode, Shell};
4+
use std::sync::Arc;
75

86
#[tokio::test(flavor = "multi_thread")]
9-
async fn test_mutation_handler_lifecycle() {
7+
async fn test_mutation_test_lifecycle() {
108
let contract = r#"
119
// SPDX-License-Identifier: UNLICENSED
1210
pragma solidity ^0.8.13;

0 commit comments

Comments
 (0)