// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "forge-std/Test.sol"; import "../contracts/LabContract.sol"; import "../contracts/interfaces/ILabRegistry.sol"; import "../contracts/LabHelper.sol"; contract LabContractTest is Test { LabContract public labContract; ILabRegistry public mockLabRegistry; LabHelper public mockLabHelper; address public owner; address public experimentCreator; uint256 public initialFunding; function setUp() public { owner = makeAddr("owner"); experimentCreator = makeAddr("experimentCreator"); vm.startPrank(owner); mockLabRegistry = ILabRegistry(makeAddr("labRegistry")); mockLabHelper = new LabHelper(); labContract = new LabContract(address(mockLabRegistry), address(mockLabHelper)); vm.stopPrank(); initialFunding = 1 ether; } function test_Constructor() public { assertEq(address(labContract.labRegistry()), address(mockLabRegistry), "Registry address mismatch"); assertEq(address(labContract.labHelper()), address(mockLabHelper), "Helper address mismatch"); } function test_CreateExperiment() public { vm.startPrank(experimentCreator); bytes32 configHash = keccak256("test_config"); vm.mockCall( address(mockLabRegistry), abi.encodeWithSelector(ILabRegistry.registerExperiment.selector), abi.encode(true) ); vm.expectEmit(true, true, false, true); emit LabContract.ExperimentCreated( keccak256(abi.encodePacked(experimentCreator, block.timestamp, configHash)), experimentCreator, initialFunding ); bytes32 experimentId = labContract.createExperiment(initialFunding, configHash); LabContract.ExperimentConfig memory experiment = labContract.getExperimentDetails(experimentId); assertEq(experiment.creator, experimentCreator, "Creator mismatch"); assertEq(experiment.fundingAmount, initialFunding, "Funding amount mismatch"); assertTrue(experiment.isActive, "Experiment should be active"); assertEq(experiment.configHash, configHash, "Config hash mismatch"); vm.stopPrank(); } function testRevert_CreateExperiment_ZeroFunding() public { vm.startPrank(experimentCreator); bytes32 configHash = keccak256("test_config"); vm.expectRevert("Funding must be greater than zero"); labContract.createExperiment(0, configHash); vm.stopPrank(); } function testRevert_CreateExperiment_ZeroConfigHash() public { vm.startPrank(experimentCreator); vm.expectRevert("Invalid config hash"); labContract.createExperiment(initialFunding, bytes32(0)); vm.stopPrank(); } function test_UpdateExperimentStatus() public { vm.startPrank(experimentCreator); bytes32 configHash = keccak256("test_config"); vm.mockCall( address(mockLabRegistry), abi.encodeWithSelector(ILabRegistry.registerExperiment.selector), abi.encode(true) ); bytes32 experimentId = labContract.createExperiment(initialFunding, configHash); vm.expectEmit(true, false, false, true); emit LabContract.ExperimentUpdated(experimentId, false); labContract.updateExperimentStatus(experimentId, false); LabContract.ExperimentConfig memory experiment = labContract.getExperimentDetails(experimentId); assertFalse(experiment.isActive, "Experiment status not updated"); vm.stopPrank(); } function testRevert_UpdateExperimentStatus_UnauthorizedCaller() public { vm.startPrank(experimentCreator); bytes32 configHash = keccak256("test_config"); vm.mockCall( address(mockLabRegistry), abi.encodeWithSelector(ILabRegistry.registerExperiment.selector), abi.encode(true) ); bytes32 experimentId = labContract.createExperiment(initialFunding, configHash); vm.stopPrank(); address unauthorized = makeAddr("unauthorized"); vm.startPrank(unauthorized); vm.expectRevert("Only experiment creator can update status"); labContract.updateExperimentStatus(experimentId, false); vm.stopPrank(); } function test_WithdrawFunds() public { vm.startPrank(experimentCreator); bytes32 configHash = keccak256("test_config"); vm.mockCall( address(mockLabRegistry), abi.encodeWithSelector(ILabRegistry.registerExperiment.selector), abi.encode(true) ); bytes32 experimentId = labContract.createExperiment(initialFunding, configHash); vm.deal(address(labContract), initialFunding); uint256 withdrawAmount = 0.5 ether;