-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
17dc651
commit 1049ab8
Showing
4 changed files
with
217 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.22; | ||
|
||
import { Batch } from "src/abstracts/Batch.sol"; | ||
|
||
contract BatchMock is Batch { | ||
error InvalidNumber(uint256); | ||
|
||
uint256 internal _number = 10; | ||
|
||
// A view only function. | ||
function getNumber() public view returns (uint256) { | ||
return _number; | ||
} | ||
|
||
// A view only function that reverts. | ||
function getNumberAndRevert() public pure returns (uint256) { | ||
revert InvalidNumber(1); | ||
} | ||
|
||
// A state changing function with no return value. | ||
function setNumber(uint256 number) public { | ||
_number = number; | ||
} | ||
|
||
// A state changing function with payable modifier and return value. | ||
function setNumberWithPayableAndReturn(uint256 number) public payable returns (uint256) { | ||
_number = number; | ||
return _number; | ||
} | ||
|
||
// A state changing function with payable modifier but reverts with custom error. | ||
function setNumberWithPayableAndRevert(uint256 number) public payable { | ||
_number = number; | ||
revert InvalidNumber(number); | ||
} | ||
|
||
// A state changing function with payable modifier but reverts with string error. | ||
function setNumberWithPayableAndRevertString(uint256 number) public payable { | ||
_number = number; | ||
revert("You cannot pass"); | ||
} | ||
|
||
// A state changing function with payable modifier and no return value. | ||
function setNumberWithPayable(uint256 number) public payable { | ||
_number = number; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.22; | ||
|
||
import { Base_Test } from "../../../Base.t.sol"; | ||
import { BatchMock } from "../../../mocks/BatchMock.sol"; | ||
|
||
contract Batch_Unit_Concrete_Test is Base_Test { | ||
BatchMock internal batchMock; | ||
bytes[] internal calls; | ||
bytes[] internal results; | ||
uint256 internal newNumber = 100; | ||
|
||
function setUp() public virtual override { | ||
Base_Test.setUp(); | ||
|
||
batchMock = new BatchMock(); | ||
} | ||
|
||
function test_RevertWhen_FunctionDoesNotExist() external { | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeWithSignature("nonExistentFunction()"); | ||
|
||
// It should revert. | ||
vm.expectRevert(bytes("")); | ||
batchMock.batch(calls); | ||
} | ||
|
||
modifier whenFunctionExists() { | ||
_; | ||
} | ||
|
||
modifier givenNonStateChangingFunction() { | ||
_; | ||
} | ||
|
||
function test_RevertWhen_FunctionReverts() external whenFunctionExists givenNonStateChangingFunction { | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.getNumberAndRevert, ()); | ||
|
||
// It should revert. | ||
vm.expectRevert(abi.encodeWithSelector(BatchMock.InvalidNumber.selector, 1)); | ||
batchMock.batch(calls); | ||
} | ||
|
||
function test_WhenFunctionNotRevert() external whenFunctionExists givenNonStateChangingFunction { | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.getNumber, ()); | ||
results = batchMock.batch(calls); | ||
|
||
// It should return expected value. | ||
assertEq(results.length, 1); | ||
assertEq(abi.decode(results[0], (uint256)), 10); | ||
} | ||
|
||
modifier givenStateChangingFunction() { | ||
_; | ||
} | ||
|
||
modifier whenNotPayable() { | ||
_; | ||
} | ||
|
||
function test_RevertWhen_BatchIncludesETHValue() | ||
external | ||
whenFunctionExists | ||
givenStateChangingFunction | ||
whenNotPayable | ||
{ | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumber, (newNumber)); | ||
|
||
// It should revert. | ||
vm.expectRevert(bytes("")); | ||
batchMock.batch{ value: 1 wei }(calls); | ||
} | ||
|
||
function test_WhenBatchNotIncludeETHValue() external whenFunctionExists givenStateChangingFunction whenNotPayable { | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumber, (newNumber)); | ||
|
||
results = batchMock.batch(calls); | ||
|
||
// It should return empty value. | ||
assertEq(results.length, 1); | ||
assertEq(results[0], hex""); | ||
} | ||
|
||
modifier whenPayable() { | ||
_; | ||
} | ||
|
||
function test_RevertWhen_FunctionRevertsWithCustomError() | ||
external | ||
whenFunctionExists | ||
givenStateChangingFunction | ||
whenPayable | ||
{ | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumberWithPayableAndRevert, (newNumber)); | ||
|
||
// It should revert. | ||
vm.expectRevert(abi.encodeWithSelector(BatchMock.InvalidNumber.selector, newNumber)); | ||
batchMock.batch{ value: 1 wei }(calls); | ||
} | ||
|
||
function test_RevertWhen_FunctionRevertsWithStringError() | ||
external | ||
whenFunctionExists | ||
givenStateChangingFunction | ||
whenPayable | ||
{ | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumberWithPayableAndRevertString, (newNumber)); | ||
|
||
// It should revert. | ||
vm.expectRevert("You cannot pass"); | ||
batchMock.batch{ value: 1 wei }(calls); | ||
} | ||
|
||
function test_WhenFunctionReturnsAValue() external whenFunctionExists givenStateChangingFunction whenPayable { | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumberWithPayableAndReturn, (newNumber)); | ||
results = batchMock.batch{ value: 1 wei }(calls); | ||
|
||
// It should return expected value. | ||
assertEq(results.length, 1); | ||
assertEq(abi.decode(results[0], (uint256)), newNumber); | ||
} | ||
|
||
function test_WhenFunctionDoesNotReturnAValue() | ||
external | ||
whenFunctionExists | ||
givenStateChangingFunction | ||
whenPayable | ||
{ | ||
calls = new bytes[](1); | ||
calls[0] = abi.encodeCall(batchMock.setNumberWithPayable, (newNumber)); | ||
results = batchMock.batch{ value: 1 wei }(calls); | ||
|
||
// It should return empty value. | ||
assertEq(results.length, 1); | ||
assertEq(results[0], hex""); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Batch_Unit_Concrete_Test | ||
├── when function does not exist | ||
│ └── it should revert | ||
└── when function exists | ||
├── given non state changing function | ||
│ ├── when function reverts | ||
│ │ └── it should revert | ||
│ └── when function not revert | ||
│ └── it should return expected value | ||
└── given state changing function | ||
├── when not payable | ||
│ ├── when batch includes ETH value | ||
│ │ └── it should revert | ||
│ └── when batch not include ETH value | ||
│ └── it should return empty value | ||
└── when payable | ||
├── when function reverts with custom error | ||
│ └── it should revert | ||
├── when function reverts with string error | ||
│ └── it should revert | ||
├── when function returns a value | ||
│ └── it should return expected value | ||
└── when function does not return a value | ||
└── it should return empty value |