bug(forge): coverage does not work for enum assignments
Component
Forge
Have you ensured that all of these are up to date?
- [X] Foundry
- [X] Foundryup
What version of Foundry are you on?
forge 0.2.0 (249538f 2023-02-08T00:12:05.805004Z)
What command(s) is the bug in?
forge coverage
Operating System
macOS (Apple Silicon)
Describe the bug
Take the following contract (hidden by default for brevity reasons, click the toggle below to collapse it):
Click me to toggle the contract
contract Foo {
enum Status {
NULL,
OPEN,
CLOSED
}
struct Item {
Status status;
uint256 value;
}
mapping(uint256 => Item) internal items;
uint256 public nextId = 1;
function getItem(uint256 id) public view returns (Item memory item) {
item = items[id];
}
function addItem(uint256 value) public returns (uint256 id) {
id = nextId;
items[id] = Item(Status.OPEN, value);
nextId++;
}
function closeIfEqValue(uint256 id, uint256 value) public {
if (items[id].value == value) {
items[id].status = Status.CLOSED;
}
}
function incrementIfEqValue(uint256 id, uint256 value) public {
if (items[id].value == value) {
items[id].value = value + 1;
}
}
}
And the following tests (again, hidden for brevity):
Click me to toggle the tests
contract FooTest is Test {
Foo internal foo = new Foo();
function test_AddItem() external {
uint256 value = 42;
uint256 id = foo.addItem(value);
assertEq(id, 1);
assertEq(foo.nextId(), 2);
Foo.Item memory item = foo.getItem(id);
assertEq(uint8(item.status), uint8(Foo.Status.OPEN));
assertEq(item.value, value);
}
function test_CloseIfEqValue_NotEq() external {
uint256 value = 42;
uint256 id = foo.addItem(value);
foo.closeIfEqValue(id, 903);
Foo.Item memory item = foo.getItem(id);
assertEq(uint8(item.status), uint8(Foo.Status.OPEN));
}
function test_CloseIfEqValue_Eq() external {
uint256 value = 42;
uint256 id = foo.addItem(value);
foo.closeIfEqValue(id, 42);
Foo.Item memory item = foo.getItem(id);
assertEq(uint8(item.status), uint8(Foo.Status.CLOSED));
}
function test_IncrementIfEqValue_NotEq() external {
uint256 value = 42;
uint256 id = foo.addItem(value);
foo.incrementIfEqValue(id, 903);
Foo.Item memory item = foo.getItem(id);
assertEq(item.value, 42);
}
function test_IncrementIfEqValue_Eq() external {
uint256 value = 42;
uint256 id = foo.addItem(value);
foo.incrementIfEqValue(id, 42);
Foo.Item memory item = foo.getItem(id);
assertEq(item.value, 43);
}
}
Now, run forge coverage. You will get this report:
| File | % Lines | % Statements | % Branches | % Funcs |
|-------------|---------------|---------------|--------------|---------------|
| src/Foo.sol | 100.00% (8/8) | 100.00% (8/8) | 75.00% (3/4) | 100.00% (4/4) |
| Total | 100.00% (8/8) | 100.00% (8/8) | 75.00% (3/4) | 100.00% (4/4) |
Notice that the branch coverage is 75% even if we do have full coverage of all the possible branches of the closeIfEqValue function:
By contrast, the coverage for the incrementIfEqValue function is 100%, which shows that this bug is specifically about enum assignments. closeIfEqValue and incrementIfEqValue are fully equivalent, except for the enum assignment.
Able to reproduce, now still yields:
| File | % Lines | % Statements | % Branches | % Funcs |
|-------------|---------------|---------------|--------------|---------------|
| src/Foo.sol | 100.00% (8/8) | 100.00% (8/8) | 75.00% (3/4) | 100.00% (4/4) |
| Total | 100.00% (8/8) | 100.00% (8/8) | 75.00% (3/4) | 100.00% (4/4) |