Context
After looking at this documentation about fuzz testing, I tried to apply it to the setUp()
function in my test. However, that throws an error. I would like to test that the random stuff that I like to test, does not only work for that one hardcoded setUp()
configuration that I choose, but also works for different configurations. The simple solution is to copy the initialization content of the SetUp()
function into the testFuzz_
function, however that leads to a lot of duplicate code.
Question
Hence, I was wondering: is possible to let foundry run the setUp()
function with random parameters?
Code
To make it into a concrete question, here is the relevant code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.25 <0.9.0;
import "forge-std/src/Vm.sol" as vm;
import { PRBTest } from "@prb/test/src/PRBTest.sol";
import { StdCheats } from "forge-std/src/StdCheats.sol";
import { DecentralisedInvestmentManager } from "../../../../src/DecentralisedInvestmentManager.sol";
import { InitialiseDim } from "test/InitialiseDim.sol";
import { console2 } from "forge-std/src/console2.sol";
interface IFuzzTriggerReturnAll {
function setUp(
uint256 firstCeiling,
uint256 secondCeiling,
uint256 thirdCeiling,
uint8 firstMultiple,
uint8 secondMultiple,
uint8 thirdMultiple
) external;
function testFuzzRaisePeriodReturnSingleInvestment() external;
function testFuzzKeepInvestmentsForSuccesfullRaise() external;
}
/**
Tests whether the _dim.triggerReturnAll() function ensures the investments are:
- returned if the investment target is not reached, after the raisePeriod has passed.
- not returned if the investment target is reached, after the raisePeriod has passed.
TODO: test whether the investments are:
- not returned if the investment target is not reached, before the raisePeriod has passed.
- not returned if the investment target is reached, before the raisePeriod has passed.
*/
contract FuzzTriggerReturnAll is PRBTest, StdCheats, IFuzzTriggerReturnAll {
address internal _projectLead;
address payable private _firstInvestorWallet;
address payable private _secondInvestorWallet;
uint256 private _firstInvestmentAmount;
DecentralisedInvestmentManager private _dim;
/// @dev A function invoked before each test case is run.
function setUp(
uint256 firstCeiling,
uint256 secondCeiling,
uint256 thirdCeiling,
uint8 firstMultiple,
uint8 secondMultiple,
uint8 thirdMultiple
) public virtual override {
// Instantiate the attribute for the contract-under-test.
_projectLead = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
uint256[] memory ceilings = new uint256[](3);
ceilings[0] = firstCeiling;
ceilings[1] = secondCeiling;
ceilings[2] = thirdCeiling;
uint8[] memory multiples = new uint8[](3);
multiples[0] = firstMultiple;
multiples[1] = secondMultiple;
multiples[2] = thirdMultiple;
console2.log("Hi");
if (firstCeiling < secondCeiling && secondCeiling < thirdCeiling) {
InitialiseDim initDim = new InitialiseDim({
ceilings: ceilings,
multiples: multiples,
raisePeriod: 12 weeks,
investmentTarget: 0.6 ether,
projectLead: _projectLead,
projectLeadFracNumerator: 4,
projectLeadFracDenominator: 10
});
_dim = initDim.getDim();
_firstInvestorWallet = payable(address(uint160(uint256(keccak256(bytes("1"))))));
deal(_firstInvestorWallet, 3 ether);
_secondInvestorWallet = payable(address(uint160(uint256(keccak256(bytes("2"))))));
deal(_secondInvestorWallet, 4 ether);
_firstInvestmentAmount = 0.5 ether;
// Set the msg.sender address to that of the _firstInvestorWallet for the next call.
vm.prank(address(_firstInvestorWallet));
// Send investment directly from the investor wallet into the receiveInvestment function.
_dim.receiveInvestment{ value: _firstInvestmentAmount }();
assertEq(_dim.getTierInvestmentLength(), 1, "Error, the _tierInvestments.length was not as expected.");
}
}
/**
@dev The investor has invested 0.5 eth, and the investment target is 0.6 eth after 12 weeks.
So the investment target is not reached, so all the funds should be returned.
*/
function testFuzzRaisePeriodReturnSingleInvestment() public virtual override {
// Simulate 3 weeks passing by
// solhint-disable-next-line not-rely-on-time
vm.warp(block.timestamp + 3 weeks);
vm.expectRevert(bytes("The fund raising period has not passed yet."));
_dim.triggerReturnAll();
assertEq(address(_dim).balance, 0.5 ether, "The _dim did not contain 0.5 ether.");
// solhint-disable-next-line not-rely-on-time
vm.warp(block.timestamp + 15 weeks);
vm.prank(_projectLead);
_dim.triggerReturnAll();
assertEq(address(_dim).balance, 0 ether, "The _dim did not contain 0 ether after returning all investments.");
}
/**
Tests whether two investments together that reach the investment target result prevents the
funds from being returned to the investors. (Because if the investment target is reached, the funds
should be allocated to development, instead of being returned.) */
function testFuzzKeepInvestmentsForSuccesfullRaise() public virtual override {
// Simulate 3 weeks passing by
// solhint-disable-next-line not-rely-on-time
vm.warp(block.timestamp + 3 weeks);
vm.expectRevert(bytes("The fund raising period has not passed yet."));
_dim.triggerReturnAll();
assertEq(address(_dim).balance, 0.5 ether, "The _dim did not contain 0.5 ether.");
// Set the msg.sender address to that of the _firstInvestorWallet for the next call.
vm.prank(address(_firstInvestorWallet));
// Send investment directly from the investor wallet into the receiveInvestment function.
_dim.receiveInvestment{ value: 2.5 ether }();
// solhint-disable-next-line not-rely-on-time
vm.warp(block.timestamp + 15 weeks);
vm.expectRevert(bytes("Investment target reached!"));
_dim.triggerReturnAll();
assertEq(address(_dim).balance, 3 ether, "The _dim did not contain 3 ether.");
}
}
Output
Running the code above with:
clear && forge test -vvvvvv --match-test testFuzz
yields:
Ran 1 test for test/functional/DecentralisedInvestmentManager/triggerReturnAll/FuzzTriggerReturnAll.t.sol:FuzzTriggerReturnAll
[FAIL. Reason: setup failed: EvmError: Revert] setUp() (gas: 0)
Traces:
[149] FuzzTriggerReturnAll::setUp()
└─ ← [Revert] EvmError: Revert
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.18ms (0.00ns CPU time)
Ran 1 test suite in 591.61ms (1.18ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/functional/DecentralisedInvestmentManager/triggerReturnAll/FuzzTriggerReturnAll.t.sol:FuzzTriggerReturnAll
[FAIL. Reason: setup failed: EvmError: Revert] setUp() (gas: 0)
Encountered a total of 1 failing tests, 0 tests succeeded