Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions test/src/concrete/Flow.construction.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import {Vm} from "forge-std/Test.sol";
import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol";
import {FlowTest} from "test/abstract/FlowTest.sol";
import {EmptyFlowConfig} from "src/error/ErrFlow.sol";
import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol";
import {LibLogHelper} from "test/lib/LibLogHelper.sol";

contract FlowConstructionTest is FlowTest {
using LibLogHelper for Vm.Log[];
function testFlowConstructionEmptyConfigReverts() external {
EvaluableConfigV3[] memory emptyConfig = new EvaluableConfigV3[](0);
address impl = deployFlowImplementation();
Expand Down Expand Up @@ -37,4 +40,43 @@ contract FlowConstructionTest is FlowTest {
assertEq(sender, address(I_CLONE_FACTORY), "wrong sender in Initialize event");
assertEq(keccak256(abi.encode(flowConfig)), keccak256(abi.encode(config)), "wrong compare Structs");
}

/// `flowInit` MUST emit one `FlowInitialized(sender, evaluable)` per
/// registered config, with `sender` equal to the clone-factory caller
/// and `evaluable` equal to the deployer-returned `(interpreter, store,
/// expression)` triple. Pinning this prevents a future change that
/// drops the event, mismatches the sender, or skips emissions on
/// duplicate configs.
/// forge-config: default.fuzz.runs = 100
function testFlowConstructionEmitsFlowInitializedPerConfig(address[] memory expressions) external {
uint256 length = bound(expressions.length, 1, 5);
assembly ("memory-safe") {
mstore(expressions, length)
}

EvaluableConfigV3[] memory flowConfig = new EvaluableConfigV3[](length);
for (uint256 i = 0; i < length; i++) {
// Distinct (bytecode, constants) per config so each call to the
// deployer mock returns a distinct `expression`.
bytes memory bytecode = abi.encodePacked(uint256(i));
uint256[] memory constants = new uint256[](0);
expressionDeployerDeployExpression2MockCall(bytecode, constants, expressions[i], bytes(hex"0007"));
flowConfig[i] = EvaluableConfigV3(DEPLOYER, bytecode, constants);
}

vm.recordLogs();
I_CLONE_FACTORY.clone(deployFlowImplementation(), abi.encode(flowConfig));

Vm.Log[] memory all = vm.getRecordedLogs();
Vm.Log[] memory init = all.findEvents(keccak256("FlowInitialized(address,(address,address,address))"));

assertEq(init.length, length, "FlowInitialized count");
for (uint256 i = 0; i < length; i++) {
(address sender, EvaluableV2 memory ev) = abi.decode(init[i].data, (address, EvaluableV2));
assertEq(sender, address(I_CLONE_FACTORY), "FlowInitialized sender");
assertEq(address(ev.interpreter), address(INTERPRETER), "FlowInitialized interpreter");
assertEq(address(ev.store), address(STORE), "FlowInitialized store");
assertEq(ev.expression, expressions[i], "FlowInitialized expression");
}
}
}
Loading