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
18 changes: 18 additions & 0 deletions crates/forge/src/cmd/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ impl GasSnapshotConfig {
let mut tests = outcome
.into_tests()
.filter(|test| self.is_in_gas_range(test.gas_used()))
.flat_map(expand_invariant_snapshot_entries)
.collect::<Vec<_>>();

if self.asc {
Expand All @@ -225,6 +226,23 @@ impl GasSnapshotConfig {
}
}

/// Expands merged invariant campaigns into per-predicate gas snapshot rows.
fn expand_invariant_snapshot_entries(test: SuiteTestResult) -> Vec<SuiteTestResult> {
if !test.result.kind.is_invariant() || test.result.invariant_predicate_results.len() <= 1 {
return vec![test];
}

test.result
.invariant_predicate_results
.iter()
.map(|predicate| {
let mut expanded = test.clone();
expanded.signature = format!("{}()", predicate.name);
expanded
})
.collect()
}

/// A general entry in a gas snapshot file
///
/// Has the form:
Expand Down
45 changes: 45 additions & 0 deletions crates/forge/tests/cli/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,51 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
"#]]);
});

forgetest!(snapshot_expands_invariant_campaign_predicates, |prj, cmd| {
prj.add_test(
"InvariantSnapshot.t.sol",
r#"
contract InvariantSnapshotHandler {
uint256 public count;

function increment() public {
count++;
}
}

contract InvariantSnapshotTest {
InvariantSnapshotHandler internal handler;

function setUp() public {
handler = new InvariantSnapshotHandler();
}

/// forge-config: default.invariant.runs = 2
/// forge-config: default.invariant.depth = 4
function invariant_count_is_non_negative() public view {
require(handler.count() >= 0);
}

/// forge-config: default.invariant.runs = 2
/// forge-config: default.invariant.depth = 4
function invariant_count_is_not_max() public view {
require(handler.count() != type(uint256).max);
}
}
"#,
);

cmd.args(["snapshot"]).assert_success();

let snapshot = read_string(prj.root().join(".gas-snapshot"));
assert_eq!(
snapshot.lines().filter(|line| line.starts_with("InvariantSnapshotTest:")).count(),
2
);
assert!(snapshot.contains("InvariantSnapshotTest:invariant_count_is_non_negative()"));
assert!(snapshot.contains("InvariantSnapshotTest:invariant_count_is_not_max()"));
});

forgetest!(snapshot_reports_when_snap_file_is_not_written, |prj, cmd| {
prj.insert_ds_test();

Expand Down
Loading