Skip to content
Merged
Show file tree
Hide file tree
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
29 changes: 29 additions & 0 deletions test/unit/ActivationRegistry/activate_revertOrder.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IActivationRegistry} from "src/interfaces/IActivationRegistry.sol";

import {ActivationRegistryTest} from "test/lib/ActivationRegistryTest.sol";

contract ActivationRegistryActivateRevertOrderTest is ActivationRegistryTest {
/// @notice Verifies Unauthorized fires before AlreadyActivated when caller is not admin
/// and the feature is already activated
/// @dev Revert order: access-control check precedes state validation; a non-admin caller
/// never reaches the AlreadyActivated guard regardless of feature state.
/// Fuzz: any caller that is not the activationAdmin, any feature id.
function test_activate_revertOrder_unauthorized_beats_alreadyActivated(address caller, bytes32 feature) public {
_assumeValidCaller(caller);
vm.assume(caller != activationAdmin);

// Activate the feature as admin so it is already activated, establishing
// the precondition that AlreadyActivated *could* fire for an admin caller.
vm.prank(activationAdmin);
activationRegistry.activate(feature);

// A non-admin caller must see Unauthorized, not AlreadyActivated,
// because the access-control check in activate fires first.
vm.expectRevert(abi.encodeWithSelector(IActivationRegistry.Unauthorized.selector, caller));
vm.prank(caller);
activationRegistry.activate(feature);
}
}
29 changes: 29 additions & 0 deletions test/unit/ActivationRegistry/deactivate_revertOrder.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IActivationRegistry} from "src/interfaces/IActivationRegistry.sol";

import {ActivationRegistryTest} from "test/lib/ActivationRegistryTest.sol";

contract ActivationRegistryDeactivateRevertOrderTest is ActivationRegistryTest {
/// @notice Verifies Unauthorized fires before FeatureNotActivated when caller is not admin
/// and the feature is not currently activated
/// @dev Revert order: access-control check precedes state validation; a non-admin caller
/// never reaches the FeatureNotActivated guard regardless of feature state.
/// Fuzz: any caller that is not the activationAdmin, any feature id.
function test_deactivate_revertOrder_unauthorized_beats_featureNotActivated(address caller, bytes32 feature)
public
{
_assumeValidCaller(caller);
vm.assume(caller != activationAdmin);

// The feature is not activated (default state), establishing the precondition
// that FeatureNotActivated *could* fire for an admin caller.

// A non-admin caller must see Unauthorized, not FeatureNotActivated,
// because the access-control check in deactivate fires first.
vm.expectRevert(abi.encodeWithSelector(IActivationRegistry.Unauthorized.selector, caller));
vm.prank(caller);
activationRegistry.deactivate(feature);
}
}
Loading