foundry-rs / foundry-rs/foundry

feat(forge): new cheatcode for running simple tests with multiple `msg.sender` values

Open
#4,839 2 comments 0 reactions 0 assignees View on GitHub
A-cheatcodes C-forge Cmd-forge-test T-feature
Dominant language
Rust
Stars
10.6k
Forks
2.6k
Avg merge
18h 20m
Merged PRs (30d)
510

Description

### Component

Forge

### Describe the feature you would like

Scenario: a contract function allows the caller to be one of two special accounts:

```solidity
function foo() external onlyAliceOrBob {
// <--- snip --- >
}
```

Testing this sort of function is annoying because I have to duplicate logic in my tests, e.g.

```solidity
function testFoo_Alice() external {
assertEq(A, B);
assertEq(C, D);
assertEq(E, F);
}

function testFoo_Bob() external {
assertEq(A, B);
assertEq(C, D);
assertEq(E, F);
}
```

Now, I know I could de-dup the assertions in a subroutine, like this:

```solidity
function testFoo_Common() internal {
// <--- snip --->
}
```

But I wouldn't say I like this approach because it (i) hurts the readability of the tests and (ii) doesn't scale super well (e.g. in realistic scenarios, Bob has specific permissions that Alice doesn't have, which requires branching, which in turn complicates the subroutine).

It would be helpful if Forge lent a hand for this use case. I imagine that a new cheatcode could be implemented, e.g. `vm.consider`, which would be similar to `vm.assume` and would work something like this:

- Takes one, two, three, four, or a dynamic array of addresses
- When Forge sees `vm.consider` in a test, it runs the test with all provided addresses, one test run for each address. Basically, `vm.consider` would run a batch of `changePrank` under the hood (related: https://github.com/foundry-rs/foundry/issues/4779)
- Forge overrides any prank started before the test (e.g. in `setUp`), but it lets the user change the prank during the test
- Using this cheat in a fuzz test would result in an error

With this hypothetical `vm.consider`, I could write my test like this:

```solidity
function testFoo() external {
vm.consider(users.alice, users.bob); // succinct and declarative
assertEq(A, B);
assertEq(C, D);
assertEq(E, F);
}
```

Side notes:

- `vm.consider` is just a suggestion. I don't think it's a great name. Alternatives: `vm.regard,` `vm.rollPrank`, `vm.testPrank`.
- What I'm referring to in this feature request is not fuzzing. I want to run the test once with Alice as the caller, and once with Bob. I don't want to run the tests hundreds of times - these are unit tests I refer to.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.