fix(forge): expectCall with no count#4845
Conversation
expectCall with no countexpectCall with no count
expectCall with no countexpectCall with no count
mds1
left a comment
There was a problem hiding this comment.
Thanks! Agreed it makes sense to revert this back to the original behavior per the discussion in the prior PR
|
I don't think this is working as expected. I pulled the latest Forge: And our existing tests (which are using multiple standard Upgrading to the latest |
|
@reubenr0d mind taking another look at this? Do you an example where it broke @PaulRBerg? |
|
@mattsse sure, here's an example. Code Snippet
pragma solidity >=0.8.19 <0.9.0;
import { Test } from "forge-std/Test.sol";
contract Foo {
function func() external pure returns (uint256) {
return 1;
}
}
contract Bar {
Foo internal foo;
constructor(Foo foo_) {
foo = foo_;
}
function func(uint256 times) external view returns (uint256) {
for (uint256 i = 0; i < times; ++i) {
foo.func();
}
return 1;
}
}
contract ExpectCallTest is Test {
Foo internal foo = new Foo();
Bar internal bar = new Bar(foo);
// Fails on forge 0.2.0 (f128ff9 2023-04-29T00:16:05.704419000Z)
function test_MultipleExpectCalls_1() external {
vm.expectCall({ callee: address(foo), data: abi.encodeWithSelector(foo.func.selector) });
vm.expectCall({ callee: address(foo), data: abi.encodeWithSelector(foo.func.selector) });
bar.func({ times: 2 });
}
// Passes
function test_MultipleExpectCalls_2() external {
vm.expectCall({ callee: address(foo), data: abi.encodeWithSelector(foo.func.selector), count: uint64(2) });
bar.func({ times: 2 });
}
} |
|
Thanks for reporting, @PaulRBerg. This was also reported here: #4833 (comment) This needs some more work in that case! Just to clarify,
But this behaviour would be different from if
While in the older versions, when There are some conflicting ideas here; keen to hear on what you'll think on how we should proceed with this. |
|
Nice write up, so my thoughts are:
|
💯 This is actually a useful thing in and of itself; even if there had not been a path dependence on this behavior, I would have preferred Foundry to offer it because it is needed e.g. when fuzzing and the exact number of token transfers cannot be known in advance. Basically, when not passing |
|
@reubenr0d do you have an ETA for reverting the previous behavior as per point 1 above? Sorry to chase - it's just that our test suite is broken now, and the only ways to fix it are to either (i) remove certain |
agree, @reubenr0d do you have bandwidth to make this work? |
|
I’m a bit held up at the moment, but I should be able to get around to it later in the week. |
|
oof, this also broke a test in one of our repos: I guess ideally they would be in two separate test functions, but I should preserve this functionality as well I suppose. |
|
My guess is that a lot of Foundry repos have been affected by this breaking change - many of which will not manage to trace the issue to our discussion here, and will end up opening new issues or asking questions in the Telegram group. As a quick patch, I would suggest reverting the changes introduced by this PR (as well as #4833) until the additive behavior of |
|
I can try to fix this asap but need a test case that I can just use. |
|
Doesn't my code snippet from above work, @mattsse? We ended up disabling all of our |
Motivation
#4833 introduced a breaking change to
expectCallwhereby if nocountwas specified it would default to 1. This PR preserves the older behaviour of checking that a call is made at least once ifcountis not specified.Solution
Change
counttype toOption<u64>and revert to older behaviour ifis_none()