Skip to content

Commit

Permalink
test: test casting utilities for basic types
Browse files Browse the repository at this point in the history
docs: add basic NatSpec for casting libraries
refactor: reorder custom errors alphabetically
refactor: simplify casting from "uint40" to "uint64"
test: add "boundUint128" helpers
  • Loading branch information
PaulRBerg committed Jan 12, 2023
1 parent 593a0ea commit 5085861
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 13 deletions.
16 changes: 9 additions & 7 deletions src/casting/Uint128.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ error PRBMath_IntoSD1x18_Overflow(uint128 x);
/// @notice Emitted when trying to cast an uint128 that doesn't fit in UD2x18.
error PRBMath_IntoUD2x18_Overflow(uint128 x);

/// @title PRBMathCastingUint128
/// @notice Casting utilities for uint128.
library PRBMathCastingUint128 {
/// @notice Casts an uint128 number to SD1x18.
/// @dev Requirements:
Expand All @@ -20,7 +22,13 @@ library PRBMathCastingUint128 {
if (x > uint256(int256(uMAX_SD1x18))) {
revert PRBMath_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(int256(uint256(x))));
result = SD1x18.wrap(int64(uint64(x)));
}

/// @notice Casts an uint128 number to SD59x18.
/// @dev There is no overflow check because the domain of uint128 is a subset of SD59x18.
function intoSD59x18(uint128 x) internal pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(uint256(x)));
}

/// @notice Casts an uint128 number to UD2x18.
Expand All @@ -33,12 +41,6 @@ library PRBMathCastingUint128 {
result = UD2x18.wrap(uint64(uint256(x)));
}

/// @notice Casts an uint128 number to SD59x18.
/// @dev There is no overflow check because the domain of uint128 is a subset of SD59x18.
function intoSD59x18(uint128 x) internal pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(uint256(x)));
}

/// @notice Casts an uint128 number to UD60x18.
/// @dev There is no overflow check because the domain of uint128 is a subset of UD60x18.
function intoUD60x18(uint128 x) internal pure returns (UD60x18 result) {
Expand Down
8 changes: 5 additions & 3 deletions src/casting/Uint256.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { UD60x18 } from "../UD60x18.sol";
/// @notice Emitted when trying to cast an uint256 that doesn't fit in SD1x18.
error PRBMath_IntoSD1x18_Overflow(uint256 x);

/// @notice Emitted when trying to cast an uint256 that doesn't fit in UD2x18.
error PRBMath_IntoUD2x18_Overflow(uint256 x);

/// @notice Emitted when trying to cast an uint256 that doesn't fit in SD59x18.
error PRBMath_IntoSD59x18_Overflow(uint256 x);

/// @notice Emitted when trying to cast an uint256 that doesn't fit in UD2x18.
error PRBMath_IntoUD2x18_Overflow(uint256 x);

/// @title PRBMathCastingUint256
/// @notice Casting utilities for uint256.
library PRBMathCastingUint256 {
/// @notice Casts an uint256 number to SD1x18.
/// @dev Requirements:
Expand Down
4 changes: 3 additions & 1 deletion src/casting/Uint40.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { SD59x18 } from "../SD59x18.sol";
import { UD2x18 } from "../UD2x18.sol";
import { UD60x18 } from "../UD60x18.sol";

/// @title PRBMathCastingUint40
/// @notice Casting utilities for uint40.
library PRBMathCastingUint40 {
/// @notice Casts an uint40 number into SD1x18.
/// @dev There is no overflow check because the domain of uint40 is a subset of SD1x18.
function intoSD1x18(uint40 x) internal pure returns (SD1x18 result) {
result = SD1x18.wrap(int64(int256(uint256(x))));
result = SD1x18.wrap(int64(uint64(x)));
}

/// @notice Casts an uint40 number into SD59x18.
Expand Down
5 changes: 3 additions & 2 deletions test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ abstract contract BaseTest is PRBTest, PRBMathAssertions, StdCheats, StdUtils {
CONSTANT HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

function bn(uint256 amount, uint256 decimals) internal pure returns (uint256 result) {
result = amount * 10 ** decimals;
/// @dev Bounds a `uint128` number.
function boundUint128(uint128 x, uint128 min, uint128 max) internal view returns (uint128 result) {
result = uint128(bound(uint256(x), uint256(min), uint256(max)));
}

/*//////////////////////////////////////////////////////////////////////////
Expand Down
59 changes: 59 additions & 0 deletions test/casting/CastingUint128.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13 <0.9.0;

import {
PRBMathCastingUint128 as CastingUint128,
PRBMath_IntoSD1x18_Overflow,
PRBMath_IntoUD2x18_Overflow
} from "src/casting/Uint128.sol";
import { uMAX_SD1x18 } from "src/sd1x18/Constants.sol";
import { SD1x18 } from "src/sd1x18/ValueType.sol";
import { SD59x18 } from "src/sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "src/ud2x18/Constants.sol";
import { UD2x18 } from "src/ud2x18/ValueType.sol";
import { UD60x18 } from "src/ud60x18/ValueType.sol";

import { BaseTest } from "../BaseTest.t.sol";

/// @dev Collection of tests for the casting library available for uint128.
contract CastingUint128_Test is BaseTest {
using CastingUint128 for uint128;

function test_RevertWhen_OverflowSD1x18(uint128 x) external {
x = boundUint128(x, uint128(uint64(uMAX_SD1x18)) + 1, type(uint128).max);
vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD1x18_Overflow.selector, x));
x.intoSD1x18();
}

function testFuzz_intoSD1x18(uint128 x) external {
x = boundUint128(x, 0, uint128(uint64(uMAX_SD1x18)));
SD1x18 actual = x.intoSD1x18();
SD1x18 expected = SD1x18.wrap(int64(uint64(x)));
assertEq(actual, expected);
}

function testFuzz_intoSD59x18(uint128 x) external {
SD59x18 actual = x.intoSD59x18();
SD59x18 expected = SD59x18.wrap(int256(uint256(x)));
assertEq(actual, expected);
}

function test_RevertWhen_OverflowUD2x18(uint128 x) external {
x = boundUint128(x, uint128(uMAX_UD2x18) + 1, type(uint128).max);
vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoUD2x18_Overflow.selector, x));
x.intoUD2x18();
}

function testFuzz_intoUD2x18(uint128 x) external {
x = boundUint128(x, 0, uint128(uMAX_UD2x18));
UD2x18 actual = x.intoUD2x18();
UD2x18 expected = UD2x18.wrap(uint64(x));
assertEq(actual, expected);
}

function testFuzz_intoUD60x18(uint128 x) external {
UD60x18 actual = x.intoUD60x18();
UD60x18 expected = UD60x18.wrap(uint256(x));
assertEq(actual, expected);
}
}
68 changes: 68 additions & 0 deletions test/casting/CastingUint256.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13 <0.9.0;

import {
PRBMathCastingUint256 as CastingUint256,
PRBMath_IntoSD1x18_Overflow,
PRBMath_IntoSD59x18_Overflow,
PRBMath_IntoUD2x18_Overflow
} from "src/casting/Uint256.sol";
import { uMAX_SD1x18 } from "src/sd1x18/Constants.sol";
import { SD1x18 } from "src/sd1x18/ValueType.sol";
import { uMAX_SD59x18 } from "src/sd59x18/Constants.sol";
import { SD59x18 } from "src/sd59x18/ValueType.sol";
import { uMAX_UD2x18 } from "src/ud2x18/Constants.sol";
import { UD2x18 } from "src/ud2x18/ValueType.sol";
import { UD60x18 } from "src/ud60x18/ValueType.sol";

import { BaseTest } from "../BaseTest.t.sol";

/// @dev Collection of tests for the casting library available for uint256.
contract CastingUint256_Test is BaseTest {
using CastingUint256 for uint256;

function test_RevertWhen_OverflowSD1x18(uint256 x) external {
x = bound(x, uint256(uint64(uMAX_SD1x18)) + 1, type(uint256).max);
vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD1x18_Overflow.selector, x));
x.intoSD1x18();
}

function testFuzz_intoSD1x18(uint256 x) external {
x = bound(x, 0, uint256(uint64(uMAX_SD1x18)));
SD1x18 actual = x.intoSD1x18();
SD1x18 expected = SD1x18.wrap(int64(uint64(x)));
assertEq(actual, expected);
}

function test_RevertWhen_OverflowSD59x18(uint256 x) external {
x = bound(x, uint256(uMAX_SD59x18) + 1, type(uint256).max);
vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoSD59x18_Overflow.selector, x));
x.intoSD59x18();
}

function testFuzz_intoSD59x18(uint256 x) external {
x = bound(x, 0, uint256(uMAX_SD59x18));
SD59x18 actual = x.intoSD59x18();
SD59x18 expected = SD59x18.wrap(int256(uint256(x)));
assertEq(actual, expected);
}

function test_RevertWhen_OverflowUD2x18(uint256 x) external {
x = bound(x, uint256(uMAX_UD2x18) + 1, type(uint256).max);
vm.expectRevert(abi.encodeWithSelector(PRBMath_IntoUD2x18_Overflow.selector, x));
x.intoUD2x18();
}

function testFuzz_intoUD2x18(uint256 x) external {
x = bound(x, 0, uint256(uMAX_UD2x18));
UD2x18 actual = x.intoUD2x18();
UD2x18 expected = UD2x18.wrap(uint64(x));
assertEq(actual, expected);
}

function testFuzz_intoUD60x18(uint256 x) external {
UD60x18 actual = x.intoUD60x18();
UD60x18 expected = UD60x18.wrap(x);
assertEq(actual, expected);
}
}
39 changes: 39 additions & 0 deletions test/casting/CastingUint40.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.13 <0.9.0;

import { PRBMathCastingUint40 as CastingUint40 } from "src/casting/Uint40.sol";
import { SD1x18 } from "src/sd1x18/ValueType.sol";
import { SD59x18 } from "src/sd59x18/ValueType.sol";
import { UD2x18 } from "src/ud2x18/ValueType.sol";
import { UD60x18 } from "src/ud60x18/ValueType.sol";

import { BaseTest } from "../BaseTest.t.sol";

/// @dev Collection of tests for the casting library available for uint40.
contract CastingUint40_Test is BaseTest {
using CastingUint40 for uint40;

function testFuzz_intoSD1x18(uint40 x) external {
SD1x18 actual = x.intoSD1x18();
SD1x18 expected = SD1x18.wrap(int64(uint64(x)));
assertEq(actual, expected);
}

function testFuzz_intoSD59x18(uint40 x) external {
SD59x18 actual = x.intoSD59x18();
SD59x18 expected = SD59x18.wrap(int256(uint256(x)));
assertEq(actual, expected);
}

function testFuzz_intoUD2x18(uint40 x) external {
UD2x18 actual = x.intoUD2x18();
UD2x18 expected = UD2x18.wrap(uint64(x));
assertEq(actual, expected);
}

function testFuzz_intoUD60x18(uint40 x) external {
UD60x18 actual = x.intoUD60x18();
UD60x18 expected = UD60x18.wrap(uint256(x));
assertEq(actual, expected);
}
}

0 comments on commit 5085861

Please sign in to comment.