// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
import {DSTest} from "ds-test/test.sol";
import {stdMath} from "./StdMath.sol";
abstract contract StdAssertions is DSTest {
event log_array(uint256[] val);
event log_array(int256[] val);
event log_array(address[] val);
event log_named_array(string key, uint256[] val);
event log_named_array(string key, int256[] val);
event log_named_array(string key, address[] val);
function fail(string memory err) internal virtual {
emit log_named_string("Error", err);
fail();
}
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 virtual {
if (a != b) {
emit log("Error: a == b not satisfied [bool]");
emit log_named_string(" Left", a ? "true" : "false");
emit log_named_string(" Right", b ? "true" : "false");
fail();
}
}
function assertEq(bool a, bool b, string memory err) internal virtual {
if (a != b) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
function assertEq(bytes memory a, bytes memory b) internal virtual {
assertEq0(a, b);
}
function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual {
assertEq0(a, b, err);
}
function assertEq(uint256[] memory a, uint256[] memory b) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [uint[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
function assertEq(int256[] memory a, int256[] memory b) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [int[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
function assertEq(address[] memory a, address[] memory b) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log("Error: a == b not satisfied [address[]]");
emit log_named_array(" Left", a);
emit log_named_array(" Right", b);
fail();
}
}
function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual {
if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
emit log_named_string("Error", err);
assertEq(a, b);
}
}
// Legacy helper
function assertEqUint(uint256 a, uint256 b) internal virtual {
assertEq(uint256(a), uint256(b));
}
function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_uint(" Left", a);
emit log_named_uint(" Right", b);
emit log_named_uint(" Max Delta", maxDelta);
emit log_named_uint(" Delta", delta);
fail();
}
}
function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbs(a, b, maxDelta);
}
}
function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_decimal_uint(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, decimals);
emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
emit log_named_decimal_uint(" Delta", delta, decimals);
fail();
}
}
function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, string memory err)
internal
virtual
{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
}
}
function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_int(" Left", a);
emit log_named_int(" Right", b);
emit log_named_uint(" Max Delta", maxDelta);
emit log_named_uint(" Delta", delta);
fail();
}
}
function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbs(a, b, maxDelta);
}
}
function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internal virtual {
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_decimal_int(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, decimals);
emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
emit log_named_decimal_uint(" Delta", delta, decimals);
fail();
}
}
function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, string memory err)
internal
virtual
{
uint256 delta = stdMath.delta(a, b);
if (delta > maxDelta) {
emit log_named_string("Error", err);
assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
}
}
function assertApproxEqRel(
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 left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_uint(" Left", a);
emit log_named_uint(" Right", b);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18);
fail();
}
}
function assertApproxEqRel(
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, err); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRel(a, b, maxPercentDelta);
}
}
function assertApproxEqRelDecimal(
uint256 a,
uint256 b,
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
uint256 decimals
) internal virtual {
if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [uint]");
emit log_named_decimal_uint(" Left", a, decimals);
emit log_named_decimal_uint(" Right", b, decimals);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18);
fail();
}
}
function assertApproxEqRelDecimal(
uint256 a,
uint256 b,
uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
uint256 decimals,
string memory err
) internal virtual {
if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
}
}
function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual {
if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_int(" Left", a);
emit log_named_int(" Right", b);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18);
fail();
}
}
function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual {
if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRel(a, b, maxPercentDelta);
}
}
function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internal virtual {
if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log("Error: a ~= b not satisfied [int]");
emit log_named_decimal_int(" Left", a, decimals);
emit log_named_decimal_int(" Right", b, decimals);
emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18);
fail();
}
}
function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, string memory err)
internal
virtual
{
if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
uint256 percentDelta = stdMath.percentDelta(a, b);
if (percentDelta > maxPercentDelta) {
emit log_named_string("Error", err);
assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
}
}
function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB) internal virtual {
assertEqCall(target, callDataA, target, callDataB, true);
}
function assertEqCall(address targetA, bytes memory callDataA, address targetB, bytes memory callDataB)
internal
virtual
{
assertEqCall(targetA, callDataA, targetB, callDataB, true);
}
function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB, bool strictRevertData)
internal
virtual
{
assertEqCall(target, callDataA, target, callDataB, strictRevertData);
}
function assertEqCall(
address targetA,
bytes memory callDataA,
address targetB,
bytes memory callDataB,
bool strictRevertData
) internal virtual {
(bool successA, bytes memory returnDataA) = address(targetA).call(callDataA);
(bool successB, bytes memory returnDataB) = address(targetB).call(callDataB);
if (successA && successB) {
assertEq(returnDataA, returnDataB, "Call return data does not match");
}
if (!successA && !successB && strictRevertData) {
assertEq(returnDataA, returnDataB, "Call revert data does not match");
}
if (!successA && successB) {
emit log("Error: Calls were not equal");
emit log_named_bytes(" Left call revert data", returnDataA);
emit log_named_bytes(" Right call return data", returnDataB);
fail();
}
if (successA && !successB) {
emit log("Error: Calls were not equal");
emit log_named_bytes(" Left call return data", returnDataA);
emit log_named_bytes(" Right call revert data", returnDataB);
fail();
}
}
}