Skip to content

Commit 42d44bf

Browse files
authored
fix(coverage): account if/else statements without brackets (#8608)
fix(coverage): recognize if/else statements without brackets
1 parent 0b73b42 commit 42d44bf

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

crates/evm/coverage/src/analysis.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,23 @@ impl<'a> ContractVisitor<'a> {
534534
}
535535
}
536536

537-
/// Helper function to check if a given node contains any statement.
537+
/// Helper function to check if a given node is or contains any statement.
538538
fn has_statements(node: &Node) -> bool {
539-
let statements: Vec<Node> = node.attribute("statements").unwrap_or_default();
540-
!statements.is_empty()
539+
match node.node_type {
540+
NodeType::DoWhileStatement |
541+
NodeType::EmitStatement |
542+
NodeType::ExpressionStatement |
543+
NodeType::ForStatement |
544+
NodeType::IfStatement |
545+
NodeType::RevertStatement |
546+
NodeType::TryStatement |
547+
NodeType::VariableDeclarationStatement |
548+
NodeType::WhileStatement => true,
549+
_ => {
550+
let statements: Vec<Node> = node.attribute("statements").unwrap_or_default();
551+
!statements.is_empty()
552+
}
553+
}
541554
}
542555

543556
/// [`SourceAnalyzer`] result type.

crates/forge/tests/cli/coverage.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,3 +1030,86 @@ contract FooTest is DSTest {
10301030
"#]],
10311031
);
10321032
});
1033+
1034+
// https://github.com/foundry-rs/foundry/issues/8605
1035+
forgetest!(test_single_statement_coverage, |prj, cmd| {
1036+
prj.insert_ds_test();
1037+
prj.add_source(
1038+
"AContract.sol",
1039+
r#"
1040+
contract AContract {
1041+
event IsTrue(bool isTrue);
1042+
event IsFalse(bool isFalse);
1043+
1044+
function ifElseStatementIgnored(bool flag) external {
1045+
if (flag) emit IsTrue(true);
1046+
else emit IsFalse(false);
1047+
1048+
if (flag) flag = true;
1049+
else flag = false;
1050+
}
1051+
}
1052+
"#,
1053+
)
1054+
.unwrap();
1055+
1056+
prj.add_source(
1057+
"AContractTest.sol",
1058+
r#"
1059+
import "./test.sol";
1060+
import {AContract} from "./AContract.sol";
1061+
1062+
contract AContractTest is DSTest {
1063+
function testTrueCoverage() external {
1064+
AContract a = new AContract();
1065+
a.ifElseStatementIgnored(true);
1066+
}
1067+
1068+
function testFalseCoverage() external {
1069+
AContract a = new AContract();
1070+
a.ifElseStatementIgnored(false);
1071+
}
1072+
}
1073+
"#,
1074+
)
1075+
.unwrap();
1076+
1077+
// Assert 50% coverage for true branches.
1078+
cmd.arg("coverage")
1079+
.args(["--mt".to_string(), "testTrueCoverage".to_string()])
1080+
.assert_success()
1081+
.stdout_eq(str![[r#"
1082+
...
1083+
| File | % Lines | % Statements | % Branches | % Funcs |
1084+
|-------------------|--------------|--------------|--------------|---------------|
1085+
| src/AContract.sol | 50.00% (2/4) | 50.00% (2/4) | 50.00% (2/4) | 100.00% (1/1) |
1086+
| Total | 50.00% (2/4) | 50.00% (2/4) | 50.00% (2/4) | 100.00% (1/1) |
1087+
1088+
"#]]);
1089+
1090+
// Assert 50% coverage for false branches.
1091+
cmd.forge_fuse()
1092+
.arg("coverage")
1093+
.args(["--mt".to_string(), "testFalseCoverage".to_string()])
1094+
.assert_success()
1095+
.stdout_eq(str![[r#"
1096+
...
1097+
| File | % Lines | % Statements | % Branches | % Funcs |
1098+
|-------------------|---------------|--------------|--------------|---------------|
1099+
| src/AContract.sol | 100.00% (4/4) | 50.00% (2/4) | 50.00% (2/4) | 100.00% (1/1) |
1100+
| Total | 100.00% (4/4) | 50.00% (2/4) | 50.00% (2/4) | 100.00% (1/1) |
1101+
1102+
"#]]);
1103+
1104+
// Assert 100% coverage (true/false branches properly covered).
1105+
cmd.forge_fuse().arg("coverage").args(["--summary".to_string()]).assert_success().stdout_eq(
1106+
str![[r#"
1107+
...
1108+
| File | % Lines | % Statements | % Branches | % Funcs |
1109+
|-------------------|---------------|---------------|---------------|---------------|
1110+
| src/AContract.sol | 100.00% (4/4) | 100.00% (4/4) | 100.00% (4/4) | 100.00% (1/1) |
1111+
| Total | 100.00% (4/4) | 100.00% (4/4) | 100.00% (4/4) | 100.00% (1/1) |
1112+
1113+
"#]],
1114+
);
1115+
});

0 commit comments

Comments
 (0)