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

mockCall's calldata partial matching behaviour doesn't work as expected #1604

Closed
2 tasks done
AdithyaNarayan opened this issue May 13, 2022 · 2 comments · Fixed by #1619
Closed
2 tasks done

mockCall's calldata partial matching behaviour doesn't work as expected #1604

AdithyaNarayan opened this issue May 13, 2022 · 2 comments · Fixed by #1619
Assignees
Labels
A-cheatcodes Area: cheatcodes C-forge Command: forge Cmd-forge-test Command: forge test T-bug Type: bug

Comments

@AdithyaNarayan
Copy link
Contributor

AdithyaNarayan commented May 13, 2022

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 (4604a42 2022-05-12T00:04:28.117376+00:00)

What command(s) is the bug in?

forge test

Operating System

macOS (Apple Silicon)

Describe the bug

The mockCall's partial calldata matching is not working as expected.

import "forge-std/Test.sol";

contract Contract {
    function f(uint256 a, uint256 b) public pure returns(uint256) {
      return a + b; 
    }
}

contract ContractTest is Test {
    function setUp() public {}

    function testExample() public {
        Contract target = new Contract();

        vm.mockCall(address(target), abi.encodeWithSelector(target.f.selector), abi.encode(10)); 
        vm.mockCall(address(target), abi.encodeWithSelector(target.f.selector, 2), abi.encode(20)); 
        vm.mockCall(address(target), abi.encodeWithSelector(target.f.selector, 2, 3), abi.encode(30)); 

        assertEq(target.f(1, 2), 10);
        assertEq(target.f(2, 2), 20); // Expected: 20, Actual: 10
        assertEq(target.f(2, 3), 30);
    }
}

This is probably because of the way the partial matching works, since it check for a match, and if not found, iterates and returns the first match. In this case, it looks like the iteration is happening from least specific to most specific when it should be the other way around

@onbjerg
Copy link
Member

onbjerg commented May 13, 2022

It works in order of precedent IIRC, so you need to put vm.mockCall(address(target), abi.encodeWithSelector(target.f.selector), abi.encode(10)); last. If this is counter-intuitive we should consider addressing it in the book

@onbjerg onbjerg added Cmd-forge-test Command: forge test C-forge Command: forge A-cheatcodes Area: cheatcodes labels May 13, 2022
@AdithyaNarayan
Copy link
Contributor Author

I think since it uses a BTreeMap internally, seems like order of precedence is just the sorting order of Bytes which is lower to highest and hence, if there is no exact match, it chooses the most generic match. Tried with different ordering of the mockCalls, all seem to fail

@onbjerg onbjerg moved this from Todo to In Progress in Foundry May 15, 2022
Repository owner moved this from In Progress to Done in Foundry May 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cheatcodes Area: cheatcodes C-forge Command: forge Cmd-forge-test Command: forge test T-bug Type: bug
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants