Skip to content

Commit

Permalink
fix(coverage): do not report empty constructors, enable reports for `…
Browse files Browse the repository at this point in the history
…receive` (#9288)

fix(coverage): do not report empty constructors, enable reports for receive fn
  • Loading branch information
grandizzy authored Nov 9, 2024
1 parent f3376a6 commit 91d3349
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 4 deletions.
8 changes: 4 additions & 4 deletions crates/evm/coverage/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ impl<'a> ContractVisitor<'a> {
let name: String =
node.attribute("name").ok_or_else(|| eyre::eyre!("Function has no name"))?;

// TODO(onbjerg): Figure out why we cannot find anchors for the receive function
let kind: String =
node.attribute("kind").ok_or_else(|| eyre::eyre!("Function has no kind"))?;
if kind == "receive" {
return Ok(())
}

match &node.body {
Some(body) => {
// Do not add coverage item for constructors without statements.
if kind == "constructor" && !has_statements(body) {
return Ok(())
}
self.push_item_kind(CoverageItemKind::Function { name }, &node.src);
self.visit_block(body)
}
Expand Down
92 changes: 92 additions & 0 deletions crates/forge/tests/cli/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1321,3 +1321,95 @@ contract AContractTest is DSTest {
"#]]);
});

// <https://github.com/foundry-rs/foundry/issues/9270>
// Test that constructor with no statements is not counted in functions coverage.
forgetest!(test_ignore_empty_constructors_coverage, |prj, cmd| {
prj.insert_ds_test();
prj.add_source(
"AContract.sol",
r#"
contract AContract {
constructor() {}
function increment() public {}
}
"#,
)
.unwrap();

prj.add_source(
"AContractTest.sol",
r#"
import "./test.sol";
import "./AContract.sol";
contract AContractTest is DSTest {
function test_constructors() public {
AContract a = new AContract();
a.increment();
}
}
"#,
)
.unwrap();

// Assert there's only one function (`increment`) reported.
cmd.arg("coverage").args(["--summary".to_string()]).assert_success().stdout_eq(str![[r#"
...
| File | % Lines | % Statements | % Branches | % Funcs |
|-------------------|---------------|---------------|---------------|---------------|
| src/AContract.sol | 100.00% (0/0) | 100.00% (0/0) | 100.00% (0/0) | 100.00% (1/1) |
| Total | 100.00% (0/0) | 100.00% (0/0) | 100.00% (0/0) | 100.00% (1/1) |
"#]]);
});

// Test coverage for `receive` functions.
forgetest!(test_receive_coverage, |prj, cmd| {
prj.insert_ds_test();
prj.add_source(
"AContract.sol",
r#"
contract AContract {
uint256 public counter = 0;
constructor() {
counter = 1;
}
receive() external payable {
counter = msg.value;
}
}
"#,
)
.unwrap();

prj.add_source(
"AContractTest.sol",
r#"
import "./test.sol";
import "./AContract.sol";
contract AContractTest is DSTest {
function test_constructors() public {
AContract a = new AContract();
address(a).call{value: 5}("");
require(a.counter() == 5);
}
}
"#,
)
.unwrap();

// Assert both constructor and receive functions coverage reported.
cmd.arg("coverage").args(["--summary".to_string()]).assert_success().stdout_eq(str![[r#"
...
| File | % Lines | % Statements | % Branches | % Funcs |
|-------------------|---------------|---------------|---------------|---------------|
| src/AContract.sol | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |
| Total | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |
"#]]);
});

0 comments on commit 91d3349

Please sign in to comment.