Skip to content

Commit

Permalink
chore(cheatcodes): add more edge case tests on expect* cheatcodes (
Browse files Browse the repository at this point in the history
…#5135)

* chore: add edge-cases

* chore: add edge case covering #4920 (comment)
  • Loading branch information
Evalir authored Jun 12, 2023
1 parent 075d4d0 commit 4a871d6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 14 deletions.
31 changes: 31 additions & 0 deletions testdata/cheats/ExpectCall.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ contract NestedContract {
function hello() public pure returns (string memory) {
return "hi";
}

function sumInPlace(uint256 a, uint256 b) public view returns (uint256) {
return a + b + 42;
}
}

contract ExpectCallTest is DSTest {
Expand Down Expand Up @@ -133,6 +137,33 @@ contract ExpectCallTest is DSTest {
target.hello();
}

// We should be able to match whichever function is called inside of the next call.
// Even multiple functions.
function testExpectCallMultipleFunctions() public {
Contract inner = new Contract();
NestedContract target = new NestedContract(inner);

cheats.expectCall(address(target), abi.encodeWithSelector(target.forwardPay.selector));
cheats.expectCall(address(inner), abi.encodeWithSelector(inner.pay.selector));
this.exposed_forwardPay(target);
}

// We should also be able to match multiple functions that happen one after another,
// but inside the next call.
function testExpectCallMultipleFunctionsFlattened() public {
Contract inner = new Contract();
NestedContract target = new NestedContract(inner);

cheats.expectCall(address(target), abi.encodeWithSelector(target.sumInPlace.selector));
cheats.expectCall(address(inner), abi.encodeWithSelector(inner.add.selector));
this.exposed_expectCallMultipleFunctionsFlattened(target, inner);
}

function exposed_expectCallMultipleFunctionsFlattened(NestedContract target, Contract inner) public {
target.sumInPlace(1, 1);
inner.add(1, 1);
}

function testExpectSelectorCall() public {
Contract target = new Contract();
cheats.expectCall(address(target), abi.encodeWithSelector(target.add.selector));
Expand Down
48 changes: 48 additions & 0 deletions testdata/cheats/ExpectEmit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ contract Emitter {
this.emitWindow();
}

// Used to test matching of consecutive different events
// split across subtree calls.
function emitSplitWindow() public {
this.emitWindow();
this.emitWindow();
}

function emitWindowAndOnTest(ExpectEmitTest t) public {
this.emitWindow();
t.emitLocal();
}

/// Ref: issue #1214
function doesNothing() public pure {}

Expand Down Expand Up @@ -117,6 +129,10 @@ contract ExpectEmitTest is DSTest {
emitter = new Emitter();
}

function emitLocal() public {
emit A(1);
}

function testFailExpectEmitDanglingNoReference() public {
cheats.expectEmit(false, false, false, false);
}
Expand Down Expand Up @@ -474,6 +490,27 @@ contract ExpectEmitTest is DSTest {
emitter.emitNestedWindow();
}

/// emitSplitWindow() emits events [[A, B, C, D, E], [A, B, C, D, E]]. Essentially, in an external call,
/// it emits the sequence of events twice at the same depth.
/// We should be able to match [A, A, B, C, D, E] as it's all in the next call, no matter
/// if they're emitted on subcalls at the same depth (but with correct ordering).
function testCanMatchConsecutiveSubtreeEvents() public {
cheats.expectEmit(true, false, false, true);
emit A(1);
cheats.expectEmit(true, false, false, true);
emit A(1);
cheats.expectEmit(true, false, false, true);
emit B(2);
cheats.expectEmit(true, false, false, true);
emit C(3);
cheats.expectEmit(true, false, false, true);
emit D(4);
cheats.expectEmit(true, false, false, true);
emit E(5);

emitter.emitSplitWindow();
}

/// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.
/// We should be able to match [A, C, E, A, C, E] in that order, as these are emitted twice.
function testCanMatchRepeatedEvents() public {
Expand Down Expand Up @@ -521,6 +558,17 @@ contract ExpectEmitTest is DSTest {
emitter.emitWindow();
}

/// emitWindowAndOnTest emits [[A, B, C, D, E], [A]]. The interesting bit is that the
/// second call that emits [A] is on this same contract. We should still be able to match
/// [A, A] as the call made to this contract is still external.
function testEmitWindowAndOnTest() public {
cheats.expectEmit(true, false, false, true);
emit A(1);
cheats.expectEmit(true, false, false, true);
emit A(1);
emitter.emitWindowAndOnTest(this);
}

/// This test will fail if we check that all expected logs were emitted
/// after every call from the same depth as the call that invoked the cheatcode.
///
Expand Down
14 changes: 0 additions & 14 deletions testdata/cheats/ExpectRevert.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,4 @@ contract ExpectRevertTest is DSTest {
function testFailExpectRevertDangling() public {
cheats.expectRevert("dangling");
}

// This is now illegal behavior for expectRevert.
// This test would've previously passed as expectRevert
// would also check reverts at the test level, not only
// at the immediate next call.
// This allowed cheatcodes to be checked for reverts,
// which actually shouldn't have been possible as cheatcodes
// are supposed to be bypassed for all expect* checks.
// function testExpectRevertInvalidEnv() public {
// cheats.expectRevert(
// "Failed to get environment variable `_testExpectRevertInvalidEnv` as type `string`: environment variable not found"
// );
// string memory val = cheats.envString("_testExpectRevertInvalidEnv");
// }
}

0 comments on commit 4a871d6

Please sign in to comment.