Files

126 lines
3.9 KiB
Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {BitMath} from "../../src/libraries/BitMath.sol";
contract TestBitMath is Test {
function test_mostSignificantBit_revertsWhenZero() public {
vm.expectRevert();
BitMath.mostSignificantBit(0);
}
function test_mostSignificantBit_one() public pure {
assertEq(BitMath.mostSignificantBit(1), 0);
}
function test_mostSignificantBit_two() public pure {
assertEq(BitMath.mostSignificantBit(2), 1);
}
function test_mostSignificantBit_powersOfTwo() public pure {
for (uint256 i = 0; i < 255; i++) {
uint256 x = 1 << i;
assertEq(BitMath.mostSignificantBit(x), i);
}
}
function test_mostSignificantBit_maxUint256() public pure {
assertEq(BitMath.mostSignificantBit(type(uint256).max), 255);
}
function test_fuzz_mostSignificantBit(uint256 x) public pure {
vm.assume(x != 0);
assertEq(BitMath.mostSignificantBit(x), mostSignificantBitReference(x));
}
function test_invariant_mostSignificantBit(uint256 x) public pure {
vm.assume(x != 0);
uint8 msb = BitMath.mostSignificantBit(x);
assertGe(x, uint256(2) ** msb);
assertTrue(msb == 255 || x < uint256(2) ** (msb + 1));
}
function test_mostSignificantBit_gas() public {
vm.startSnapshotGas("BitMathMostSignificantBitSmallNumber");
BitMath.mostSignificantBit(3568);
vm.stopSnapshotGas();
vm.startSnapshotGas("BitMathMostSignificantBitMaxUint128");
BitMath.mostSignificantBit(type(uint128).max);
vm.stopSnapshotGas();
vm.startSnapshotGas("BitMathMostSignificantBitMaxUint256");
BitMath.mostSignificantBit(type(uint256).max);
vm.stopSnapshotGas();
}
function test_leastSignificantBit_revertsWhenZero() public {
vm.expectRevert();
BitMath.leastSignificantBit(0);
}
function test_leastSignificantBit_one() public pure {
assertEq(BitMath.leastSignificantBit(1), 0);
}
function test_leastSignificantBit_two() public pure {
assertEq(BitMath.leastSignificantBit(2), 1);
}
function test_leastSignificantBit_powersOfTwo() public pure {
for (uint256 i = 0; i < 255; i++) {
uint256 x = 1 << i;
assertEq(BitMath.leastSignificantBit(x), i);
}
}
function test_leastSignificantBit_maxUint256() public pure {
assertEq(BitMath.leastSignificantBit(type(uint256).max), 0);
}
function test_fuzz_leastSignificantBit(uint256 x) public pure {
vm.assume(x != 0);
assertEq(BitMath.leastSignificantBit(x), leastSignificantBitReference(x));
}
function test_invariant_leastSignificantBit(uint256 x) public pure {
vm.assume(x != 0);
uint8 lsb = BitMath.leastSignificantBit(x);
assertNotEq(x & (uint256(2) ** lsb), 0);
assertEq(x & (uint256(2) ** lsb - 1), 0);
}
function test_leastSignificantBit_gas() public {
vm.startSnapshotGas("BitMathLeastSignificantBitSmallNumber");
BitMath.leastSignificantBit(3568);
vm.stopSnapshotGas();
vm.startSnapshotGas("BitMathLeastSignificantBitMaxUint128");
BitMath.leastSignificantBit(type(uint128).max);
vm.stopSnapshotGas();
vm.startSnapshotGas("BitMathLeastSignificantBitMaxUint256");
BitMath.leastSignificantBit(type(uint256).max);
vm.stopSnapshotGas();
}
function mostSignificantBitReference(uint256 x) private pure returns (uint256) {
uint256 i = 0;
while ((x >>= 1) > 0) {
++i;
}
return i;
}
function leastSignificantBitReference(uint256 x) private pure returns (uint256) {
require(x > 0, "BitMath: zero has no least significant bit");
uint256 i = 0;
while ((x >> i) & 1 == 0) {
++i;
}
return i;
}
}