SignedMath.t.sol 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import {Test} from "forge-std/Test.sol";
  4. import {Math} from "../../../contracts/utils/math/Math.sol";
  5. import {SignedMath} from "../../../contracts/utils/math/SignedMath.sol";
  6. contract SignedMathTest is Test {
  7. function testSymbolicTernary(bool f, int256 a, int256 b) public pure {
  8. assertEq(SignedMath.ternary(f, a, b), f ? a : b);
  9. }
  10. // MIN & MAX
  11. function testSymbolicMinMax(int256 a, int256 b) public pure {
  12. assertEq(SignedMath.min(a, b), a < b ? a : b);
  13. assertEq(SignedMath.max(a, b), a > b ? a : b);
  14. }
  15. // MIN
  16. function testSymbolicMin(int256 a, int256 b) public pure {
  17. int256 result = SignedMath.min(a, b);
  18. assertLe(result, a);
  19. assertLe(result, b);
  20. assertTrue(result == a || result == b);
  21. }
  22. // MAX
  23. function testSymbolicMax(int256 a, int256 b) public pure {
  24. int256 result = SignedMath.max(a, b);
  25. assertGe(result, a);
  26. assertGe(result, b);
  27. assertTrue(result == a || result == b);
  28. }
  29. // AVERAGE
  30. // 1. simple test, not full int256 range
  31. function testAverage1(int256 a, int256 b) public pure {
  32. a = bound(a, type(int256).min / 2, type(int256).max / 2);
  33. b = bound(b, type(int256).min / 2, type(int256).max / 2);
  34. int256 result = SignedMath.average(a, b);
  35. assertEq(result, (a + b) / 2);
  36. }
  37. // 2. more complex test, full int256 range (solver timeout 0 = no timeout)
  38. /// @custom:halmos --solver-timeout-assertion 0
  39. function testSymbolicAverage2(int256 a, int256 b) public pure {
  40. (int256 result, int256 min, int256 max) = (
  41. SignedMath.average(a, b),
  42. SignedMath.min(a, b),
  43. SignedMath.max(a, b)
  44. );
  45. // average must be between `a` and `b`
  46. assertGe(result, min);
  47. assertLe(result, max);
  48. unchecked {
  49. // must be unchecked in order to support `a = type(int256).min, b = type(int256).max`
  50. uint256 deltaLower = uint256(result - min);
  51. uint256 deltaUpper = uint256(max - result);
  52. uint256 remainder = uint256((a & 1) ^ (b & 1));
  53. assertEq(remainder, Math.max(deltaLower, deltaUpper) - Math.min(deltaLower, deltaUpper));
  54. }
  55. }
  56. // ABS
  57. function testSymbolicAbs(int256 a) public pure {
  58. uint256 result = SignedMath.abs(a);
  59. unchecked {
  60. // must be unchecked in order to support `n = type(int256).min`
  61. assertEq(result, a < 0 ? uint256(-a) : uint256(a));
  62. }
  63. }
  64. }