EnumerableMap.behavior.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const zip = require('lodash.zip');
  4. function shouldBehaveLikeMap(keys, values, zeroValue, methods, events) {
  5. const [keyA, keyB, keyC] = keys;
  6. const [valueA, valueB, valueC] = values;
  7. async function expectMembersMatch(map, keys, values) {
  8. expect(keys.length).to.equal(values.length);
  9. await Promise.all(keys.map(async key => expect(await methods.contains(map, key)).to.equal(true)));
  10. expect(await methods.length(map)).to.bignumber.equal(keys.length.toString());
  11. expect((await Promise.all(keys.map(key => methods.get(map, key)))).map(k => k.toString())).to.have.same.members(
  12. values.map(value => value.toString()),
  13. );
  14. // To compare key-value pairs, we zip keys and values, and convert BNs to
  15. // strings to workaround Chai limitations when dealing with nested arrays
  16. expect(
  17. await Promise.all(
  18. [...Array(keys.length).keys()].map(async index => {
  19. const entry = await methods.at(map, index);
  20. return [entry[0].toString(), entry[1].toString()];
  21. }),
  22. ),
  23. ).to.have.same.deep.members(
  24. zip(
  25. keys.map(k => k.toString()),
  26. values.map(v => v.toString()),
  27. ),
  28. );
  29. // This also checks that both arrays have the same length
  30. expect((await methods.keys(map)).map(k => k.toString())).to.have.same.members(keys.map(key => key.toString()));
  31. }
  32. it('starts empty', async function () {
  33. expect(await methods.contains(this.map, keyA)).to.equal(false);
  34. await expectMembersMatch(this.map, [], []);
  35. });
  36. describe('set', function () {
  37. it('adds a key', async function () {
  38. const receipt = await methods.set(this.map, keyA, valueA);
  39. expectEvent(receipt, events.setReturn, { ret0: true });
  40. await expectMembersMatch(this.map, [keyA], [valueA]);
  41. });
  42. it('adds several keys', async function () {
  43. await methods.set(this.map, keyA, valueA);
  44. await methods.set(this.map, keyB, valueB);
  45. await expectMembersMatch(this.map, [keyA, keyB], [valueA, valueB]);
  46. expect(await methods.contains(this.map, keyC)).to.equal(false);
  47. });
  48. it('returns false when adding keys already in the set', async function () {
  49. await methods.set(this.map, keyA, valueA);
  50. const receipt = await methods.set(this.map, keyA, valueA);
  51. expectEvent(receipt, events.setReturn, { ret0: false });
  52. await expectMembersMatch(this.map, [keyA], [valueA]);
  53. });
  54. it('updates values for keys already in the set', async function () {
  55. await methods.set(this.map, keyA, valueA);
  56. await methods.set(this.map, keyA, valueB);
  57. await expectMembersMatch(this.map, [keyA], [valueB]);
  58. });
  59. });
  60. describe('remove', function () {
  61. it('removes added keys', async function () {
  62. await methods.set(this.map, keyA, valueA);
  63. const receipt = await methods.remove(this.map, keyA);
  64. expectEvent(receipt, events.removeReturn, { ret0: true });
  65. expect(await methods.contains(this.map, keyA)).to.equal(false);
  66. await expectMembersMatch(this.map, [], []);
  67. });
  68. it('returns false when removing keys not in the set', async function () {
  69. const receipt = await methods.remove(this.map, keyA);
  70. expectEvent(receipt, events.removeReturn, { ret0: false });
  71. expect(await methods.contains(this.map, keyA)).to.equal(false);
  72. });
  73. it('adds and removes multiple keys', async function () {
  74. // []
  75. await methods.set(this.map, keyA, valueA);
  76. await methods.set(this.map, keyC, valueC);
  77. // [A, C]
  78. await methods.remove(this.map, keyA);
  79. await methods.remove(this.map, keyB);
  80. // [C]
  81. await methods.set(this.map, keyB, valueB);
  82. // [C, B]
  83. await methods.set(this.map, keyA, valueA);
  84. await methods.remove(this.map, keyC);
  85. // [A, B]
  86. await methods.set(this.map, keyA, valueA);
  87. await methods.set(this.map, keyB, valueB);
  88. // [A, B]
  89. await methods.set(this.map, keyC, valueC);
  90. await methods.remove(this.map, keyA);
  91. // [B, C]
  92. await methods.set(this.map, keyA, valueA);
  93. await methods.remove(this.map, keyB);
  94. // [A, C]
  95. await expectMembersMatch(this.map, [keyA, keyC], [valueA, valueC]);
  96. expect(await methods.contains(this.map, keyA)).to.equal(true);
  97. expect(await methods.contains(this.map, keyB)).to.equal(false);
  98. expect(await methods.contains(this.map, keyC)).to.equal(true);
  99. });
  100. });
  101. describe('read', function () {
  102. beforeEach(async function () {
  103. await methods.set(this.map, keyA, valueA);
  104. });
  105. describe('get', function () {
  106. it('existing value', async function () {
  107. expect(await methods.get(this.map, keyA).then(r => r.toString())).to.be.equal(valueA.toString());
  108. });
  109. it('missing value', async function () {
  110. await expectRevert(methods.get(this.map, keyB), 'EnumerableMap: nonexistent key');
  111. });
  112. });
  113. describe('tryGet', function () {
  114. it('existing value', async function () {
  115. const result = await methods.tryGet(this.map, keyA);
  116. expect(result['0']).to.be.equal(true);
  117. expect(result['1'].toString()).to.be.equal(valueA.toString());
  118. });
  119. it('missing value', async function () {
  120. const result = await methods.tryGet(this.map, keyB);
  121. expect(result['0']).to.be.equal(false);
  122. expect(result['1'].toString()).to.be.equal(zeroValue.toString());
  123. });
  124. });
  125. });
  126. }
  127. module.exports = {
  128. shouldBehaveLikeMap,
  129. };