Heap.t.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. const format = require('../format-lines');
  2. const { TYPES } = require('./Heap.opts');
  3. /* eslint-disable max-len */
  4. const header = `\
  5. pragma solidity ^0.8.20;
  6. import {Test} from "forge-std/Test.sol";
  7. import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
  8. import {Heap} from "@openzeppelin/contracts/utils/structs/Heap.sol";
  9. import {Comparators} from "@openzeppelin/contracts/utils/Comparators.sol";
  10. `;
  11. const generate = ({ struct, valueType }) => `\
  12. contract ${struct}Test is Test {
  13. using Heap for Heap.${struct};
  14. Heap.${struct} internal heap;
  15. function _validateHeap(function(uint256, uint256) view returns (bool) comp) internal {
  16. for (uint32 i = 0; i < heap.length(); ++i) {
  17. // lookups
  18. assertEq(i, heap.data[heap.data[i].index].lookup);
  19. assertEq(i, heap.data[heap.data[i].lookup].index);
  20. // ordering: each node has a value bigger then its parent
  21. if (i > 0)
  22. assertFalse(comp(heap.data[heap.data[i].index].value, heap.data[heap.data[(i - 1) / 2].index].value));
  23. }
  24. }
  25. function testFuzz(${valueType}[] calldata input) public {
  26. vm.assume(input.length < 0x20);
  27. assertEq(heap.length(), 0);
  28. uint256 min = type(uint256).max;
  29. for (uint256 i = 0; i < input.length; ++i) {
  30. heap.insert(input[i]);
  31. assertEq(heap.length(), i + 1);
  32. _validateHeap(Comparators.lt);
  33. min = Math.min(min, input[i]);
  34. assertEq(heap.peek(), min);
  35. }
  36. uint256 max = 0;
  37. for (uint256 i = 0; i < input.length; ++i) {
  38. ${valueType} top = heap.peek();
  39. ${valueType} pop = heap.pop();
  40. assertEq(heap.length(), input.length - i - 1);
  41. _validateHeap(Comparators.lt);
  42. assertEq(pop, top);
  43. assertGe(pop, max);
  44. max = pop;
  45. }
  46. }
  47. function testFuzzGt(${valueType}[] calldata input) public {
  48. vm.assume(input.length < 0x20);
  49. assertEq(heap.length(), 0);
  50. uint256 max = 0;
  51. for (uint256 i = 0; i < input.length; ++i) {
  52. heap.insert(input[i], Comparators.gt);
  53. assertEq(heap.length(), i + 1);
  54. _validateHeap(Comparators.gt);
  55. max = Math.max(max, input[i]);
  56. assertEq(heap.peek(), max);
  57. }
  58. uint256 min = type(uint256).max;
  59. for (uint256 i = 0; i < input.length; ++i) {
  60. ${valueType} top = heap.peek();
  61. ${valueType} pop = heap.pop(Comparators.gt);
  62. assertEq(heap.length(), input.length - i - 1);
  63. _validateHeap(Comparators.gt);
  64. assertEq(pop, top);
  65. assertLe(pop, min);
  66. min = pop;
  67. }
  68. }
  69. }
  70. `;
  71. // GENERATE
  72. module.exports = format(header, ...TYPES.map(type => generate(type)));