EnumerableSet.behavior.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. const { expect } = require('chai');
  2. const { PANIC_CODES } = require('@nomicfoundation/hardhat-chai-matchers/panic');
  3. function shouldBehaveLikeSet() {
  4. async function expectMembersMatch(methods, values) {
  5. expect(await methods.length()).to.equal(values.length);
  6. for (const value of values) expect(await methods.contains(value)).to.be.true;
  7. expect(await Promise.all(values.map((_, index) => methods.at(index)))).to.have.deep.members(values);
  8. expect([...(await methods.values())]).to.have.deep.members(values);
  9. }
  10. it('starts empty', async function () {
  11. expect(await this.methods.contains(this.valueA)).to.be.false;
  12. await expectMembersMatch(this.methods, []);
  13. });
  14. describe('add', function () {
  15. it('adds a value', async function () {
  16. await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(true);
  17. await expectMembersMatch(this.methods, [this.valueA]);
  18. });
  19. it('adds several values', async function () {
  20. await this.methods.add(this.valueA);
  21. await this.methods.add(this.valueB);
  22. await expectMembersMatch(this.methods, [this.valueA, this.valueB]);
  23. expect(await this.methods.contains(this.valueC)).to.be.false;
  24. });
  25. it('returns false when adding values already in the set', async function () {
  26. await this.methods.add(this.valueA);
  27. await expect(this.methods.add(this.valueA)).to.emit(this.mock, this.events.addReturn).withArgs(false);
  28. await expectMembersMatch(this.methods, [this.valueA]);
  29. });
  30. });
  31. describe('at', function () {
  32. it('reverts when retrieving non-existent elements', async function () {
  33. await expect(this.methods.at(0)).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
  34. });
  35. it('retrieves existing element', async function () {
  36. await this.methods.add(this.valueA);
  37. expect(await this.methods.at(0)).to.deep.equal(this.valueA);
  38. });
  39. });
  40. describe('remove', function () {
  41. it('removes added values', async function () {
  42. await this.methods.add(this.valueA);
  43. await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(true);
  44. expect(await this.methods.contains(this.valueA)).to.be.false;
  45. await expectMembersMatch(this.methods, []);
  46. });
  47. it('returns false when removing values not in the set', async function () {
  48. await expect(this.methods.remove(this.valueA)).to.emit(this.mock, this.events.removeReturn).withArgs(false);
  49. expect(await this.methods.contains(this.valueA)).to.be.false;
  50. });
  51. it('adds and removes multiple values', async function () {
  52. // []
  53. await this.methods.add(this.valueA);
  54. await this.methods.add(this.valueC);
  55. // [A, C]
  56. await this.methods.remove(this.valueA);
  57. await this.methods.remove(this.valueB);
  58. // [C]
  59. await this.methods.add(this.valueB);
  60. // [C, B]
  61. await this.methods.add(this.valueA);
  62. await this.methods.remove(this.valueC);
  63. // [A, B]
  64. await this.methods.add(this.valueA);
  65. await this.methods.add(this.valueB);
  66. // [A, B]
  67. await this.methods.add(this.valueC);
  68. await this.methods.remove(this.valueA);
  69. // [B, C]
  70. await this.methods.add(this.valueA);
  71. await this.methods.remove(this.valueB);
  72. // [A, C]
  73. await expectMembersMatch(this.methods, [this.valueA, this.valueC]);
  74. expect(await this.methods.contains(this.valueB)).to.be.false;
  75. });
  76. });
  77. describe('clear', function () {
  78. it('clears a single value', async function () {
  79. await this.methods.add(this.valueA);
  80. await this.methods.clear();
  81. expect(await this.methods.contains(this.valueA)).to.be.false;
  82. await expectMembersMatch(this.methods, []);
  83. });
  84. it('clears multiple values', async function () {
  85. await this.methods.add(this.valueA);
  86. await this.methods.add(this.valueB);
  87. await this.methods.add(this.valueC);
  88. await this.methods.clear();
  89. expect(await this.methods.contains(this.valueA)).to.be.false;
  90. expect(await this.methods.contains(this.valueB)).to.be.false;
  91. expect(await this.methods.contains(this.valueC)).to.be.false;
  92. await expectMembersMatch(this.methods, []);
  93. });
  94. it('does not revert on empty set', async function () {
  95. await this.methods.clear();
  96. });
  97. it('clear then add value', async function () {
  98. await this.methods.add(this.valueA);
  99. await this.methods.add(this.valueB);
  100. await this.methods.add(this.valueC);
  101. await this.methods.clear();
  102. await this.methods.add(this.valueA);
  103. expect(await this.methods.contains(this.valueA)).to.be.true;
  104. expect(await this.methods.contains(this.valueB)).to.be.false;
  105. expect(await this.methods.contains(this.valueC)).to.be.false;
  106. await expectMembersMatch(this.methods, [this.valueA]);
  107. });
  108. });
  109. }
  110. module.exports = {
  111. shouldBehaveLikeSet,
  112. };