-
Notifications
You must be signed in to change notification settings - Fork 2
Impl unit tests #16
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
Merged
Merged
Impl unit tests #16
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
c72f295
feat: add unit tests
YukiTsuchida f7a8a05
refactor: enhance comments for deployment artifacts and writeBack fun…
YukiTsuchida e60c231
fix: update test to use AUTH_MODE_EXTENSION for onContractCall
YukiTsuchida b24e48a
test: update onContractCall test to check for callInfo length of two
YukiTsuchida 19ee209
fix: update coverage report workflow to filter LCOV and use filtered …
YukiTsuchida b9c33ad
fix: update coverage report to include IContractModule and ignore err…
YukiTsuchida ec5116b
fix: disable filtering of changed files in coverage report workflow
YukiTsuchida 48fda91
fix: add IAccessControl import and update interface support test
YukiTsuchida 7b019d8
fix: update coverage report to ignore errors and set minimum coverage…
YukiTsuchida d90e8de
fix: remove IContractModule from LCOV filtering in coverage report
YukiTsuchida 13d6bfc
refactor: rename test contracts and expose functions for better clarity
YukiTsuchida f7da2e0
fix: remove commented assertions for event emissions in TxAtomicSimpl…
YukiTsuchida a6fd5fe
fix: update vm.expectEmit to use harness address in TxAtomicSimpleTest
YukiTsuchida 51a84ae
refactor: standardize test function naming conventions for clarity
YukiTsuchida File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 |
|---|---|---|
|
|
@@ -41,7 +41,6 @@ import {ILightClient} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/02 | |
| contract DeployAll is Script, Config { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I split the function because solhint complained about function-max-lines (I wonder why it didn't complain before? I don't know why). |
||
| // === Deployment artifacts (written back to deployments.toml) === | ||
| IBCHandler public ibcHandler; | ||
|
|
||
| MockCrossContract public mockApp; | ||
| CrossSimpleModule public crossSimpleModule; | ||
| MockClient public mockClient; | ||
|
|
@@ -92,65 +91,96 @@ contract DeployAll is Script, Config { | |
| console2.log(" Initialized. port=%s, clientType=%s", portCross, mockClientType); | ||
| } | ||
|
|
||
| // ---------- entry ---------- | ||
| function run() external { | ||
| // 1) Load config with write-back enabled (stores results after deployment) | ||
| _loadConfig( | ||
| "./deployments.toml", | ||
| /*writeBack=*/ | ||
| true | ||
| ); | ||
| function _readConfig() | ||
| internal | ||
| returns ( | ||
| string memory mnemonic, | ||
| uint32 mnemonicIndex, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) | ||
| { | ||
| string memory m = config.get("mnemonic").toString(); | ||
| uint256 idxU256 = config.get("mnemonic_index").toUint256(); | ||
| require(idxU256 < 2 ** 32, "mnemonic_index too large"); | ||
| uint32 idx = uint32(idxU256); | ||
| bool dbg = config.get("debug_mode").toBool(); | ||
| string memory port = config.get("port_cross").toString(); | ||
| string memory cli = config.get("mock_client_type").toString(); | ||
| return (m, idx, dbg, port, cli); | ||
| } | ||
|
|
||
| uint256 chainId = block.chainid; | ||
| function _logConfig( | ||
| uint256 chainId, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType, | ||
| uint32 mnemonicIndex | ||
| ) internal { | ||
| console2.log("Deploying to chain:", chainId); | ||
|
|
||
| // 2) Read configuration values (resolved for the current chain) | ||
| // - Required: | ||
| // string: mnemonic | ||
| // uint: mnemonic_index | ||
| // bool: debug_mode | ||
| // string: port_cross | ||
| // string: mock_client_type | ||
| string memory mnemonic = config.get("mnemonic").toString(); | ||
| uint256 mnemonicIndexU256 = config.get("mnemonic_index").toUint256(); | ||
| // solhint-disable-next-line gas-strict-inequalities | ||
| require(mnemonicIndexU256 <= type(uint32).max, "mnemonic_index too large"); | ||
| uint32 mnemonicIndex = uint32(mnemonicIndexU256); | ||
|
|
||
| bool debugMode = config.get("debug_mode").toBool(); | ||
| string memory portCross = config.get("port_cross").toString(); | ||
| string memory mockClientType = config.get("mock_client_type").toString(); | ||
|
|
||
| console2.log("Config:"); | ||
| console2.log(" debug_mode :", debugMode); | ||
| console2.log(" port_cross :", portCross); | ||
| console2.log(" mock_client_type:", mockClientType); | ||
| console2.log(" mnemonic_index :", mnemonicIndex); | ||
| } | ||
|
|
||
| // 3) Derive deployer private key from mnemonic + index (Foundry cheatcode) | ||
| uint256 deployerPk = vm.deriveKey(mnemonic, mnemonicIndex); | ||
| address deployer = vm.addr(deployerPk); | ||
| console2.log("Deployer:", deployer); | ||
| function _deriveDeployer(string memory mnemonic, uint32 mnemonicIndex) | ||
| internal | ||
| returns (uint256 deployerPk, address deployer) | ||
| { | ||
| uint256 pk = vm.deriveKey(mnemonic, mnemonicIndex); | ||
| address addr = vm.addr(pk); | ||
| console2.log("Deployer:", addr); | ||
| return (pk, addr); | ||
| } | ||
|
|
||
| // 4) Deploy + Initialize (single broadcast session) | ||
| function _broadcastDeployAndInit( | ||
| uint256 deployerPk, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) internal { | ||
| vm.startBroadcast(deployerPk); | ||
|
|
||
| ibcHandler = _deployCore(); | ||
| (mockApp, crossSimpleModule, mockClient) = _deployApp(ibcHandler, debugMode); | ||
| _initialize(ibcHandler, crossSimpleModule, portCross, mockClientType, mockClient); | ||
|
|
||
| vm.stopBroadcast(); | ||
| } | ||
|
|
||
| // 5) Write back: save addresses & metadata to deployments.toml | ||
| // (addresses go under <chain>.address.*, meta under <chain>.meta.*) | ||
| function _writeBack(address deployer) internal { | ||
| // save addresses & metadata to deployments.toml | ||
| // (addresses go under <chain>.address.*, meta under <chain>.meta.*) | ||
| config.set("ibc_handler", address(ibcHandler)); | ||
| config.set("mock_cross_contract", address(mockApp)); | ||
| config.set("cross_simple_module", address(crossSimpleModule)); | ||
| config.set("mock_client", address(mockClient)); | ||
|
|
||
| // Meta | ||
| config.set("deployer", deployer); | ||
|
|
||
| console2.log("\nDeployment complete! Addresses saved to deployments.toml"); | ||
| } | ||
|
|
||
| // ---------- entry ---------- | ||
| function run() external { | ||
| _loadConfig("./deployments.toml", true); | ||
|
|
||
| uint256 chainId = block.chainid; | ||
| ( | ||
| string memory mnemonic, | ||
| uint32 mnemonicIndex, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) = _readConfig(); | ||
|
|
||
| _logConfig(chainId, debugMode, portCross, mockClientType, mnemonicIndex); | ||
|
|
||
| (uint256 deployerPk, address deployer) = _deriveDeployer(mnemonic, mnemonicIndex); | ||
|
|
||
| _broadcastDeployAndInit(deployerPk, debugMode, portCross, mockClientType); | ||
|
|
||
| _writeBack(deployer); | ||
| } | ||
| } | ||
This file contains hidden or 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,198 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // solhint-disable one-contract-per-file, func-name-mixedcase | ||
| pragma solidity ^0.8.20; | ||
|
|
||
| import "forge-std/src/Test.sol"; | ||
|
|
||
| import "../src/core/CrossModule.sol"; | ||
| import { | ||
| IIBCModule, | ||
| IIBCModuleInitializer | ||
| } from "@hyperledger-labs/yui-ibc-solidity/contracts/core/26-router/IIBCModule.sol"; | ||
| import {IIBCHandler} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/25-handler/IIBCHandler.sol"; | ||
| import {Packet} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/04-channel/IIBCChannel.sol"; | ||
|
|
||
| import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; | ||
|
|
||
| contract DummyHandler {} | ||
|
|
||
| contract TestableCrossModule is CrossModule { | ||
| uint256 public recvCount; | ||
| uint256 public ackCount; | ||
| uint256 public timeoutCount; | ||
| bytes public lastAckArg; | ||
|
|
||
| constructor(IIBCHandler h) CrossModule(h) {} | ||
|
|
||
| function handlePacket( | ||
| Packet memory /*packet*/ | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| returns (bytes memory) | ||
| { | ||
| ++recvCount; | ||
| return bytes("ack-ok"); | ||
| } | ||
|
|
||
| function handleAcknowledgement( | ||
| Packet memory, | ||
| /*packet*/ | ||
| bytes memory acknowledgement | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| { | ||
| ++ackCount; | ||
| lastAckArg = acknowledgement; | ||
| } | ||
|
|
||
| function handleTimeout( | ||
| Packet calldata /*packet*/ | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| { | ||
| ++timeoutCount; | ||
| } | ||
| } | ||
|
|
||
| contract CrossModuleTest is Test { | ||
| DummyHandler private handler; | ||
| TestableCrossModule private mod; | ||
| Packet internal _emptyPacket; | ||
|
|
||
| function setUp() public { | ||
| handler = new DummyHandler(); | ||
| mod = new TestableCrossModule(IIBCHandler(address(handler))); | ||
| } | ||
|
|
||
| function test_constructor_GrantsIbcRoleToHandler() public { | ||
| assertTrue(mod.hasRole(mod.IBC_ROLE(), address(handler))); | ||
| } | ||
|
|
||
| function test_supportsInterface_ReturnsTrueForIIBCAndIAccessControlAndFalseForUnsupported() public view { | ||
| assertTrue(mod.supportsInterface(type(IIBCModule).interfaceId)); | ||
| assertTrue(mod.supportsInterface(type(IIBCModuleInitializer).interfaceId)); | ||
| assertTrue(mod.supportsInterface(type(IAccessControl).interfaceId)); | ||
| assertFalse(mod.supportsInterface(0xDEADBEEF)); | ||
| } | ||
|
|
||
| function test_onRecvPacket_CallsHandlerAndReturnsAckWhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| bytes memory ack = mod.onRecvPacket(_emptyPacket, address(0)); | ||
| assertEq(ack, bytes("ack-ok")); | ||
| assertEq(mod.recvCount(), 1); | ||
| } | ||
|
|
||
| function test_onRecvPacket_RevertWhen_CallerLacksIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onRecvPacket(_emptyPacket, address(0)); | ||
| } | ||
|
|
||
| function test_onAcknowledgementPacket_CallsHandlerWhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| mod.onAcknowledgementPacket(_emptyPacket, bytes("ack123"), address(0)); | ||
| assertEq(mod.ackCount(), 1); | ||
| assertEq(mod.lastAckArg(), bytes("ack123")); | ||
| } | ||
|
|
||
| function test_onAcknowledgementPacket_RevertWhen_CallerLacksIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onAcknowledgementPacket(_emptyPacket, bytes("ack"), address(0)); | ||
| } | ||
|
|
||
| function test_onTimeoutPacket_CallsHandlerWhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| mod.onTimeoutPacket(_emptyPacket, address(0)); | ||
| assertEq(mod.timeoutCount(), 1); | ||
| } | ||
|
|
||
| function test_onTimeoutPacket_RevertWhen_CallerLacksIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onTimeoutPacket(_emptyPacket, address(0)); | ||
| } | ||
|
|
||
| function test_onChanOpenInit_ReturnsSelfAndVersionWhenCallerHasRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenInit memory m; | ||
| m.version = "v1"; | ||
| vm.prank(address(handler)); | ||
| (address moduleAddr, string memory version) = mod.onChanOpenInit(m); | ||
| assertEq(moduleAddr, address(mod)); | ||
| assertEq(version, "v1"); | ||
| } | ||
|
|
||
| function test_onChanOpenInit_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenInit memory m; | ||
| m.version = "v1"; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenInit(m); | ||
| } | ||
|
|
||
| function test_onChanOpenTry_ReturnsSelfAndCounterpartyVersionWhenCallerHasRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenTry memory m; | ||
| m.counterpartyVersion = "cp-v1"; | ||
| vm.prank(address(handler)); | ||
| (address moduleAddr, string memory version) = mod.onChanOpenTry(m); | ||
| assertEq(moduleAddr, address(mod)); | ||
| assertEq(version, "cp-v1"); | ||
| } | ||
|
|
||
| function test_onChanOpenTry_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenTry memory m; | ||
| m.counterpartyVersion = "cp-v1"; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenTry(m); | ||
| } | ||
|
|
||
| function test_onChanOpenAck_SucceedsWhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanOpenAck memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanOpenAck(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanOpenAck_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModule.MsgOnChanOpenAck memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenAck(m); | ||
| } | ||
|
|
||
| function test_onChanOpenConfirm_SucceedsWhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanOpenConfirm memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanOpenConfirm(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanOpenConfirm_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModule.MsgOnChanOpenConfirm memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenConfirm(m); | ||
| } | ||
|
|
||
| function test_onChanCloseInit_SucceedsWhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanCloseInit memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanCloseInit(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanCloseInit_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModule.MsgOnChanCloseInit memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanCloseInit(m); | ||
| } | ||
|
|
||
| function test_onChanCloseConfirm_SucceedsWhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanCloseConfirm memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanCloseConfirm(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanCloseConfirm_RevertWhen_CallerLacksIbcRole() public { | ||
| IIBCModule.MsgOnChanCloseConfirm memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanCloseConfirm(m); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exclude because coverage measurement is not required