From a7bff136abb85b448a3fe1086a6310adcadc385f Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Mon, 20 May 2024 12:07:59 -0300 Subject: [PATCH 1/9] Add eq test in uint128 case --- src/FuzzLibString.sol | 72 ++++++++++++++++++++++++++++++++++++ src/helpers/HelperAssert.sol | 22 +++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/FuzzLibString.sol b/src/FuzzLibString.sol index f906f75..c3dd63e 100644 --- a/src/FuzzLibString.sol +++ b/src/FuzzLibString.sol @@ -17,6 +17,15 @@ library FuzzLibString { } } + function intToString(int128 value) internal pure returns (string memory str) { + uint128 absValue = value >= 0 ? uint128(value) : uint128(-value); + str = toString(absValue); + + if (value < 0) { + str = string(abi.encodePacked("-", str)); + } + } + function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { @@ -66,6 +75,55 @@ library FuzzLibString { } } + function intToString(uint128 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes + // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the + // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes. + let newFreeMemoryPointer := add(mload(0x40), 160) + + // Update the free memory pointer to avoid overriding our string. + mstore(0x40, newFreeMemoryPointer) + + // Assign str to the end of the zone of newly allocated memory. + str := sub(newFreeMemoryPointer, 32) + + // Clean the last word of memory it may not be overwritten. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + // Move the pointer 1 byte to the left. + str := sub(str, 1) + + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + + // Keep dividing temp until zero. + temp := div(temp, 10) + + // prettier-ignore + if iszero(temp) { break } + } + + // Compute and cache the final total length of the string. + let length := sub(end, str) + + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 32) + + // Store the string's length at the start of memory allocated for our string. + mstore(str, length) + } + } + function toString(address value) internal pure returns (string memory str) { bytes memory s = new bytes(40); for (uint256 i = 0; i < 20; i++) { @@ -80,6 +138,20 @@ library FuzzLibString { return string(s); } + function intToString(address value) internal pure returns (string memory str) { + bytes memory s = new bytes(40); + for (uint128 i = 0; i < 20; i++) { + bytes1 b = bytes1( + uint8(uint128(uint160(value)) / (2**(8 * (19 - i)))) + ); + bytes1 hi = bytes1(uint8(b) / 16); + bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); + s[2 * i] = char(hi); + s[2 * i + 1] = char(lo); + } + return string(s); + } + function char(bytes1 b) internal pure returns (bytes1 c) { if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); else return bytes1(uint8(b) + 0x57); diff --git a/src/helpers/HelperAssert.sol b/src/helpers/HelperAssert.sol index b6c0549..5c8585a 100644 --- a/src/helpers/HelperAssert.sol +++ b/src/helpers/HelperAssert.sol @@ -66,6 +66,28 @@ abstract contract HelperAssert is HelperBase { } } + /// @notice int128 version of eq + function eq( + int128 a, + int128 b, + string memory reason + ) public { + if (a != b) { + string memory aStr = FuzzLibString.intToString(a); + string memory bStr = FuzzLibString.intToString(b); + bytes memory assertMsg = abi.encodePacked( + "Invalid: ", + aStr, + "!=", + bStr, + ", reason: ", + reason + ); + emit AssertEqFail(string(assertMsg)); + platform.assertFail(); + } + } + /// @notice bytes4 version of eq function eq( bytes4 a, From 8202c53fea0544e7f889b3fc1cfa17ee644cfec8 Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Tue, 21 May 2024 15:37:38 -0300 Subject: [PATCH 2/9] assert eq tests --- src/FuzzLibString.sol | 72 ------------------------------------ src/helpers/HelperAssert.sol | 22 ----------- test/Assert.t.sol | 32 +++++++++++++++- 3 files changed, 31 insertions(+), 95 deletions(-) diff --git a/src/FuzzLibString.sol b/src/FuzzLibString.sol index c3dd63e..f906f75 100644 --- a/src/FuzzLibString.sol +++ b/src/FuzzLibString.sol @@ -17,15 +17,6 @@ library FuzzLibString { } } - function intToString(int128 value) internal pure returns (string memory str) { - uint128 absValue = value >= 0 ? uint128(value) : uint128(-value); - str = toString(absValue); - - if (value < 0) { - str = string(abi.encodePacked("-", str)); - } - } - function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { @@ -75,55 +66,6 @@ library FuzzLibString { } } - function intToString(uint128 value) internal pure returns (string memory str) { - /// @solidity memory-safe-assembly - assembly { - // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes - // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the - // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes. - let newFreeMemoryPointer := add(mload(0x40), 160) - - // Update the free memory pointer to avoid overriding our string. - mstore(0x40, newFreeMemoryPointer) - - // Assign str to the end of the zone of newly allocated memory. - str := sub(newFreeMemoryPointer, 32) - - // Clean the last word of memory it may not be overwritten. - mstore(str, 0) - - // Cache the end of the memory to calculate the length later. - let end := str - - // We write the string from rightmost digit to leftmost digit. - // The following is essentially a do-while loop that also handles the zero case. - // prettier-ignore - for { let temp := value } 1 {} { - // Move the pointer 1 byte to the left. - str := sub(str, 1) - - // Write the character to the pointer. - // The ASCII index of the '0' character is 48. - mstore8(str, add(48, mod(temp, 10))) - - // Keep dividing temp until zero. - temp := div(temp, 10) - - // prettier-ignore - if iszero(temp) { break } - } - - // Compute and cache the final total length of the string. - let length := sub(end, str) - - // Move the pointer 32 bytes leftwards to make room for the length. - str := sub(str, 32) - - // Store the string's length at the start of memory allocated for our string. - mstore(str, length) - } - } - function toString(address value) internal pure returns (string memory str) { bytes memory s = new bytes(40); for (uint256 i = 0; i < 20; i++) { @@ -138,20 +80,6 @@ library FuzzLibString { return string(s); } - function intToString(address value) internal pure returns (string memory str) { - bytes memory s = new bytes(40); - for (uint128 i = 0; i < 20; i++) { - bytes1 b = bytes1( - uint8(uint128(uint160(value)) / (2**(8 * (19 - i)))) - ); - bytes1 hi = bytes1(uint8(b) / 16); - bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); - s[2 * i] = char(hi); - s[2 * i + 1] = char(lo); - } - return string(s); - } - function char(bytes1 b) internal pure returns (bytes1 c) { if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); else return bytes1(uint8(b) + 0x57); diff --git a/src/helpers/HelperAssert.sol b/src/helpers/HelperAssert.sol index 5c8585a..b6c0549 100644 --- a/src/helpers/HelperAssert.sol +++ b/src/helpers/HelperAssert.sol @@ -66,28 +66,6 @@ abstract contract HelperAssert is HelperBase { } } - /// @notice int128 version of eq - function eq( - int128 a, - int128 b, - string memory reason - ) public { - if (a != b) { - string memory aStr = FuzzLibString.intToString(a); - string memory bStr = FuzzLibString.intToString(b); - bytes memory assertMsg = abi.encodePacked( - "Invalid: ", - aStr, - "!=", - bStr, - ", reason: ", - reason - ); - emit AssertEqFail(string(assertMsg)); - platform.assertFail(); - } - } - /// @notice bytes4 version of eq function eq( bytes4 a, diff --git a/test/Assert.t.sol b/test/Assert.t.sol index 9f23717..514ce90 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -25,4 +25,34 @@ contract TestAsserts is Test, HelperAssert { string memory reason = "Testing assertion"; t(true, reason); } -} + + function test_HelperAssert_Ttrue() public { + //vm.expectRevert(); + t(true, "t reverts for true"); + } + + function test_HelperAssert_Tfalse() public { + //emit AssertEqFail("Testing assertion"); + vm.expectRevert(); + t(false, "t does not revert for true"); + } + + function test_HelperAssert_eq_x_x_concrete(uint256 x) public { + assertEq(x, x,"eq reverts with the concrete values"); + } + + function test_HelperAssert_eq_x_x_fuzz(uint256 x) public { + assertEq(x, x, "eq does not revert with the fuzz values"); + } + + function test_HelperAssert_eq_x_y_concrete(uint256 x, uint256 y) public { + vm.assume(x == y); + assertEq(x, y,"eq reverts with the concrete values"); + } + + function test_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { + vm.assume(x != y); + vm.expectRevert(); + eq(x,y, "eq does not revert with the fuzz values"); + } +} \ No newline at end of file From 5ac3f7823dbd6f3cabc33daeb487e71b670ef15d Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 23 May 2024 14:08:59 -0300 Subject: [PATCH 3/9] Changes on tests --- test/Assert.t.sol | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index 514ce90..c4b9d17 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -8,6 +8,7 @@ import {HelperAssert} from "../src/helpers/HelperAssert.sol"; import {PlatformTest} from "./util/PlatformTest.sol"; contract TestAsserts is Test, HelperAssert { + function setUp() public { setPlatform(address(new PlatformTest())); } @@ -26,33 +27,39 @@ contract TestAsserts is Test, HelperAssert { t(true, reason); } - function test_HelperAssert_Ttrue() public { - //vm.expectRevert(); + function test_HelperAssert_t_true() public { t(true, "t reverts for true"); } - function test_HelperAssert_Tfalse() public { - //emit AssertEqFail("Testing assertion"); + function test_HelperAssert_t_false() public { vm.expectRevert(); t(false, "t does not revert for true"); } - function test_HelperAssert_eq_x_x_concrete(uint256 x) public { - assertEq(x, x,"eq reverts with the concrete values"); + function test_HelperAssert_eq_x_x_concrete() public { + uint256 x = 1; + eq(x, x, "eq does not revert with equal values"); } - function test_HelperAssert_eq_x_x_fuzz(uint256 x) public { - assertEq(x, x, "eq does not revert with the fuzz values"); + function testFuzz_HelperAssert_eq_x_x_fuzz(uint256 x) public { + eq(x, x, "eq does not revert with the fuzz values"); } - function test_HelperAssert_eq_x_y_concrete(uint256 x, uint256 y) public { - vm.assume(x == y); - assertEq(x, y,"eq reverts with the concrete values"); - } + function test_HelperAssert_eq_x_y_concrete() public { + uint256 x = 2; + uint256 y = 4; + vm.expectEmit(true, true, false, false); + emit AssertEqFail(""); + vm.expectRevert(); + eq(x, y, "eq does not revert with the fuzz values"); + } - function test_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { + function testFuzz_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { vm.assume(x != y); + string memory reason = "eq does not revert with equal values"; + vm.expectEmit(true, true, false, false); + emit AssertEqFail(""); vm.expectRevert(); - eq(x,y, "eq does not revert with the fuzz values"); + eq(x, y, reason); } } \ No newline at end of file From eacd02e44d02b32b1efe3a94e011cbcd4f23722d Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 23 May 2024 14:12:38 -0300 Subject: [PATCH 4/9] some typo adjusts --- test/Assert.t.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index c4b9d17..c9839e7 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -51,15 +51,14 @@ contract TestAsserts is Test, HelperAssert { vm.expectEmit(true, true, false, false); emit AssertEqFail(""); vm.expectRevert(); - eq(x, y, "eq does not revert with the fuzz values"); + eq(x, y, "eq reverts with different values"); } function testFuzz_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { vm.assume(x != y); - string memory reason = "eq does not revert with equal values"; vm.expectEmit(true, true, false, false); emit AssertEqFail(""); vm.expectRevert(); - eq(x, y, reason); + eq(x, y, "eq does reverts with different values"); } } \ No newline at end of file From 1407f768abdba032bfcdd2daabe03c86a698c19c Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 23 May 2024 14:15:20 -0300 Subject: [PATCH 5/9] typo changes --- test/Assert.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index c9839e7..af7761e 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -59,6 +59,6 @@ contract TestAsserts is Test, HelperAssert { vm.expectEmit(true, true, false, false); emit AssertEqFail(""); vm.expectRevert(); - eq(x, y, "eq does reverts with different values"); + eq(x, y, "eq reverts with different values"); } } \ No newline at end of file From 5d71468c766e8d95349fe569128d3c4273d22613 Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 23 May 2024 14:24:43 -0300 Subject: [PATCH 6/9] description adjust --- test/Assert.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index af7761e..324d792 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -28,12 +28,12 @@ contract TestAsserts is Test, HelperAssert { } function test_HelperAssert_t_true() public { - t(true, "t reverts for true"); + t(true, "t does not revert for true"); } function test_HelperAssert_t_false() public { vm.expectRevert(); - t(false, "t does not revert for true"); + t(false, "t reverts for true"); } function test_HelperAssert_eq_x_x_concrete() public { From ac0adc235f7e06782cc292640d56ffa1a3c098de Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 23 May 2024 15:56:11 -0300 Subject: [PATCH 7/9] final adjusts --- test/Assert.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index 324d792..0191e03 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -32,8 +32,8 @@ contract TestAsserts is Test, HelperAssert { } function test_HelperAssert_t_false() public { - vm.expectRevert(); - t(false, "t reverts for true"); + vm.expectRevert(PlatformTest.TestAssertFail.selector); + t(false, "t does not revert for true"); } function test_HelperAssert_eq_x_x_concrete() public { From af57c4b59df32ec2a34d8d17c612b3e682fbff73 Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Thu, 30 May 2024 14:14:36 -0300 Subject: [PATCH 8/9] adjusts in the tests --- test/Assert.t.sol | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index 0191e03..21836bd 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -13,27 +13,16 @@ contract TestAsserts is Test, HelperAssert { setPlatform(address(new PlatformTest())); } - function test_TFail() public { - string memory reason = "Testing assertion"; - - vm.expectEmit(true, true, true, true); - emit AssertFail("Testing assertion"); - vm.expectRevert(PlatformTest.TestAssertFail.selector); - t(false, reason); - } - - function test_TSuccess() public { - string memory reason = "Testing assertion"; - t(true, reason); - } - function test_HelperAssert_t_true() public { t(true, "t does not revert for true"); } function test_HelperAssert_t_false() public { - vm.expectRevert(PlatformTest.TestAssertFail.selector); - t(false, "t does not revert for true"); + string memory reason = "t does not revert for true"; + vm.expectEmit(true, true, false, false); + emit AssertFail(reason); + vm.expectRevert(PlatformTest.TestAssertFail.selector); + t(false, reason); } function test_HelperAssert_eq_x_x_concrete() public { @@ -48,17 +37,26 @@ contract TestAsserts is Test, HelperAssert { function test_HelperAssert_eq_x_y_concrete() public { uint256 x = 2; uint256 y = 4; + string memory reason = "eq reverts with different values"; + vm.expectEmit(true, true, false, false); - emit AssertEqFail(""); - vm.expectRevert(); - eq(x, y, "eq reverts with different values"); + emit AssertEqFail(reason); + + vm.expectRevert(PlatformTest.TestAssertFail.selector); + + eq(x, y, reason); } function testFuzz_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { vm.assume(x != y); + string memory reason = "eq reverts with different values"; + vm.expectEmit(true, true, false, false); - emit AssertEqFail(""); - vm.expectRevert(); - eq(x, y, "eq reverts with different values"); - } + emit AssertEqFail(reason); + + vm.expectRevert(PlatformTest.TestAssertFail.selector); + + eq(x, y, reason); +} + } \ No newline at end of file From 11a87b4c0a75ade8893c374d1f43a12f105b5c9e Mon Sep 17 00:00:00 2001 From: Antonio Gabriel Date: Wed, 5 Jun 2024 12:19:12 -0300 Subject: [PATCH 9/9] suggested changes --- test/Assert.t.sol | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/test/Assert.t.sol b/test/Assert.t.sol index 21836bd..2a97197 100644 --- a/test/Assert.t.sol +++ b/test/Assert.t.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "forge-std/console.sol"; +import "src/FuzzLibString.sol"; + import {HelperAssert} from "../src/helpers/HelperAssert.sol"; import {PlatformTest} from "./util/PlatformTest.sol"; @@ -14,12 +16,13 @@ contract TestAsserts is Test, HelperAssert { } function test_HelperAssert_t_true() public { - t(true, "t does not revert for true"); + string memory reason = "example message"; + t(true, reason); } function test_HelperAssert_t_false() public { - string memory reason = "t does not revert for true"; - vm.expectEmit(true, true, false, false); + string memory reason = "example message"; + vm.expectEmit(true, false, false, true); emit AssertFail(reason); vm.expectRevert(PlatformTest.TestAssertFail.selector); t(false, reason); @@ -37,10 +40,18 @@ contract TestAsserts is Test, HelperAssert { function test_HelperAssert_eq_x_y_concrete() public { uint256 x = 2; uint256 y = 4; - string memory reason = "eq reverts with different values"; - vm.expectEmit(true, true, false, false); - emit AssertEqFail(reason); + string memory reason = "eq reverts with different values."; + string memory failReason = string(abi.encodePacked( + "Invalid: ", + FuzzLibString.toString(x), + "!=", + FuzzLibString.toString(y), + ", reason: ", + reason + )); + vm.expectEmit(true, false, false, true); + emit AssertEqFail(failReason); vm.expectRevert(PlatformTest.TestAssertFail.selector); @@ -49,14 +60,21 @@ contract TestAsserts is Test, HelperAssert { function testFuzz_HelperAssert_eq_x_y_fuzz(uint256 x, uint256 y) public { vm.assume(x != y); - string memory reason = "eq reverts with different values"; - - vm.expectEmit(true, true, false, false); - emit AssertEqFail(reason); + string memory reason = "eq reverts with fuzz values."; + + vm.expectEmit(true, false, false, true); + string memory failReason = string(abi.encodePacked( + "Invalid: ", + FuzzLibString.toString(x), + "!=", + FuzzLibString.toString(y), + ", reason: ", + reason + )); + emit AssertEqFail(failReason); vm.expectRevert(PlatformTest.TestAssertFail.selector); eq(x, y, reason); -} - + } } \ No newline at end of file