Skip to content

Commit 1250622

Browse files
committed
Adding more tests
1 parent e0fe942 commit 1250622

3 files changed

Lines changed: 137 additions & 0 deletions

File tree

test/core/dao/DAO.t.sol

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,53 @@ contract DAOInitializeTest is DAOTestBase {
150150
}
151151
}
152152

153+
/// @notice `initializeFrom` (the post-upgrade reinitializer). The live v1.3→v1.4
154+
/// path can't reach its body (F9: v1.3.0 already set `_initialized == 3`), so we
155+
/// exercise it directly on a fresh proxy: deployed WITHOUT `initialize`,
156+
/// `_initialized == 0 < 3`, so `reinitializer(3)` runs. Covers the major-version
157+
/// gate and the version-conditional side effects.
158+
contract DAOInitializeFromTest is DAOTestBase {
159+
/// A proxy pointing at a DAO impl but never `initialize`d (`_initialized == 0`).
160+
function _freshProxy() internal returns (DAO) {
161+
DAO impl = new DAO();
162+
return DAO(payable(address(new ERC1967Proxy(address(impl), ""))));
163+
}
164+
165+
/// Upgrading across a major release is rejected.
166+
function test_initializeFrom_revertsIfMajorVersionNotOne() public {
167+
DAO d = _freshProxy();
168+
uint8[3] memory prev = [uint8(2), 0, 0];
169+
vm.expectRevert(abi.encodeWithSelector(DAO.ProtocolVersionUpgradeNotSupported.selector, prev));
170+
d.initializeFrom(prev, "");
171+
}
172+
173+
/// From a pre-1.3.0 source, the body arms the reentrancy guard and registers
174+
/// the interfaces added in v1.3.0 (`IProtocolVersion`) and v1.4.0 (`IDAO`,
175+
/// `IExecutor`), and bumps the OZ initialized slot to 3.
176+
function test_initializeFrom_fromPre130_initsReentrancyGuardAndInterfaces() public {
177+
DAO d = _freshProxy();
178+
d.initializeFrom([uint8(1), 0, 0], "");
179+
180+
assertEq(uint8(uint256(vm.load(address(d), bytes32(uint256(0))))), 3, "_initialized == 3");
181+
assertEq(uint256(vm.load(address(d), bytes32(uint256(304)))), 1, "_reentrancyStatus == _NOT_ENTERED");
182+
assertTrue(d.supportsInterface(type(IProtocolVersion).interfaceId), "IProtocolVersion registered");
183+
assertTrue(d.supportsInterface(type(IDAO).interfaceId), "IDAO registered");
184+
assertTrue(d.supportsInterface(type(IExecutor).interfaceId), "IExecutor registered");
185+
}
186+
187+
/// Boundary check: `[1,3,0]` is NOT `lt [1,3,0]`, so the reentrancy /
188+
/// `IProtocolVersion` branch is skipped — proving the version gate is strict.
189+
function test_initializeFrom_from130_skipsReentrancyBranch() public {
190+
DAO d = _freshProxy();
191+
d.initializeFrom([uint8(1), 3, 0], "");
192+
193+
assertEq(uint256(vm.load(address(d), bytes32(uint256(304)))), 0, "reentrancy branch skipped");
194+
assertFalse(d.supportsInterface(type(IProtocolVersion).interfaceId), "IProtocolVersion NOT registered");
195+
// The `< [1,4,0]` branch still ran.
196+
assertTrue(d.supportsInterface(type(IDAO).interfaceId), "IDAO registered");
197+
}
198+
}
199+
153200
/// @notice setTrustedForwarder + setMetadata.
154201
contract DAOMetadataTest is DAOTestBase {
155202
function test_setTrustedForwarder_revertsIfCallerLacksPermission() public {

test/framework/plugin/setup/PSP.Installation.t.sol

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,25 @@ contract PSPPrepareInstallationTest is PSPBaseTest {
122122
assertTrue(found, "InstallationPrepared not emitted");
123123
}
124124

125+
/// Preparing an installation for a plugin that is already installed reverts.
126+
/// Build 5 (Bad) returns a fixed plugin address, so re-preparing after an
127+
/// apply lands in the SAME installation slot (non-zero `currentAppliedSetupId`).
128+
function test_prepareInstallation_revertsIfPluginAlreadyInstalled() public {
129+
(address plugin, IPluginSetup.PreparedSetupData memory data) =
130+
psp.prepareInstallation(address(dao), _prepareInstallParams(5, ""));
131+
_grantApplyInstallation(owner);
132+
_grantPspRoot();
133+
psp.applyInstallation(
134+
address(dao),
135+
PluginSetupProcessor.ApplyInstallationParams({
136+
pluginSetupRef: _ref(5), plugin: plugin, permissions: data.permissions, helpersHash: hashHelpers(data.helpers)
137+
})
138+
);
139+
140+
vm.expectRevert(PluginSetupProcessor.PluginAlreadyInstalled.selector);
141+
psp.prepareInstallation(address(dao), _prepareInstallParams(5, ""));
142+
}
143+
125144
function test_prepareInstallation_revertsIfSamePrepIdPending() public {
126145
// The V1 mock deploys a NEW proxy each call (different `plugin` →
127146
// different installationId), so re-using V1 lands in a fresh state
@@ -208,6 +227,24 @@ contract PSPApplyInstallationTest is PSPBaseTest {
208227
assertEq(currentAppliedId, expectedAppliedId);
209228
}
210229

230+
/// Applying an installation for an already-installed plugin reverts. The
231+
/// `currentAppliedSetupId != 0` guard is checked BEFORE `validatePreparedSetupId`,
232+
/// so re-applying the same params surfaces `PluginAlreadyInstalled` (not
233+
/// `SetupNotApplicable`). Build 5 (Bad) gives the fixed plugin address needed.
234+
function test_applyInstallation_revertsIfPluginAlreadyInstalled() public {
235+
(address plugin, IPluginSetup.PreparedSetupData memory data) =
236+
psp.prepareInstallation(address(dao), _prepareInstallParams(5, ""));
237+
PluginSetupProcessor.ApplyInstallationParams memory p = PluginSetupProcessor.ApplyInstallationParams({
238+
pluginSetupRef: _ref(5), plugin: plugin, permissions: data.permissions, helpersHash: hashHelpers(data.helpers)
239+
});
240+
_grantApplyInstallation(owner);
241+
_grantPspRoot();
242+
psp.applyInstallation(address(dao), p);
243+
244+
vm.expectRevert(PluginSetupProcessor.PluginAlreadyInstalled.selector);
245+
psp.applyInstallation(address(dao), p);
246+
}
247+
211248
/// **F32 closer**: `msg.sender == _dao` bypasses APPLY_INSTALLATION_PERMISSION.
212249
function test_applyInstallation_daoAsSelfBypassesPermissionCheck() public {
213250
(address plugin, PluginSetupProcessor.ApplyInstallationParams memory p) = _prepare();
@@ -432,6 +469,13 @@ contract PSPConstructorAndConstantsTest is PSPBaseTest {
432469
assertEq(address(psp.repoRegistry()), address(pluginRepoRegistry));
433470
}
434471

472+
function test_protocolVersion_returnsCurrent() public view {
473+
uint8[3] memory v = psp.protocolVersion();
474+
assertEq(v[0], 1);
475+
assertEq(v[1], 4);
476+
assertEq(v[2], 0);
477+
}
478+
435479
function test_permissionId_applyInstallationMatchesKeccak() public view {
436480
assertEq(psp.APPLY_INSTALLATION_PERMISSION_ID(), keccak256("APPLY_INSTALLATION_PERMISSION"));
437481
}

test/framework/plugin/setup/PSP.Update.t.sol

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,52 @@ contract PSPApplyUpdateTest is PSPUpdateFixture {
244244
assertEq(currentAppliedId, expectedAppliedId);
245245
}
246246

247+
/// Twin of `PSP.Uninstallation.t.sol::test_applyUninstallation_otherPendingPrepsBecomeInapplicable`:
248+
/// two distinct update preparations for the same plugin, applying one bumps
249+
/// `pluginState.blockNumber`, invalidating the other (its `preparedBlock` is
250+
/// now stale) → `SetupNotApplicable`.
251+
function test_applyUpdate_otherPendingPrepsBecomeInapplicable() public {
252+
(address plugin, address[] memory helpers) = _installV1();
253+
254+
// Prep A: default permission range → setup id A.
255+
setupV2.mockPermissionIndexes(1, 2);
256+
(bytes memory initA, IPluginSetup.PreparedSetupData memory dataA) =
257+
psp.prepareUpdate(address(dao), _prepareUpdateParams(1, 2, plugin, helpers));
258+
259+
// Prep B: different permission range → distinct setup id B.
260+
setupV2.mockPermissionIndexes(3, 4);
261+
(bytes memory initB, IPluginSetup.PreparedSetupData memory dataB) =
262+
psp.prepareUpdate(address(dao), _prepareUpdateParams(1, 2, plugin, helpers));
263+
264+
_grantApplyUpdate(owner);
265+
_grantPspRoot();
266+
267+
// Apply A.
268+
psp.applyUpdate(
269+
address(dao),
270+
PluginSetupProcessor.ApplyUpdateParams({
271+
plugin: plugin,
272+
pluginSetupRef: _ref(2),
273+
initData: initA,
274+
permissions: dataA.permissions,
275+
helpersHash: hashHelpers(dataA.helpers)
276+
})
277+
);
278+
279+
// B is now inapplicable — its prepared block predates A's applied bump.
280+
vm.expectRevert(); // SetupNotApplicable
281+
psp.applyUpdate(
282+
address(dao),
283+
PluginSetupProcessor.ApplyUpdateParams({
284+
plugin: plugin,
285+
pluginSetupRef: _ref(2),
286+
initData: initB,
287+
permissions: dataB.permissions,
288+
helpersHash: hashHelpers(dataB.helpers)
289+
})
290+
);
291+
}
292+
247293
/// V2's prepareUpdate returns `_mockHelpers(2)` — same length as V1's helpers
248294
/// (both 2 entries: address(0), address(1)).
249295
function _helpersV2() internal pure returns (address[] memory h) {

0 commit comments

Comments
 (0)