From e17d6f03c3b22ac77c92393a855a5e0beee851f9 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Mon, 18 Apr 2022 15:46:38 +1000 Subject: [PATCH 01/19] feat(test): assertApproxEq, assertNotEq, assertFalse --- src/Test.sol | 202 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 8 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 8d189b72..69a9dab8 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -139,6 +139,192 @@ abstract contract Test is DSTest { addr := create(0, add(bytecode, 0x20), mload(bytecode)) } } + + /*////////////////////////////////////////////////////////////////////////// + APPROX EQUAL + //////////////////////////////////////////////////////////////////////////*/ + + function assertApproxEq(uint256 a, uint256 b, uint256 errorMargin) internal { + if (a > b) { + if (a - b > errorMargin) { + emit log("Error a not equal to b"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } else { + if (b - a > errorMargin) { + emit log("Error a not equal to b"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + } + + function assertApproxEq(uint256 a, uint256 b, uint256 errorMargin, string memory err) internal { + if (a > b) { + if (a - b > errorMargin) { + emit log_named_string("Error", err); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } else { + if (b - a > errorMargin) { + emit log_named_string("Error", err); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + } + + function assertApproxEq(int256 a, int256 b, int256 errorMargin) internal { + if (a > b) { + if (a - b > errorMargin) { + emit log("Error a not equal to b"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } else { + if (b - a > errorMargin) { + emit log("Error a not equal to b"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + } + + function assertApproxEq(int256 a, int256 b, int256 errorMargin, string memory err) internal { + if (a > b) { + if (a - b > errorMargin) { + emit log_named_string("Error", err); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } else { + if (b - a > errorMargin) { + emit log_named_string("Error", err); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + } + + /*////////////////////////////////////////////////////////////////////////// + NOT EQUAL + //////////////////////////////////////////////////////////////////////////*/ + + function assertNotEq(address a, address b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + + function assertNotEq(address a, address b, string memory err) internal { + if (a == b) { + emit log_named_string ("Error", err); + assertNotEq(a, b); + } + } + + function assertNotEq(bytes32 a, bytes32 b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + + function assertNotEq(bytes32 a, bytes32 b, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + + function assertNotEq32(bytes32 a, bytes32 b) internal { + assertNotEq(a, b); + } + + function assertNotEq32(bytes32 a, bytes32 b, string memory err) internal { + assertNotEq(a, b, err); + } + + function assertNotEq(int a, int b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + + function assertNotEq(int a, int b, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + + function assertNotEq(uint a, uint b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + + function assertNotEq(uint a, uint b, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + + function assertNotEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { + emit log("Error: a != b not satisfied [string]"); + emit log_named_string(" Value a", a); + emit log_named_string(" Value b", b); + fail(); + } + } + + function assertNotEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function assertFalse(bool condition) internal { + if (condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertFalse(bool condition, string memory err) internal { + if (condition) { + emit log_named_string("Error", err); + assertFalse(condition); + } + } } @@ -159,7 +345,7 @@ library stdError { struct StdStorage { mapping (address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; mapping (address => mapping(bytes4 => mapping(bytes32 => bool))) finds; - + bytes32[] _keys; bytes4 _sig; uint256 _depth; @@ -171,7 +357,7 @@ struct StdStorage { library stdStorage { event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot); event WARNING_UninitedSlot(address who, uint slot); - + Vm private constant vm_std_store = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); function sigs( @@ -192,8 +378,8 @@ library stdStorage { // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); function find( StdStorage storage self - ) - internal + ) + internal returns (uint256) { address who = self._target; @@ -212,7 +398,7 @@ library stdStorage { (, bytes memory rdat) = who.staticcall(cald); fdat = bytesToBytes32(rdat, 32*field_depth); } - + (bytes32[] memory reads, ) = vm_std_store.accesses(address(who)); if (reads.length == 1) { bytes32 curr = vm_std_store.load(who, reads[0]); @@ -239,7 +425,7 @@ library stdStorage { (success, rdat) = who.staticcall(cald); fdat = bytesToBytes32(rdat, 32*field_depth); } - + if (success && fdat == bytes32(hex"1337")) { // we found which of the slots is the actual one emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); @@ -259,7 +445,7 @@ library stdStorage { delete self._target; delete self._sig; delete self._keys; - delete self._depth; + delete self._depth; return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; } @@ -343,7 +529,7 @@ library stdStorage { delete self._target; delete self._sig; delete self._keys; - delete self._depth; + delete self._depth; } function bytesToBytes32(bytes memory b, uint offset) public pure returns (bytes32) { From 1e3b6a24f3ca2c500493266619560eb8d74f2df7 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:17:39 +1000 Subject: [PATCH 02/19] refactor: yoink assertApproxEq from t11s --- src/Test.sol | 119 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 69a9dab8..4291af7a 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -144,75 +144,72 @@ abstract contract Test is DSTest { APPROX EQUAL //////////////////////////////////////////////////////////////////////////*/ - function assertApproxEq(uint256 a, uint256 b, uint256 errorMargin) internal { - if (a > b) { - if (a - b > errorMargin) { - emit log("Error a not equal to b"); - emit log_named_uint(" Expected", b); - emit log_named_uint(" Actual", a); - fail(); - } - } else { - if (b - a > errorMargin) { - emit log("Error a not equal to b"); - emit log_named_uint(" Expected", b); - emit log_named_uint(" Actual", a); - fail(); - } + function assertApproxEq( + uint256 a, + uint256 b, + uint256 maxDelta + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log ("Error: a ~= b not satisfied [uint]"); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", delta); + fail(); } } - function assertApproxEq(uint256 a, uint256 b, uint256 errorMargin, string memory err) internal { - if (a > b) { - if (a - b > errorMargin) { - emit log_named_string("Error", err); - emit log_named_uint(" Expected", b); - emit log_named_uint(" Actual", a); - fail(); - } - } else { - if (b - a > errorMargin) { - emit log_named_string("Error", err); - emit log_named_uint(" Expected", b); - emit log_named_uint(" Actual", a); - fail(); - } + function assertApproxEq( + uint256 a, + uint256 b, + uint256 maxDelta, + string memory err + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log ("Error", err); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", delta); + fail(); } } - - function assertApproxEq(int256 a, int256 b, int256 errorMargin) internal { - if (a > b) { - if (a - b > errorMargin) { - emit log("Error a not equal to b"); - emit log_named_int(" Expected", b); - emit log_named_int(" Actual", a); - fail(); - } - } else { - if (b - a > errorMargin) { - emit log("Error a not equal to b"); - emit log_named_int(" Expected", b); - emit log_named_int(" Actual", a); - fail(); - } + function assertApproxEq( + int256 a, + int256 b, + int256 maxDelta + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log ("Error: a ~= b not satisfied [int]"); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); + emit log_named_int (" Max Delta", maxDelta); + emit log_named_int (" Delta", delta); + fail(); } } - function assertApproxEq(int256 a, int256 b, int256 errorMargin, string memory err) internal { - if (a > b) { - if (a - b > errorMargin) { - emit log_named_string("Error", err); - emit log_named_int(" Expected", b); - emit log_named_int(" Actual", a); - fail(); - } - } else { - if (b - a > errorMargin) { - emit log_named_string("Error", err); - emit log_named_int(" Expected", b); - emit log_named_int(" Actual", a); - fail(); - } + function assertApproxEq( + int256 a, + int256 b, + int256 maxDelta, + string memory err + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log ("Error", err); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); + emit log_named_int (" Max Delta", maxDelta); + emit log_named_int (" Delta", delta); + fail(); } } From fb089f06457710464daffea0b662389257019d31 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:18:30 +1000 Subject: [PATCH 03/19] feat(test): yoink assertRelApproxEq from t11s --- src/Test.sol | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index 4291af7a..cb3dc538 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -213,6 +213,49 @@ abstract contract Test is DSTest { } } + /*////////////////////////////////////////////////////////////////////////// + REL APPROX EQUAL + //////////////////////////////////////////////////////////////////////////*/ + + function assertRelApproxEq( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log ("Error: a ~= b not satisfied [uint]"); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); + emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint (" % Delta", percentDelta, 18); + fail(); + } + } + + function assertRelApproxEq( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log ("Error", err); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); + emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint (" % Delta", percentDelta, 18); + fail(); + } + } + /*////////////////////////////////////////////////////////////////////////// NOT EQUAL //////////////////////////////////////////////////////////////////////////*/ From dfaa2d5965c1769c21117826ba1103a6dc16e08e Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:19:04 +1000 Subject: [PATCH 04/19] style(test): align multi-line log messages for character alignment --- src/Test.sol | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index cb3dc538..bb69005f 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -262,32 +262,32 @@ abstract contract Test is DSTest { function assertNotEq(address a, address b) internal { if (a == b) { - emit log("Error: a != b not satisfied [address]"); - emit log_named_address(" Expected", b); - emit log_named_address(" Actual", a); + emit log ("Error: a != b not satisfied [address]"); + emit log_named_address (" Expected", b); + emit log_named_address (" Actual", a); fail(); } } function assertNotEq(address a, address b, string memory err) internal { if (a == b) { - emit log_named_string ("Error", err); + emit log_named_string ("Error", err); assertNotEq(a, b); } } function assertNotEq(bytes32 a, bytes32 b) internal { if (a == b) { - emit log("Error: a != b not satisfied [bytes32]"); - emit log_named_bytes32(" Expected", b); - emit log_named_bytes32(" Actual", a); + emit log ("Error: a != b not satisfied [bytes32]"); + emit log_named_bytes32 (" Expected", b); + emit log_named_bytes32 (" Actual", a); fail(); } } function assertNotEq(bytes32 a, bytes32 b, string memory err) internal { if (a == b) { - emit log_named_string("Error", err); + emit log_named_string ("Error", err); assertNotEq(a, b); } } @@ -302,48 +302,48 @@ abstract contract Test is DSTest { function assertNotEq(int a, int b) internal { if (a == b) { - emit log("Error: a != b not satisfied [int]"); - emit log_named_int(" Expected", b); - emit log_named_int(" Actual", a); + emit log ("Error: a != b not satisfied [int]"); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); fail(); } } function assertNotEq(int a, int b, string memory err) internal { if (a == b) { - emit log_named_string("Error", err); + emit log_named_string ("Error", err); assertNotEq(a, b); } } function assertNotEq(uint a, uint b) internal { if (a == b) { - emit log("Error: a != b not satisfied [uint]"); - emit log_named_uint(" Expected", b); - emit log_named_uint(" Actual", a); + emit log ("Error: a != b not satisfied [uint]"); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); fail(); } } function assertNotEq(uint a, uint b, string memory err) internal { if (a == b) { - emit log_named_string("Error", err); + emit log_named_string ("Error", err); assertNotEq(a, b); } } function assertNotEq(string memory a, string memory b) internal { if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { - emit log("Error: a != b not satisfied [string]"); - emit log_named_string(" Value a", a); - emit log_named_string(" Value b", b); + emit log ("Error: a != b not satisfied [string]"); + emit log_named_string (" Value a", a); + emit log_named_string (" Value b", b); fail(); } } function assertNotEq(string memory a, string memory b, string memory err) internal { if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { - emit log_named_string("Error", err); + emit log_named_string ("Error", err); assertNotEq(a, b); } } @@ -354,14 +354,14 @@ abstract contract Test is DSTest { function assertFalse(bool condition) internal { if (condition) { - emit log("Error: Assertion Failed"); + emit log ("Error: Assertion Failed"); fail(); } } function assertFalse(bool condition, string memory err) internal { if (condition) { - emit log_named_string("Error", err); + emit log_named_string ("Error", err); assertFalse(condition); } } From 7e73c210ab35fcb6c5c81e43df7e342951907aca Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:24:47 +1000 Subject: [PATCH 05/19] fix(test): correct yoink/translation errors --- src/Test.sol | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index bb69005f..e97486ce 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -170,11 +170,11 @@ abstract contract Test is DSTest { uint256 delta = a > b ? a - b : b - a; if (delta > maxDelta) { - emit log ("Error", err); - emit log_named_uint (" Expected", b); - emit log_named_uint (" Actual", a); - emit log_named_uint (" Max Delta", maxDelta); - emit log_named_uint (" Delta", delta); + emit log_named_string ("Error", err); + emit log_named_uint (" Expected", b); + emit log_named_uint (" Actual", a); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", delta); fail(); } } @@ -183,7 +183,7 @@ abstract contract Test is DSTest { int256 b, int256 maxDelta ) internal virtual { - uint256 delta = a > b ? a - b : b - a; + int256 delta = a > b ? a - b : b - a; if (delta > maxDelta) { emit log ("Error: a ~= b not satisfied [int]"); @@ -201,14 +201,14 @@ abstract contract Test is DSTest { int256 maxDelta, string memory err ) internal virtual { - uint256 delta = a > b ? a - b : b - a; + int256 delta = a > b ? a - b : b - a; if (delta > maxDelta) { - emit log ("Error", err); - emit log_named_int (" Expected", b); - emit log_named_int (" Actual", a); - emit log_named_int (" Max Delta", maxDelta); - emit log_named_int (" Delta", delta); + emit log_named_string ("Error", err); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); + emit log_named_int (" Max Delta", maxDelta); + emit log_named_int (" Delta", delta); fail(); } } @@ -247,7 +247,7 @@ abstract contract Test is DSTest { uint256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; if (percentDelta > maxPercentDelta) { - emit log ("Error", err); + emit log_named_string ("Error", err); emit log_named_uint (" Expected", b); emit log_named_uint (" Actual", a); emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18); From 1a78d1b830c3d2f258ad355e034097a362694bb4 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:25:02 +1000 Subject: [PATCH 06/19] feat(test): add more bool asserts, t11s assertFalse --- src/Test.sol | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index e97486ce..9e6d88d4 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -349,21 +349,19 @@ abstract contract Test is DSTest { } /*////////////////////////////////////////////////////////////////////////// - ASSERT FALSE + BOOL ASSERTS //////////////////////////////////////////////////////////////////////////*/ - function assertFalse(bool condition) internal { - if (condition) { - emit log ("Error: Assertion Failed"); - fail(); - } + function assertEq(bool a, bool b) internal virtual { + b ? assertTrue(a) : assertFalse(a); } - function assertFalse(bool condition, string memory err) internal { - if (condition) { - emit log_named_string ("Error", err); - assertFalse(condition); - } + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); } } From 3e8d69363f51d112d4fafc410f51d540e79a5040 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:32:12 +1000 Subject: [PATCH 07/19] feat(test): add assertEq(bool, err) --- src/Test.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index 9e6d88d4..1741c92e 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -356,6 +356,10 @@ abstract contract Test is DSTest { b ? assertTrue(a) : assertFalse(a); } + function assertEq(bool a, bool b, string memory err) internal virtual { + b ? assertTrue(a, err) : assertFalse(a, err); + } + function assertFalse(bool data) internal virtual { assertTrue(!data); } From b61c6c44a90cf77a8a37dad8bf3cc6d72937b137 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Wed, 20 Apr 2022 16:47:53 +1000 Subject: [PATCH 08/19] feat(test): add assertEq(bytes, bytes) --- src/Test.sol | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index 1741c92e..59c46e85 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -367,6 +367,28 @@ abstract contract Test is DSTest { function assertFalse(bool data, string memory err) internal virtual { assertTrue(!data, err); } + + /*////////////////////////////////////////////////////////////////////////// + BYTES ASSERTS + //////////////////////////////////////////////////////////////////////////*/ + + function assertEq(bytes memory a, bytes memory b) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log ("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log_named_string ("Error", err); + emit log_named_bytes (" Expected", b); + emit log_named_bytes (" Actual", a); + fail(); + } + } } From 51ff84f599ae52b645c1f3a1abec4e87b10de935 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 10:27:16 +1000 Subject: [PATCH 09/19] refactor(test): standardized approx eq assertion naming --- src/Test.sol | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 59c46e85..6b69685b 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -144,7 +144,7 @@ abstract contract Test is DSTest { APPROX EQUAL //////////////////////////////////////////////////////////////////////////*/ - function assertApproxEq( + function assertApproxEqAbs( uint256 a, uint256 b, uint256 maxDelta @@ -161,7 +161,7 @@ abstract contract Test is DSTest { } } - function assertApproxEq( + function assertApproxEqAbs( uint256 a, uint256 b, uint256 maxDelta, @@ -178,7 +178,8 @@ abstract contract Test is DSTest { fail(); } } - function assertApproxEq( + + function assertApproxEqAbs( int256 a, int256 b, int256 maxDelta @@ -195,7 +196,7 @@ abstract contract Test is DSTest { } } - function assertApproxEq( + function assertApproxEqAbs( int256 a, int256 b, int256 maxDelta, @@ -217,7 +218,7 @@ abstract contract Test is DSTest { REL APPROX EQUAL //////////////////////////////////////////////////////////////////////////*/ - function assertRelApproxEq( + function assertApproxEqRel( uint256 a, uint256 b, uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% @@ -236,7 +237,7 @@ abstract contract Test is DSTest { } } - function assertRelApproxEq( + function assertApproxEqRel( uint256 a, uint256 b, uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% From 3e0ef00b7b0b5a498d838bb1e209ef1d3367ec80 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 10:31:16 +1000 Subject: [PATCH 10/19] refactor(test): drop assertNotEq as it's bad practice --- src/Test.sol | 92 ---------------------------------------------------- 1 file changed, 92 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 6b69685b..6c438afd 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -257,98 +257,6 @@ abstract contract Test is DSTest { } } - /*////////////////////////////////////////////////////////////////////////// - NOT EQUAL - //////////////////////////////////////////////////////////////////////////*/ - - function assertNotEq(address a, address b) internal { - if (a == b) { - emit log ("Error: a != b not satisfied [address]"); - emit log_named_address (" Expected", b); - emit log_named_address (" Actual", a); - fail(); - } - } - - function assertNotEq(address a, address b, string memory err) internal { - if (a == b) { - emit log_named_string ("Error", err); - assertNotEq(a, b); - } - } - - function assertNotEq(bytes32 a, bytes32 b) internal { - if (a == b) { - emit log ("Error: a != b not satisfied [bytes32]"); - emit log_named_bytes32 (" Expected", b); - emit log_named_bytes32 (" Actual", a); - fail(); - } - } - - function assertNotEq(bytes32 a, bytes32 b, string memory err) internal { - if (a == b) { - emit log_named_string ("Error", err); - assertNotEq(a, b); - } - } - - function assertNotEq32(bytes32 a, bytes32 b) internal { - assertNotEq(a, b); - } - - function assertNotEq32(bytes32 a, bytes32 b, string memory err) internal { - assertNotEq(a, b, err); - } - - function assertNotEq(int a, int b) internal { - if (a == b) { - emit log ("Error: a != b not satisfied [int]"); - emit log_named_int (" Expected", b); - emit log_named_int (" Actual", a); - fail(); - } - } - - function assertNotEq(int a, int b, string memory err) internal { - if (a == b) { - emit log_named_string ("Error", err); - assertNotEq(a, b); - } - } - - function assertNotEq(uint a, uint b) internal { - if (a == b) { - emit log ("Error: a != b not satisfied [uint]"); - emit log_named_uint (" Expected", b); - emit log_named_uint (" Actual", a); - fail(); - } - } - - function assertNotEq(uint a, uint b, string memory err) internal { - if (a == b) { - emit log_named_string ("Error", err); - assertNotEq(a, b); - } - } - - function assertNotEq(string memory a, string memory b) internal { - if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { - emit log ("Error: a != b not satisfied [string]"); - emit log_named_string (" Value a", a); - emit log_named_string (" Value b", b); - fail(); - } - } - - function assertNotEq(string memory a, string memory b, string memory err) internal { - if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { - emit log_named_string ("Error", err); - assertNotEq(a, b); - } - } - /*////////////////////////////////////////////////////////////////////////// BOOL ASSERTS //////////////////////////////////////////////////////////////////////////*/ From 1f08a7655f0066fcdc9a6036802dbd31a448ed1f Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 10:37:46 +1000 Subject: [PATCH 11/19] refactor(test): improve assertEq(bool,bool) error messaging --- src/Test.sol | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 6c438afd..f954d940 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -141,7 +141,7 @@ abstract contract Test is DSTest { } /*////////////////////////////////////////////////////////////////////////// - APPROX EQUAL + ASSERTIONS //////////////////////////////////////////////////////////////////////////*/ function assertApproxEqAbs( @@ -261,8 +261,22 @@ abstract contract Test is DSTest { BOOL ASSERTS //////////////////////////////////////////////////////////////////////////*/ - function assertEq(bool a, bool b) internal virtual { - b ? assertTrue(a) : assertFalse(a); + function assertEq(bool a, bool b) internal { + if (a != b) { + emit log_named_string("Error: a == b not satisfied [bool]"); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } } function assertEq(bool a, bool b, string memory err) internal virtual { From f0e1ba9b4178c5357e23a3f9da3d47a29c812c10 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 11:25:12 +1000 Subject: [PATCH 12/19] fix(test): remove duplicate assertEq(bool,bool) --- src/Test.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index f954d940..d40c4e45 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -279,10 +279,6 @@ abstract contract Test is DSTest { } } - function assertEq(bool a, bool b, string memory err) internal virtual { - b ? assertTrue(a, err) : assertFalse(a, err); - } - function assertFalse(bool data) internal virtual { assertTrue(!data); } From 03355c9583eaf7b807300c5d79a61749f94fb3ab Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 11:27:34 +1000 Subject: [PATCH 13/19] fix(test): use log instead of log_named_string --- src/Test.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index d40c4e45..7f85aa93 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -263,9 +263,9 @@ abstract contract Test is DSTest { function assertEq(bool a, bool b) internal { if (a != b) { - emit log_named_string("Error: a == b not satisfied [bool]"); - emit log_named_string(" Expected", b ? "true" : "false"); - emit log_named_string(" Actual", a ? "true" : "false"); + emit log ("Error: a == b not satisfied [bool]"); + emit log_named_string (" Expected", b ? "true" : "false"); + emit log_named_string (" Actual", a ? "true" : "false"); fail(); } } From 2c2337492baa475fa04bd3a539541d9d778a9c59 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 11:27:53 +1000 Subject: [PATCH 14/19] feat(test): add int256 impls for assertApproxEqRel --- src/Test.sol | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index 7f85aa93..9d33c4c5 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -257,6 +257,45 @@ abstract contract Test is DSTest { } } + function assertApproxEqRel( + int256 a, + int256 b, + int256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + int256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log ("Error: a ~= b not satisfied [uint]"); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); + emit log_named_decimal_int (" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_int (" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + int256 a, + int256 b, + int256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + int256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log_named_string ("Error", err); + emit log_named_int (" Expected", b); + emit log_named_int (" Actual", a); + emit log_named_decimal_int (" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_int (" % Delta", percentDelta, 18); + fail(); + } + } + /*////////////////////////////////////////////////////////////////////////// BOOL ASSERTS //////////////////////////////////////////////////////////////////////////*/ From 924456ad2a19fe4e504639988a856c58244079d2 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Thu, 21 Apr 2022 11:30:25 +1000 Subject: [PATCH 15/19] style(test): re-order code and group overloads together --- src/Test.sol | 108 +++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 9d33c4c5..759e2592 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -141,7 +141,59 @@ abstract contract Test is DSTest { } /*////////////////////////////////////////////////////////////////////////// - ASSERTIONS + ASSERT EQ + //////////////////////////////////////////////////////////////////////////*/ + + function assertEq(bool a, bool b) internal { + if (a != b) { + emit log ("Error: a == b not satisfied [bool]"); + emit log_named_string (" Expected", b ? "true" : "false"); + emit log_named_string (" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log ("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log_named_string ("Error", err); + emit log_named_bytes (" Expected", b); + emit log_named_bytes (" Actual", a); + fail(); + } + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT APPROX EQ ABS //////////////////////////////////////////////////////////////////////////*/ function assertApproxEqAbs( @@ -215,7 +267,7 @@ abstract contract Test is DSTest { } /*////////////////////////////////////////////////////////////////////////// - REL APPROX EQUAL + ASSERT APPROX EQ REL //////////////////////////////////////////////////////////////////////////*/ function assertApproxEqRel( @@ -295,58 +347,6 @@ abstract contract Test is DSTest { fail(); } } - - /*////////////////////////////////////////////////////////////////////////// - BOOL ASSERTS - //////////////////////////////////////////////////////////////////////////*/ - - function assertEq(bool a, bool b) internal { - if (a != b) { - emit log ("Error: a == b not satisfied [bool]"); - emit log_named_string (" Expected", b ? "true" : "false"); - emit log_named_string (" Actual", a ? "true" : "false"); - fail(); - } - } - - function assertEq(bool a, bool b, string memory err) internal { - if (a != b) { - emit log_named_string("Error", err); - emit log_named_string(" Expected", b ? "true" : "false"); - emit log_named_string(" Actual", a ? "true" : "false"); - fail(); - } - } - - function assertFalse(bool data) internal virtual { - assertTrue(!data); - } - - function assertFalse(bool data, string memory err) internal virtual { - assertTrue(!data, err); - } - - /*////////////////////////////////////////////////////////////////////////// - BYTES ASSERTS - //////////////////////////////////////////////////////////////////////////*/ - - function assertEq(bytes memory a, bytes memory b) internal virtual { - if (keccak256(a) != keccak256(b)) { - emit log ("Error: a == b not satisfied [bytes]"); - emit log_named_bytes(" Expected", b); - emit log_named_bytes(" Actual", a); - fail(); - } - } - - function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { - if (keccak256(a) != keccak256(b)) { - emit log_named_string ("Error", err); - emit log_named_bytes (" Expected", b); - emit log_named_bytes (" Actual", a); - fail(); - } - } } From 99a36d8f522b5b5db867d8633fb8ed887884f6de Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Fri, 22 Apr 2022 10:32:30 +1000 Subject: [PATCH 16/19] style(test): use single STD-ASSERTIONS code region --- src/Test.sol | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index 759e2592..c57e5ea3 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -141,7 +141,7 @@ abstract contract Test is DSTest { } /*////////////////////////////////////////////////////////////////////////// - ASSERT EQ + STD-ASSERTIONS //////////////////////////////////////////////////////////////////////////*/ function assertEq(bool a, bool b) internal { @@ -180,10 +180,6 @@ abstract contract Test is DSTest { } } - /*////////////////////////////////////////////////////////////////////////// - ASSERT FALSE - //////////////////////////////////////////////////////////////////////////*/ - function assertFalse(bool data) internal virtual { assertTrue(!data); } @@ -192,10 +188,6 @@ abstract contract Test is DSTest { assertTrue(!data, err); } - /*////////////////////////////////////////////////////////////////////////// - ASSERT APPROX EQ ABS - //////////////////////////////////////////////////////////////////////////*/ - function assertApproxEqAbs( uint256 a, uint256 b, @@ -266,10 +258,6 @@ abstract contract Test is DSTest { } } - /*////////////////////////////////////////////////////////////////////////// - ASSERT APPROX EQ REL - //////////////////////////////////////////////////////////////////////////*/ - function assertApproxEqRel( uint256 a, uint256 b, From 3c15901e223e9c2b311d1c67c64c7d2e40e8615d Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Fri, 22 Apr 2022 10:33:11 +1000 Subject: [PATCH 17/19] style(test): declare assertFalse before assertEq --- src/Test.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Test.sol b/src/Test.sol index c57e5ea3..78f3d82f 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -144,6 +144,14 @@ abstract contract Test is DSTest { STD-ASSERTIONS //////////////////////////////////////////////////////////////////////////*/ + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + function assertEq(bool a, bool b) internal { if (a != b) { emit log ("Error: a == b not satisfied [bool]"); @@ -180,14 +188,6 @@ abstract contract Test is DSTest { } } - function assertFalse(bool data) internal virtual { - assertTrue(!data); - } - - function assertFalse(bool data, string memory err) internal virtual { - assertTrue(!data, err); - } - function assertApproxEqAbs( uint256 a, uint256 b, From 113b11cc97dbe416db99b1e8dfdc8144a34126d2 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Fri, 22 Apr 2022 10:35:13 +1000 Subject: [PATCH 18/19] style(test): add STD-CHEATS code region --- src/Test.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index 78f3d82f..ce673e05 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -14,6 +14,10 @@ abstract contract Test is DSTest { Vm public constant vm = Vm(HEVM_ADDRESS); StdStorage internal stdstore; + /*////////////////////////////////////////////////////////////////////////// + STD-CHEATS + //////////////////////////////////////////////////////////////////////////*/ + // Skip forward or rewind time by the specified number of seconds function skip(uint256 time) public { vm.warp(block.timestamp + time); From b43499554146b5516988e2d66752db1c9893ef18 Mon Sep 17 00:00:00 2001 From: Oliver Chalk Date: Fri, 22 Apr 2022 23:12:32 +1000 Subject: [PATCH 19/19] style: add STD-ERRORS & STD-STORAGE delimters --- src/Test.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Test.sol b/src/Test.sol index ce673e05..162a525f 100644 --- a/src/Test.sol +++ b/src/Test.sol @@ -341,6 +341,9 @@ abstract contract Test is DSTest { } } +/*////////////////////////////////////////////////////////////////////////// + STD-ERRORS +//////////////////////////////////////////////////////////////////////////*/ library stdError { bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); @@ -367,6 +370,9 @@ struct StdStorage { bytes32 _set; } +/*////////////////////////////////////////////////////////////////////////// + STD-STORAGE +//////////////////////////////////////////////////////////////////////////*/ library stdStorage { event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot);