diff --git a/test/unit/concrete/container/disable-module/disableModule.tree b/test/unit/concrete/container/disable-module/disableModule.tree index 261feeda..640e6942 100644 --- a/test/unit/concrete/container/disable-module/disableModule.tree +++ b/test/unit/concrete/container/disable-module/disableModule.tree @@ -1,4 +1,4 @@ -enableModule.t.sol +disableModule.t.sol ├── when the caller IS NOT the container owner │ └── it should revert with the {Unauthorized} error └── when the caller IS the container owner diff --git a/test/unit/concrete/container/transfer-ownership/transferOwnership.t.sol b/test/unit/concrete/container/transfer-ownership/transferOwnership.t.sol new file mode 100644 index 00000000..fe73e71b --- /dev/null +++ b/test/unit/concrete/container/transfer-ownership/transferOwnership.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.26; + +import { Container_Unit_Concrete_Test } from "../Container.t.sol"; +import { MockModule } from "../../../../mocks/MockModule.sol"; +import { Events } from "../../../../utils/Events.sol"; +import { Errors } from "../../../../utils/Errors.sol"; + +contract TransferOwnership_Unit_Concrete_Test is Container_Unit_Concrete_Test { + function setUp() public virtual override { + Container_Unit_Concrete_Test.setUp(); + } + + function test_RevertWhen_CallerNotOwner() external { + // Make Bob the caller for this test suite who is not the owner of the container + vm.startPrank({ msgSender: users.bob }); + + // Expect the next call to revert with the {Unauthorized} error + vm.expectRevert(Errors.Unauthorized.selector); + + // Run the test + container.transferOwnership({ newOwner: users.eve }); + } + + modifier whenCallerOwner() { + // Make Eve the caller for the next test suite as she's the owner of the container + vm.startPrank({ msgSender: users.eve }); + _; + } + + function test_RevertWhen_InvalidOwnerZeroAddress() external whenCallerOwner { + // Expect the next call to revert with the {InvalidOwnerZeroAddress} + vm.expectRevert(Errors.InvalidOwnerZeroAddress.selector); + + // Run the test + container.transferOwnership({ newOwner: address(0) }); + } + + modifier whenNonZeroOwnerAddress() { + _; + } + + function test_TransferOwnership() external whenCallerOwner whenNonZeroOwnerAddress { + // Expect the {OwnershipTransferred} to be emitted + vm.expectEmit(); + emit Events.OwnershipTransferred({ oldOwner: users.eve, newOwner: users.bob }); + + // Run the test + container.transferOwnership({ newOwner: users.bob }); + + // Assert the actual and expected owner + address actualOwner = container.owner(); + assertEq(actualOwner, users.bob); + } +} diff --git a/test/unit/concrete/container/transfer-ownership/transferOwnership.tree b/test/unit/concrete/container/transfer-ownership/transferOwnership.tree new file mode 100644 index 00000000..836cc7f7 --- /dev/null +++ b/test/unit/concrete/container/transfer-ownership/transferOwnership.tree @@ -0,0 +1,9 @@ +transferOwnership.t.sol +├── when the caller IS NOT the container owner +│ └── it should revert with the {Unauthorized} error +└── when the caller IS the container owner + ├── when the new owner address IS the zero address + │ └── it should revert with the {InvalidOwnerZeroAddress} error + └── when the new owner address IS NOT the zero address + ├── it should update the owner + └── it should emit a {OwnershipTransferred} event diff --git a/test/utils/Errors.sol b/test/utils/Errors.sol index d8cd31f0..7afdefea 100644 --- a/test/utils/Errors.sol +++ b/test/utils/Errors.sol @@ -101,4 +101,11 @@ library Errors { /// @notice Thrown when `msg.sender` is not the stream's sender error SablierV2Lockup_Unauthorized(uint256 streamId, address caller); + + /*////////////////////////////////////////////////////////////////////////// + OWNABLE + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when attempting to transfer ownership to the zero address + error InvalidOwnerZeroAddress(); } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 3e188fc1..cecbb8c2 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -69,4 +69,13 @@ abstract contract Events { /// @notice Emitted when an invoice is canceled /// @param id The ID of the invoice event InvoiceCanceled(uint256 indexed id); + + /*////////////////////////////////////////////////////////////////////////// + OWNABLE + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when the address of the owner is updated + /// @param oldOwner The address of the previous owner + /// @param newOwner The address of the new owner + event OwnershipTransferred(address indexed oldOwner, address newOwner); }