@Test
  public void put() {
    int size = MORE_COLLISIONS.size();
    for (int i = 1; i <= size; i++) {
      Pool<Integer> unifiedSet =
          UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 1)
              .withAll(MORE_COLLISIONS.subList(0, i - 1));
      Integer newValue = MORE_COLLISIONS.get(i - 1);

      Assert.assertSame(newValue, unifiedSet.put(newValue));
      //noinspection UnnecessaryBoxing,CachedNumberConstructorCall,BoxingBoxedValue
      Assert.assertSame(newValue, unifiedSet.put(new Integer(newValue)));
    }

    // assert that all redundant puts into a each position of chain bucket return the original
    // element added
    Pool<Integer> set =
        UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 4)
            .with(COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4);
    for (int i = 0; i < set.size(); i++) {
      Integer value = COLLISIONS.get(i);
      Assert.assertSame(value, set.put(value));
    }

    // force rehashing at each step of putting a new colliding entry
    for (int i = 0; i < COLLISIONS.size(); i++) {
      Pool<Integer> pool =
          UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, i)
              .withAll(COLLISIONS.subList(0, i));
      if (i == 2) {
        pool.put(Integer.valueOf(1));
      }
      if (i == 4) {
        pool.put(Integer.valueOf(1));
        pool.put(Integer.valueOf(2));
      }
      Integer value = COLLISIONS.get(i);
      Assert.assertSame(value, pool.put(value));
    }

    // cover one case not covered in the above: a bucket with only one entry and a low capacity
    // forcing a rehash
    // set up a chained bucket
    Pool<Integer> pool =
        UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 2)
            .with(COLLISION_1, COLLISION_2);
    // clear the bucket to one element
    pool.removeFromPool(COLLISION_2);
    // increase the occupied count to the threshold
    pool.put(Integer.valueOf(1));
    pool.put(Integer.valueOf(2));

    // put the colliding value back and force the rehash
    Assert.assertSame(COLLISION_2, pool.put(COLLISION_2));

    // put chained items into a pool without causing a rehash
    Pool<Integer> olympicPool = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY);
    Assert.assertSame(COLLISION_1, olympicPool.put(COLLISION_1));
    Assert.assertSame(COLLISION_2, olympicPool.put(COLLISION_2));
  }
  @Test
  public void null_behavior() {
    UnifiedSetWithHashingStrategy<Integer> unifiedSet =
        UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 8).withAll(MORE_COLLISIONS);
    MORE_COLLISIONS
        .clone()
        .reverseForEach(
            each -> {
              Assert.assertTrue(unifiedSet.add(null));
              Assert.assertFalse(unifiedSet.add(null));
              Verify.assertContains(null, unifiedSet);
              Verify.assertPostSerializedEqualsAndHashCode(unifiedSet);

              Assert.assertTrue(unifiedSet.remove(null));
              Assert.assertFalse(unifiedSet.remove(null));
              Verify.assertNotContains(null, unifiedSet);

              Verify.assertPostSerializedEqualsAndHashCode(unifiedSet);

              Assert.assertNull(unifiedSet.put(null));
              Assert.assertNull(unifiedSet.put(null));
              Assert.assertNull(unifiedSet.removeFromPool(null));
              Assert.assertNull(unifiedSet.removeFromPool(null));

              Verify.assertContains(each, unifiedSet);
              Assert.assertTrue(unifiedSet.remove(each));
              Assert.assertFalse(unifiedSet.remove(each));
              Verify.assertNotContains(each, unifiedSet);
            });
  }
  @Test
  public void iterator_remove() {
    int size = MORE_COLLISIONS.size();
    for (int i = 0; i < size; i++) {
      MutableSet<Integer> actual =
          UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, SIZE)
              .withAll(MORE_COLLISIONS);
      Iterator<Integer> iterator = actual.iterator();
      for (int j = 0; j <= i; j++) {
        Assert.assertTrue(iterator.hasNext());
        iterator.next();
      }
      iterator.remove();

      MutableSet<Integer> expected =
          UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, MORE_COLLISIONS);
      expected.remove(MORE_COLLISIONS.get(i));
      Assert.assertEquals(expected, actual);
    }

    // remove the last element from within a 2-level long chain that is fully populated
    MutableSet<Integer> set =
        UnifiedSetWithHashingStrategy.newSetWith(
            INTEGER_HASHING_STRATEGY,
            COLLISION_1,
            COLLISION_2,
            COLLISION_3,
            COLLISION_4,
            COLLISION_5,
            COLLISION_6,
            COLLISION_7);
    Iterator<Integer> iterator1 = set.iterator();
    for (int i = 0; i < 7; i++) {
      iterator1.next();
    }
    iterator1.remove();
    Assert.assertEquals(
        UnifiedSetWithHashingStrategy.newSetWith(
            INTEGER_HASHING_STRATEGY,
            COLLISION_1,
            COLLISION_2,
            COLLISION_3,
            COLLISION_4,
            COLLISION_5,
            COLLISION_6),
        set);

    // remove the second-to-last element from a 2-level long chain that that has one empty slot
    Iterator<Integer> iterator2 = set.iterator();
    for (int i = 0; i < 6; i++) {
      iterator2.next();
    }
    iterator2.remove();
    Assert.assertEquals(
        UnifiedSetWithHashingStrategy.newSetWith(
            INTEGER_HASHING_STRATEGY,
            COLLISION_1,
            COLLISION_2,
            COLLISION_3,
            COLLISION_4,
            COLLISION_5),
        set);

    // Testing removing the last element in a fully populated chained bucket
    UnifiedSetWithHashingStrategy<Integer> set2 =
        UnifiedSetWithHashingStrategy.newSetWith(
            INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4);
    Iterator<Integer> iterator3 = set2.iterator();
    for (int i = 0; i < 3; ++i) {
      iterator3.next();
    }
    iterator3.next();
    iterator3.remove();
    Verify.assertSetsEqual(UnifiedSet.newSetWith(COLLISION_1, COLLISION_2, COLLISION_3), set2);
  }