Heap.test.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  4. const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
  5. async function fixture() {
  6. const mock = await ethers.deployContract('$Heap');
  7. return { mock };
  8. }
  9. describe('Heap', function () {
  10. beforeEach(async function () {
  11. Object.assign(this, await loadFixture(fixture));
  12. });
  13. describe('Uint256Heap', function () {
  14. it('starts empty', async function () {
  15. expect(await this.mock.$length(0)).to.equal(0n);
  16. });
  17. it('peek, pop and replace from empty', async function () {
  18. await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
  19. await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);
  20. await expect(this.mock.$replace(0, 0n)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);
  21. });
  22. it('clear', async function () {
  23. await this.mock.$insert(0, 42n);
  24. expect(await this.mock.$length(0)).to.equal(1n);
  25. expect(await this.mock.$peek(0)).to.equal(42n);
  26. await this.mock.$clear(0);
  27. expect(await this.mock.$length(0)).to.equal(0n);
  28. await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
  29. });
  30. it('support duplicated items', async function () {
  31. expect(await this.mock.$length(0)).to.equal(0n);
  32. // insert 5 times
  33. await this.mock.$insert(0, 42n);
  34. await this.mock.$insert(0, 42n);
  35. await this.mock.$insert(0, 42n);
  36. await this.mock.$insert(0, 42n);
  37. await this.mock.$insert(0, 42n);
  38. // pop 5 times
  39. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n);
  40. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n);
  41. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n);
  42. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n);
  43. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(42n);
  44. // popping a 6th time panics
  45. await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);
  46. });
  47. it('insert, pop and replace', async function () {
  48. const heap = [];
  49. for (const { op, value } of [
  50. { op: 'insert', value: 712 }, // [712]
  51. { op: 'insert', value: 20 }, // [20, 712]
  52. { op: 'insert', value: 4337 }, // [20, 712, 4437]
  53. { op: 'pop' }, // 20, [712, 4437]
  54. { op: 'insert', value: 1559 }, // [712, 1559, 4437]
  55. { op: 'insert', value: 165 }, // [165, 712, 1559, 4437]
  56. { op: 'insert', value: 155 }, // [155, 165, 712, 1559, 4437]
  57. { op: 'insert', value: 7702 }, // [155, 165, 712, 1559, 4437, 7702]
  58. { op: 'pop' }, // 155, [165, 712, 1559, 4437, 7702]
  59. { op: 'replace', value: 721 }, // 165, [712, 721, 1559, 4437, 7702]
  60. { op: 'pop' }, // 712, [721, 1559, 4437, 7702]
  61. { op: 'pop' }, // 721, [1559, 4437, 7702]
  62. { op: 'pop' }, // 1559, [4437, 7702]
  63. { op: 'pop' }, // 4437, [7702]
  64. { op: 'pop' }, // 7702, []
  65. { op: 'pop' }, // panic
  66. { op: 'replace', value: '1363' }, // panic
  67. ]) {
  68. switch (op) {
  69. case 'insert':
  70. await this.mock.$insert(0, value);
  71. heap.push(value);
  72. heap.sort((a, b) => a - b);
  73. break;
  74. case 'pop':
  75. if (heap.length == 0) {
  76. await expect(this.mock.$pop(0)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);
  77. } else {
  78. await expect(this.mock.$pop(0)).to.emit(this.mock, 'return$pop').withArgs(heap.shift());
  79. }
  80. break;
  81. case 'replace':
  82. if (heap.length == 0) {
  83. await expect(this.mock.$replace(0, value)).to.be.revertedWithPanic(PANIC_CODES.POP_ON_EMPTY_ARRAY);
  84. } else {
  85. await expect(this.mock.$replace(0, value)).to.emit(this.mock, 'return$replace').withArgs(heap.shift());
  86. heap.push(value);
  87. heap.sort((a, b) => a - b);
  88. }
  89. break;
  90. }
  91. expect(await this.mock.$length(0)).to.equal(heap.length);
  92. if (heap.length == 0) {
  93. await expect(this.mock.$peek(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
  94. } else {
  95. expect(await this.mock.$peek(0)).to.equal(heap[0]);
  96. }
  97. }
  98. });
  99. });
  100. });