Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(forge): coverage does not work for enum assignments #4315

Closed
2 tasks done
Tracked by #4442
PaulRBerg opened this issue Feb 9, 2023 · 1 comment · Fixed by #8414
Closed
2 tasks done
Tracked by #4442

bug(forge): coverage does not work for enum assignments #4315

PaulRBerg opened this issue Feb 9, 2023 · 1 comment · Fixed by #8414
Labels
C-forge Command: forge Cmd-forge-coverage Command: forge coverage T-bug Type: bug

Comments

@PaulRBerg
Copy link
Contributor

Component

Forge

Have you ensured that all of these are up to date?

  • Foundry
  • 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:

Screenshot 2023-02-09 at 11 05 52 AM

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.

@zerosnacks
Copy link
Member

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) |

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-forge Command: forge Cmd-forge-coverage Command: forge coverage T-bug Type: bug
Projects
Status: Completed
Development

Successfully merging a pull request may close this issue.

2 participants