Skip to content

Commit 95f8ef5

Browse files
committed
test(f02): cover every branch of _readBigInt
Assisted-by: Claude:claude-sonnet-4-6
1 parent e808569 commit 95f8ef5

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

test/mocks/FVMRewardWire.t.sol

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ contract FVMRewardWireTest is MockRewardWireTest {
3030
return rewardActor().mockLastParams();
3131
}
3232

33+
/// @dev `vm.expectRevert` cannot see a revert that happens after `_invoke`'s delegatecall,
34+
/// since that delegatecall runs inlined in this contract's own frame rather than behind a
35+
/// real CALL boundary. Routing through an external self-call gives `expectRevert` one to catch.
36+
function _externalClaim(uint64 id, address[] memory wallets)
37+
external
38+
returns (int256 exitCode, uint256[] memory amounts)
39+
{
40+
return FVMRewards.tryClaim(id, wallets);
41+
}
42+
3343
// [[
3444
// [23,[23,-24,23,0,23]], [24,[24,-25,24,0,24]],
3545
// [255,[255,-256,255,0,255]], [256,[256,-257,256,0,256]],
@@ -242,6 +252,42 @@ contract FVMRewardWireTest is MockRewardWireTest {
242252
}
243253
}
244254

255+
/// @dev A lone sign byte with an empty magnitude, distinct from an empty byte string.
256+
// [[byte[00]]]
257+
function test_ClaimReturn_SignByteWithEmptyMagnitudeIsZero() public {
258+
rewardActor().mockSetClaimReturn(hex"81814100");
259+
(int256 exitCode, uint256[] memory amounts) = FVMRewards.tryClaim(1, new address[](1));
260+
assertEq(exitCode, 0);
261+
assertEq(amounts[0], 0);
262+
}
263+
264+
/// @dev The widest magnitude `_readBigInt` accepts: 32 bytes, forcing its shift amount to zero.
265+
// [[byte[00,ff*32]]]
266+
function test_ClaimReturn_WidestMagnitude() public {
267+
rewardActor()
268+
.mockSetClaimReturn(hex"8181582100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
269+
(int256 exitCode, uint256[] memory amounts) = FVMRewards.tryClaim(1, new address[](1));
270+
assertEq(exitCode, 0);
271+
assertEq(amounts[0], type(uint256).max);
272+
}
273+
274+
/// @dev A nonzero sign byte, which `_readBigInt` rejects even though f02 never emits one.
275+
// [[byte[01,01]]]
276+
function test_ClaimReturn_NegativeSignByte_Reverts() public {
277+
rewardActor().mockSetClaimReturn(hex"8181420101");
278+
vm.expectRevert(bytes(""));
279+
this._externalClaim(1, new address[](1));
280+
}
281+
282+
/// @dev One byte past `_readBigInt`'s 32-byte magnitude cap.
283+
// [[byte[00,00*33]]]
284+
function test_ClaimReturn_OversizedMagnitude_Reverts() public {
285+
rewardActor()
286+
.mockSetClaimReturn(hex"8181582200000000000000000000000000000000000000000000000000000000000000000000");
287+
vm.expectRevert(bytes(""));
288+
this._externalClaim(1, new address[](1));
289+
}
290+
245291
// [null,op] for the two schedule-wide weight slots, [id,op] for everything per stream.
246292
function test_CancelPending_NullIdAddressesTheWeightSlot() public {
247293
FVMRewards.tryCancelPendingWeight(PendingOp.SET_WEIGHT);

0 commit comments

Comments
 (0)