EnumerableSet.behavior.js 3.54 KB
Newer Older
vicotor's avatar
vicotor committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');

function shouldBehaveLikeSet (valueA, valueB, valueC) {
  async function expectMembersMatch (set, values) {
    const contains = await Promise.all(values.map(value => set.contains(value)));
    expect(contains.every(Boolean)).to.be.equal(true);

    const length = await set.length();
    expect(length).to.bignumber.equal(values.length.toString());

    // To compare values we convert to strings to workaround Chai
    // limitations when dealing with nested arrays (required for BNs)
    const indexedValues = await Promise.all(Array(values.length).fill().map((_, index) => set.at(index)));
    expect(
      indexedValues.map(v => v.toString()),
    ).to.have.same.members(
      values.map(v => v.toString()),
    );

    const returnedValues = await set.values();
    expect(
      returnedValues.map(v => v.toString()),
    ).to.have.same.members(
      values.map(v => v.toString()),
    );
  }

  it('starts empty', async function () {
    expect(await this.set.contains(valueA)).to.equal(false);

    await expectMembersMatch(this.set, []);
  });

  describe('add', function () {
    it('adds a value', async function () {
      const receipt = await this.set.add(valueA);
      expectEvent(receipt, 'OperationResult', { result: true });

      await expectMembersMatch(this.set, [valueA]);
    });

    it('adds several values', async function () {
      await this.set.add(valueA);
      await this.set.add(valueB);

      await expectMembersMatch(this.set, [valueA, valueB]);
      expect(await this.set.contains(valueC)).to.equal(false);
    });

    it('returns false when adding values already in the set', async function () {
      await this.set.add(valueA);

      const receipt = (await this.set.add(valueA));
      expectEvent(receipt, 'OperationResult', { result: false });

      await expectMembersMatch(this.set, [valueA]);
    });
  });

  describe('at', function () {
    it('reverts when retrieving non-existent elements', async function () {
      await expectRevert.unspecified(this.set.at(0));
    });
  });

  describe('remove', function () {
    it('removes added values', async function () {
      await this.set.add(valueA);

      const receipt = await this.set.remove(valueA);
      expectEvent(receipt, 'OperationResult', { result: true });

      expect(await this.set.contains(valueA)).to.equal(false);
      await expectMembersMatch(this.set, []);
    });

    it('returns false when removing values not in the set', async function () {
      const receipt = await this.set.remove(valueA);
      expectEvent(receipt, 'OperationResult', { result: false });

      expect(await this.set.contains(valueA)).to.equal(false);
    });

    it('adds and removes multiple values', async function () {
      // []

      await this.set.add(valueA);
      await this.set.add(valueC);

      // [A, C]

      await this.set.remove(valueA);
      await this.set.remove(valueB);

      // [C]

      await this.set.add(valueB);

      // [C, B]

      await this.set.add(valueA);
      await this.set.remove(valueC);

      // [A, B]

      await this.set.add(valueA);
      await this.set.add(valueB);

      // [A, B]

      await this.set.add(valueC);
      await this.set.remove(valueA);

      // [B, C]

      await this.set.add(valueA);
      await this.set.remove(valueB);

      // [A, C]

      await expectMembersMatch(this.set, [valueA, valueC]);

      expect(await this.set.contains(valueB)).to.equal(false);
    });
  });
}

module.exports = {
  shouldBehaveLikeSet,
};