/*
* Copyright 2015 Goldman Sachs.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.gs.collections.impl.set.mutable;
import java.util.HashSet;
import java.util.Iterator;
import com.gs.collections.api.LazyIterable;
import com.gs.collections.api.block.HashingStrategy;
import com.gs.collections.api.block.procedure.Procedure;
import com.gs.collections.api.list.ImmutableList;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.api.set.ImmutableSet;
import com.gs.collections.api.set.MutableSet;
import com.gs.collections.api.set.Pool;
import com.gs.collections.impl.block.factory.Comparators;
import com.gs.collections.impl.block.factory.HashingStrategies;
import com.gs.collections.impl.block.factory.IntegerPredicates;
import com.gs.collections.impl.block.factory.Predicates;
import com.gs.collections.impl.block.factory.Procedures;
import com.gs.collections.impl.factory.Lists;
import com.gs.collections.impl.factory.Sets;
import com.gs.collections.impl.list.Interval;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.math.IntegerSum;
import com.gs.collections.impl.math.Sum;
import com.gs.collections.impl.math.SumProcedure;
import com.gs.collections.impl.set.strategy.mutable.UnifiedSetWithHashingStrategy;
import com.gs.collections.impl.test.Verify;
import com.gs.collections.impl.test.domain.Key;
import com.gs.collections.impl.test.domain.Person;
import com.gs.collections.impl.utility.ArrayIterate;
import org.junit.Assert;
import org.junit.Test;
/**
* JUnit test suite for {@link UnifiedSetWithHashingStrategy}.
*/
public class UnifiedSetWithHashingStrategyTest extends AbstractUnifiedSetTestCase
{
//Not using the static factory method in order to have concrete types for test cases
private static final HashingStrategy<Integer> INTEGER_HASHING_STRATEGY = HashingStrategies.nullSafeHashingStrategy(new HashingStrategy<Integer>()
{
public int computeHashCode(Integer object)
{
return object.hashCode();
}
public boolean equals(Integer object1, Integer object2)
{
return object1.equals(object2);
}
});
private static final HashingStrategy<String> STRING_HASHING_STRATEGY = HashingStrategies.nullSafeHashingStrategy(new HashingStrategy<String>()
{
public int computeHashCode(String object)
{
return object.hashCode();
}
public boolean equals(String object1, String object2)
{
return object1.equals(object2);
}
});
private static final HashingStrategy<Person> FIRST_NAME_HASHING_STRATEGY = HashingStrategies.fromFunction(Person.TO_FIRST);
private static final HashingStrategy<Person> LAST_NAME_HASHING_STRATEGY = HashingStrategies.fromFunction(Person.TO_LAST);
private static final Person JOHNSMITH = new Person("John", "Smith");
private static final Person JANESMITH = new Person("Jane", "Smith");
private static final Person JOHNDOE = new Person("John", "Doe");
private static final Person JANEDOE = new Person("Jane", "Doe");
private static final ImmutableList<Person> PEOPLE = Lists.immutable.of(JOHNSMITH, JANESMITH, JOHNDOE, JANEDOE);
private static final ImmutableSet<Person> LAST_NAME_HASHED_SET = Sets.immutable.of(JOHNSMITH, JOHNDOE);
@Override
protected <T> MutableSet<T> newWith(T... littleElements)
{
return UnifiedSetWithHashingStrategy.newSetWith(HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<T>defaultStrategy()), littleElements);
}
@Test
public void newSet_throws()
{
Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedSetWithHashingStrategy<Integer>(INTEGER_HASHING_STRATEGY, -1, 0.5f));
Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedSetWithHashingStrategy<Integer>(INTEGER_HASHING_STRATEGY, 1, -0.5f));
Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedSetWithHashingStrategy<Integer>(INTEGER_HASHING_STRATEGY, 1, 1.5f));
}
@Override
@Test
public void tap()
{
super.tap();
MutableList<Person> tapResult = Lists.mutable.of();
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).withAll(PEOPLE.castToList());
Assert.assertSame(people, people.tap(tapResult::add));
Assert.assertEquals(people.toList(), tapResult);
}
@Override
@Test
public void select()
{
super.select();
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).withAll(PEOPLE.castToList());
Verify.assertSetsEqual(LAST_NAME_HASHED_SET.castToSet(), people);
Verify.assertSetsEqual(UnifiedSet.newSetWith(JOHNSMITH), people.select(each -> "Smith".equals(each.getLastName())).with(JANESMITH));
}
@Override
@Test
public void reject()
{
super.reject();
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).withAll(PEOPLE.castToList());
Verify.assertSetsEqual(UnifiedSet.newSetWith(JOHNSMITH), people.reject(each -> "Doe".equals(each.getLastName())).with(JANESMITH));
}
/**
* @deprecated since 3.0.
*/
@Deprecated
@Test
public void lazyCollectForEach()
{
UnifiedSetWithHashingStrategy<Integer> integers =
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, 1, 2, 3, 4, 5);
LazyIterable<String> select = integers.lazyCollect(String::valueOf);
Procedure<String> builder = Procedures.append(new StringBuilder());
select.forEach(builder);
String result = builder.toString();
Verify.assertContains("1", result);
Verify.assertContains("2", result);
Verify.assertContains("3", result);
Verify.assertContains("4", result);
Verify.assertContains("5", result);
}
/**
* @deprecated since 3.0.
*/
@Deprecated
@Test
public void lazyRejectForEach()
{
UnifiedSetWithHashingStrategy<Integer> integers =
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, 1, 2, 3, 4, 5);
LazyIterable<Integer> select = integers.lazyReject(Predicates.lessThan(5));
Sum sum = new IntegerSum(0);
select.forEach(new SumProcedure<>(sum));
Assert.assertEquals(5L, sum.getValue().intValue());
}
/**
* @deprecated since 3.0.
*/
@Deprecated
@Test
public void lazySelectForEach()
{
UnifiedSetWithHashingStrategy<Integer> integers =
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, 1, 2, 3, 4, 5);
LazyIterable<Integer> select = integers.lazySelect(Predicates.lessThan(5));
Sum sum = new IntegerSum(0);
select.forEach(new SumProcedure<>(sum));
Assert.assertEquals(10, sum.getValue().intValue());
}
@Override
@Test
public void with()
{
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(STRING_HASHING_STRATEGY, "1"),
UnifiedSetWithHashingStrategy.newSet(STRING_HASHING_STRATEGY).with("1"));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(STRING_HASHING_STRATEGY, "1", "2"),
UnifiedSetWithHashingStrategy.newSet(STRING_HASHING_STRATEGY).with("1", "2"));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(STRING_HASHING_STRATEGY, "1", "2", "3"),
UnifiedSetWithHashingStrategy.newSet(STRING_HASHING_STRATEGY).with("1", "2", "3"));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(STRING_HASHING_STRATEGY, "1", "2", "3", "4"),
UnifiedSetWithHashingStrategy.newSet(STRING_HASHING_STRATEGY).with("1", "2", "3", "4"));
MutableSet<String> list = UnifiedSetWithHashingStrategy.newSet(STRING_HASHING_STRATEGY).with("A")
.withAll(Lists.fixedSize.of("1", "2"))
.withAll(Lists.fixedSize.<String>of())
.withAll(Sets.fixedSize.of("3", "4"));
Verify.assertEqualsAndHashCode(UnifiedSetWithHashingStrategy.newSetWith(
STRING_HASHING_STRATEGY, "A", "1", "2", "3", "4"), list);
}
@Test
public void newSetWithIterable()
{
//testing collection
MutableSet<Integer> integers = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, Interval.oneTo(3));
Assert.assertEquals(UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, 1, 2, 3), integers);
//testing iterable
UnifiedSetWithHashingStrategy<Integer> set1 = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, FastList.newListWith(1, 2, 3).asLazy());
Assert.assertEquals(UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, 1, 2, 3), set1);
//testing null
Verify.assertThrows(NullPointerException.class, () -> UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, null));
}
@Override
@Test
public void add()
{
super.add();
// force rehashing at each step of adding a new colliding entry
for (int i = 0; i < COLLISIONS.size(); i++)
{
UnifiedSetWithHashingStrategy<Integer> unifiedSet = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, i, 0.75f).withAll(COLLISIONS.subList(0, i));
if (i == 2)
{
unifiedSet.add(Integer.valueOf(1));
}
if (i == 4)
{
unifiedSet.add(Integer.valueOf(1));
unifiedSet.add(Integer.valueOf(2));
}
Integer value = COLLISIONS.get(i);
Assert.assertTrue(unifiedSet.add(value));
}
// Rehashing Case A: a bucket with only one entry and a low capacity forcing a rehash, where the trigging element goes in the bucket
// set up a chained bucket
UnifiedSetWithHashingStrategy<Integer> caseA = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 2).with(COLLISION_1, COLLISION_2);
// clear the bucket to one element
caseA.remove(COLLISION_2);
// increase the occupied count to the threshold
caseA.add(Integer.valueOf(1));
caseA.add(Integer.valueOf(2));
// add the colliding value back and force the rehash
Assert.assertTrue(caseA.add(COLLISION_2));
// Rehashing Case B: a bucket with only one entry and a low capacity forcing a rehash, where the triggering element is not in the chain
// set up a chained bucket
UnifiedSetWithHashingStrategy<Integer> caseB = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 2).with(COLLISION_1, COLLISION_2);
// clear the bucket to one element
caseB.remove(COLLISION_2);
// increase the occupied count to the threshold
caseB.add(Integer.valueOf(1));
caseB.add(Integer.valueOf(2));
// add a new value and force the rehash
Assert.assertTrue(caseB.add(3));
}
@Test
public void add_with_hashingStrategy()
{
HashingStrategy<Integer> hashingStrategy = HashingStrategies.nullSafeHashingStrategy(new HashingStrategy<Integer>()
{
public int computeHashCode(Integer object)
{
return object % 1000;
}
public boolean equals(Integer object1, Integer object2)
{
return object1.equals(object2);
}
});
//Same as case A above except with a different hashing strategy
UnifiedSetWithHashingStrategy<Integer> caseA = UnifiedSetWithHashingStrategy.newSet(hashingStrategy, 2);
//Adding an element to a slot
Assert.assertTrue(caseA.add(COLLISION_1));
//Setting up a chained bucked by forcing a collision
Assert.assertTrue(caseA.add(COLLISION_1 + 1000));
//Increasing the occupied to the thresh hold
Assert.assertTrue(caseA.add(COLLISION_1 + 2000));
//Forcing a rehash where the element that forced the rehash goes in the chained bucket
Assert.assertTrue(caseA.add(null));
Verify.assertSetsEqual(UnifiedSet.newSetWith(COLLISION_1, COLLISION_1 + 1000, COLLISION_1 + 2000, null), caseA);
//Same as case B above except with a different hashing strategy
UnifiedSetWithHashingStrategy<Integer> caseB = UnifiedSetWithHashingStrategy.newSet(hashingStrategy, 2);
//Adding an element to a slot
Assert.assertTrue(caseB.add(null));
//Setting up a chained bucked by forcing a collision
Assert.assertTrue(caseB.add(1));
//Increasing the occupied to the threshold
Assert.assertTrue(caseB.add(2));
//Forcing a rehash where the element that forced the rehash does not go in the chained bucket
Assert.assertTrue(caseB.add(3));
Verify.assertSetsEqual(UnifiedSet.newSetWith(null, 1, 2, 3), caseB);
//Testing add throws NullPointerException if the hashingStrategy is not null safe
Verify.assertThrows(NullPointerException.class, () -> UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).add(null));
}
@Override
@Test
public void addAllIterable()
{
super.addAllIterable();
// test adding a fully populated chained bucket
MutableSet<Integer> expected = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5, COLLISION_6, COLLISION_7);
Assert.assertTrue(UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY).addAllIterable(expected));
// add an odd-sized collection to a set with a small max to ensure that its capacity is maintained after the operation.
UnifiedSetWithHashingStrategy<Integer> tiny = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 0);
Assert.assertTrue(tiny.addAllIterable(FastList.newListWith(COLLISION_1)));
//Testing copying set with 3rd slot in chained bucket == null
UnifiedSetWithHashingStrategy<Integer> integers = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4);
UnifiedSetWithHashingStrategy<Integer> set = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY);
integers.remove(COLLISION_4);
Assert.assertTrue(set.addAllIterable(integers));
Assert.assertEquals(UnifiedSet.newSetWith(COLLISION_1, COLLISION_2, COLLISION_3), set);
//Testing copying set with 2nd slot in chained bucket == null
integers.remove(COLLISION_3);
Assert.assertFalse(set.addAllIterable(integers));
//Testing copying set with the 1st slot in chained bucket == null
integers.remove(COLLISION_2);
Assert.assertFalse(set.addAllIterable(integers));
Assert.assertEquals(UnifiedSet.newSetWith(COLLISION_1, COLLISION_2, COLLISION_3), set);
}
@Test
public void addALLIterable_with_hashingStrategy()
{
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.nullSafeHashingStrategy(LAST_NAME_HASHING_STRATEGY), 2);
//Testing adding an iterable
Assert.assertTrue(people.addAllIterable(PEOPLE));
Verify.assertSetsEqual(UnifiedSet.newSet(LAST_NAME_HASHED_SET), people);
//Testing the set uses its own hashing strategy and not the target sets
Assert.assertFalse(people.addAllIterable(UnifiedSetWithHashingStrategy.newSet(FIRST_NAME_HASHING_STRATEGY, PEOPLE)));
Verify.assertSize(2, people);
//Testing adding with null where the call to addALLIterable forces a rehash
Person notInSet = new Person("Not", "InSet");
Assert.assertTrue(people.addAllIterable(UnifiedSet.newSetWith(notInSet, null)));
Verify.assertSetsEqual(UnifiedSet.newSet(LAST_NAME_HASHED_SET).with(notInSet, null), people);
//Testing addAllIterable throws NullPointerException if the hashingStrategy is not null safe
Verify.assertThrows(NullPointerException.class, () -> UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).addAllIterable(UnifiedSet.newSetWith((Person) null)));
}
@Test
public void get()
{
UnifiedSetWithHashingStrategy<Integer> set = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, SIZE).withAll(COLLISIONS);
set.removeAll(COLLISIONS);
for (Integer integer : COLLISIONS)
{
Assert.assertNull(set.get(integer));
Assert.assertNull(set.get(null));
set.add(integer);
//noinspection UnnecessaryBoxing,CachedNumberConstructorCall,BoxingBoxedValue
Assert.assertSame(integer, set.get(new Integer(integer)));
}
Assert.assertEquals(COLLISIONS.toSet(), set);
// the pool interface supports getting null keys
UnifiedSetWithHashingStrategy<Integer> chainedWithNull = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, null, COLLISION_1);
Verify.assertContains(null, chainedWithNull);
Assert.assertNull(chainedWithNull.get(null));
// getting a non-existent from a chain with one slot should short-circuit to return null
UnifiedSetWithHashingStrategy<Integer> chainedWithOneSlot = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2);
chainedWithOneSlot.remove(COLLISION_2);
Assert.assertNull(chainedWithOneSlot.get(COLLISION_2));
}
@Test
public void get_with_hashingStrategy()
{
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.nullSafeHashingStrategy(LAST_NAME_HASHING_STRATEGY), 2).withAll(PEOPLE.castToList());
//Putting null then testing geting a null
Verify.assertSize(3, people.with((Person) null));
Assert.assertNull(people.get(null));
//Testing it is getting the same reference
Assert.assertSame(JOHNSMITH, people.get(JANESMITH));
Assert.assertSame(JOHNSMITH, people.get(JOHNSMITH));
Assert.assertSame(JOHNDOE, people.get(JANEDOE));
Assert.assertSame(JOHNDOE, people.get(JOHNDOE));
Assert.assertSame(JOHNSMITH, people.get(new Person("Anything", "Smith")));
Assert.assertNull(people.get(new Person("John", "NotHere")));
//Testing get throws NullPointerException if the hashingStrategy is not null safe
Verify.assertThrows(NullPointerException.class, () -> UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).get(null));
}
@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 put_with_hashingStrategy()
{
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.nullSafeHashingStrategy(LAST_NAME_HASHING_STRATEGY), 2).withAll(PEOPLE.castToList());
//Testing if element already exists, returns the instance in the set
Assert.assertSame(JOHNSMITH, people.put(new Person("Anything", "Smith")));
Verify.assertSize(2, people);
//Testing if the element doesn't exist, returns the element itself
Person notInSet = new Person("Not", "inSet");
Assert.assertSame(notInSet, people.put(notInSet));
Verify.assertSize(3, people);
//Testing putting a null to force a rehash
Assert.assertNull(people.put(null));
Verify.assertSize(4, people);
//Testing put throws NullPointerException if the hashingStrategy is not null safe
Verify.assertThrows(NullPointerException.class, () -> UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY).put(null));
}
@Test
public void remove_with_hashingStrategy()
{
HashingStrategy<Integer> hashingStrategy = HashingStrategies.nullSafeHashingStrategy(new HashingStrategy<Integer>()
{
public int computeHashCode(Integer object)
{
return object % 1000;
}
public boolean equals(Integer object1, Integer object2)
{
return object1.equals(object2);
}
});
UnifiedSetWithHashingStrategy<Integer> integers = UnifiedSetWithHashingStrategy.newSet(
hashingStrategy, 2).with(COLLISION_1, COLLISION_1 + 1000, COLLISION_1 + 2000, null);
//Testing remove null from the end of the chain
Assert.assertTrue(integers.remove(null));
//Adding null back and creating a deep chain.
integers.with(null, COLLISION_1 + 3000, COLLISION_1 + 4000, COLLISION_1 + 5000);
//Removing null from the first position of a bucket in the deep chain
Assert.assertTrue(integers.remove(null));
Assert.assertFalse(integers.remove(null));
//Removing from the end of the deep chain
Assert.assertTrue(integers.remove(COLLISION_1 + 4000));
//Removing from the first spot of the chain
Assert.assertTrue(integers.remove(COLLISION_1));
Verify.assertSize(4, integers);
//Testing removing a non existent element from a non bucket slot
integers.add(2);
integers.add(4);
Assert.assertFalse(integers.remove(1002));
//Testing removeIf
Assert.assertTrue(integers.removeIf(IntegerPredicates.isEven()));
Verify.assertEmpty(integers);
}
@Test
public void removeFromPool()
{
Pool<Integer> unifiedSet = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 8).withAll(COLLISIONS);
COLLISIONS.reverseForEach(each -> {
Assert.assertNull(unifiedSet.removeFromPool(null));
Assert.assertSame(each, unifiedSet.removeFromPool(each));
Assert.assertNull(unifiedSet.removeFromPool(each));
Assert.assertNull(unifiedSet.removeFromPool(null));
Assert.assertNull(unifiedSet.removeFromPool(COLLISION_10));
});
Assert.assertEquals(UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY), unifiedSet);
COLLISIONS.forEach(Procedures.cast(each -> {
Pool<Integer> unifiedSet2 = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 8).withAll(COLLISIONS);
Assert.assertNull(unifiedSet2.removeFromPool(null));
Assert.assertSame(each, unifiedSet2.removeFromPool(each));
Assert.assertNull(unifiedSet2.removeFromPool(each));
Assert.assertNull(unifiedSet2.removeFromPool(null));
Assert.assertNull(unifiedSet2.removeFromPool(COLLISION_10));
}));
// search a chain for a non-existent element
Pool<Integer> chain = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4);
Assert.assertNull(chain.removeFromPool(COLLISION_5));
// search a deep chain for a non-existent element
Pool<Integer> deepChain = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5, COLLISION_6, COLLISION_7);
Assert.assertNull(deepChain.removeFromPool(COLLISION_8));
// search for a non-existent element
Pool<Integer> empty = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1);
Assert.assertNull(empty.removeFromPool(COLLISION_2));
}
@Test
public void removeFromPool_with_hashingStrategy()
{
HashingStrategy<Integer> hashingStrategy = HashingStrategies.nullSafeHashingStrategy(new HashingStrategy<Integer>()
{
public int computeHashCode(Integer object)
{
return object % 1000;
}
public boolean equals(Integer object1, Integer object2)
{
return object1.equals(object2);
}
});
UnifiedSetWithHashingStrategy<Integer> integers = UnifiedSetWithHashingStrategy.newSet(
hashingStrategy, 2).with(COLLISION_1, COLLISION_1 + 1000, COLLISION_1 + 2000, null);
//Testing remove null from the end of the chain
Assert.assertNull(integers.removeFromPool(null));
Integer collision4000 = COLLISION_1 + 4000;
//Adding null back and creating a deep chain.
integers.with(null, COLLISION_1 + 3000, collision4000, COLLISION_1 + 5000);
//Removing null from the first position of a bucket in the deep chain
Assert.assertNull(integers.removeFromPool(null));
Verify.assertSize(6, integers);
Assert.assertNull(integers.removeFromPool(null));
Verify.assertSize(6, integers);
//Removing from the end of the deep chain
Assert.assertSame(collision4000, integers.removeFromPool(COLLISION_1 + 4000));
//Removing from the first spot of the chain
Assert.assertSame(COLLISION_1, integers.removeFromPool(COLLISION_1));
Verify.assertSize(4, integers);
//Testing removing an element that is not in a chained bucket
Assert.assertSame(JOHNSMITH, UnifiedSetWithHashingStrategy.newSetWith(LAST_NAME_HASHING_STRATEGY, JOHNSMITH).removeFromPool(JOHNSMITH));
}
@Test
public void serialization()
{
int size = COLLISIONS.size();
for (int i = 1; i < size; i++)
{
MutableSet<Integer> set = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, SIZE).withAll(COLLISIONS.subList(0, i));
Verify.assertPostSerializedEqualsAndHashCode(set);
set.add(null);
Verify.assertPostSerializedEqualsAndHashCode(set);
}
UnifiedSetWithHashingStrategy<Integer> nullBucketZero = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, null, COLLISION_1, COLLISION_2);
Verify.assertPostSerializedEqualsAndHashCode(nullBucketZero);
UnifiedSetWithHashingStrategy<Integer> simpleSetWithNull = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, null, 1, 2);
Verify.assertPostSerializedEqualsAndHashCode(simpleSetWithNull);
UnifiedSetWithHashingStrategy<Person> people = UnifiedSetWithHashingStrategy.newSet(LAST_NAME_HASHING_STRATEGY, PEOPLE);
Verify.assertPostSerializedEqualsAndHashCode(people);
//Testing the hashingStrategy is serialized correctly by making sure it is still hashing by last name
Verify.assertSetsEqual(LAST_NAME_HASHED_SET.castToSet(), people.withAll(PEOPLE.castToList()));
}
@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);
});
}
@Override
@Test
public void equalsAndHashCode()
{
super.equalsAndHashCode();
UnifiedSetWithHashingStrategy<Integer> singleCollisionBucket = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2);
singleCollisionBucket.remove(COLLISION_2);
Assert.assertEquals(singleCollisionBucket, UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, null, COLLISION_1, COLLISION_2, COLLISION_3),
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, null, COLLISION_1, COLLISION_2, COLLISION_3));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, null, COLLISION_2, COLLISION_3),
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, null, COLLISION_2, COLLISION_3));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, null, COLLISION_3),
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, null, COLLISION_3));
Verify.assertEqualsAndHashCode(
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, null),
UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, null));
}
@Test
public void equals_with_hashingStrategy()
{
HashingStrategy<Person> personHashingStrategy = HashingStrategies.fromFunction(Person.TO_LAST);
HashingStrategy<Person> personHashingStrategyCopy = HashingStrategies.fromFunction(Person.TO_LAST);
UnifiedSetWithHashingStrategy<Person> setA = UnifiedSetWithHashingStrategy.newSet(personHashingStrategy, PEOPLE);
UnifiedSetWithHashingStrategy<Person> setB = UnifiedSetWithHashingStrategy.newSet(personHashingStrategyCopy, PEOPLE);
//Test sets with different instances of the same hashing strategy are equal symmetrically
Verify.assertEqualsAndHashCode(setA, setB);
//Checking that a hashing set is symmetrically equal to an identical JDK set
HashSet<Person> hashSet = new HashSet<>(setA);
Assert.assertTrue(hashSet.equals(setA) && setA.equals(hashSet));
//Checking that a hash set is symmetrically equal to an identical GS Collections set
UnifiedSet<Person> unifiedSet = UnifiedSet.newSet(setA);
Assert.assertTrue(unifiedSet.equals(setA) && setA.equals(unifiedSet));
//Testing the asymmetry of equals
HashingStrategy<String> firstLetterHashingStrategy = new HashingStrategy<String>()
{
public int computeHashCode(String object)
{
return Character.valueOf(object.charAt(0));
}
public boolean equals(String object1, String object2)
{
return object1.charAt(0) == object2.charAt(0);
}
};
UnifiedSetWithHashingStrategy<String> hashedString = UnifiedSetWithHashingStrategy.newSetWith(firstLetterHashingStrategy, "apple", "banana", "cheese");
UnifiedSetWithHashingStrategy<String> anotherHashedString =
UnifiedSetWithHashingStrategy.newSetWith(firstLetterHashingStrategy, "a", "b", "c");
UnifiedSet<String> normalString = UnifiedSet.newSetWith("alpha", "bravo", "charlie");
//Testing hashedString equals normalString
Assert.assertTrue(hashedString.equals(normalString) && hashedString.equals(hashedString));
//Testing normalString does not equal a hashedString, note cannot use Assert.notEquals because it assumes symmetric equals behavior
Assert.assertFalse(normalString.equals(hashedString) && hashedString.equals(normalString));
//Testing 2 sets with same hashing strategies must obey object equals definition
Verify.assertEqualsAndHashCode(hashedString, anotherHashedString);
//Testing set size matters
Assert.assertNotEquals(hashedString, normalString.remove("alpha"));
}
@Test
public void constructor_from_UnifiedSet()
{
Verify.assertEqualsAndHashCode(new HashSet<>(MORE_COLLISIONS),
UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY,
MORE_COLLISIONS));
}
@Test
public void copyConstructor()
{
// test copying a chained bucket
UnifiedSetWithHashingStrategy<Integer> set = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5, COLLISION_6, COLLISION_7);
Verify.assertEqualsAndHashCode(set, UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, set));
}
@Test(expected = NullPointerException.class)
public void newSet_null()
{
UnifiedSetWithHashingStrategy.newSet((UnifiedSetWithHashingStrategy<Object>) null);
}
@Test(expected = IllegalArgumentException.class)
public void newSet_null_hashingStrategy()
{
UnifiedSetWithHashingStrategy.newSet((HashingStrategy<Object>) null);
}
@Test
public void batchForEach()
{
//Testing batch size of 1 to 16 with no chains
UnifiedSet<Integer> set = UnifiedSet.<Integer>newSet(10).with(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
for (int sectionCount = 1; sectionCount <= 16; ++sectionCount)
{
Sum sum = new IntegerSum(0);
for (int sectionIndex = 0; sectionIndex < sectionCount; ++sectionIndex)
{
set.batchForEach(new SumProcedure<>(sum), sectionIndex, sectionCount);
}
Assert.assertEquals(55, sum.getValue());
}
//Testing 1 batch with chains
Sum sum2 = new IntegerSum(0);
UnifiedSetWithHashingStrategy<Integer> set2 = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 3).with(COLLISION_1, COLLISION_2, COLLISION_3, 1, 2);
int numBatches = set2.getBatchCount(100);
for (int i = 0; i < numBatches; ++i)
{
set2.batchForEach(new SumProcedure<>(sum2), i, numBatches);
}
Assert.assertEquals(1, numBatches);
Assert.assertEquals(54, sum2.getValue());
//Testing batch size of 3 with chains and uneven last batch
Sum sum3 = new IntegerSum(0);
UnifiedSetWithHashingStrategy<Integer> set3 = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, 4, 1.0F).with(COLLISION_1, COLLISION_2, 1, 2, 3, 4, 5);
int numBatches2 = set3.getBatchCount(3);
for (int i = 0; i < numBatches2; ++i)
{
set3.batchForEach(new SumProcedure<>(sum3), i, numBatches2);
}
Assert.assertEquals(32, sum3.getValue());
//Test batchForEach on empty set, it should simply do nothing and not throw any exceptions
Sum sum4 = new IntegerSum(0);
UnifiedSetWithHashingStrategy<Integer> set4 = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY);
set4.batchForEach(new SumProcedure<>(sum4), 0, set4.getBatchCount(1));
Assert.assertEquals(0, sum4.getValue());
}
@Override
@Test
public void toArray()
{
super.toArray();
int size = COLLISIONS.size();
for (int i = 1; i < size; i++)
{
MutableSet<Integer> set = UnifiedSetWithHashingStrategy.newSet(
INTEGER_HASHING_STRATEGY, SIZE).withAll(COLLISIONS.subList(0, i));
Object[] objects = set.toArray();
Assert.assertEquals(set, UnifiedSet.newSetWith(objects));
}
MutableSet<Integer> deepChain = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5, COLLISION_6);
Assert.assertArrayEquals(new Integer[]{COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5, COLLISION_6}, deepChain.toArray());
MutableSet<Integer> minimumChain = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2);
minimumChain.remove(COLLISION_2);
Assert.assertArrayEquals(new Integer[]{COLLISION_1}, minimumChain.toArray());
MutableSet<Integer> set = UnifiedSetWithHashingStrategy.newSetWith(
INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4);
Integer[] target = {Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(1)};
Integer[] actual = set.toArray(target);
ArrayIterate.sort(actual, actual.length, Comparators.safeNullsHigh(Integer::compareTo));
Assert.assertArrayEquals(new Integer[]{COLLISION_1, 1, COLLISION_2, COLLISION_3, COLLISION_4, null}, actual);
}
@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);
}
@Test
public void setKeyPreservation()
{
Key key = new Key("key");
Key duplicateKey1 = new Key("key");
MutableSet<Key> set1 = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.<Key>defaultStrategy()).with(key, duplicateKey1);
Verify.assertSize(1, set1);
Verify.assertContains(key, set1);
Assert.assertSame(key, set1.getFirst());
Key duplicateKey2 = new Key("key");
MutableSet<Key> set2 = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.<Key>defaultStrategy()).with(key, duplicateKey1, duplicateKey2);
Verify.assertSize(1, set2);
Verify.assertContains(key, set2);
Assert.assertSame(key, set2.getFirst());
Key duplicateKey3 = new Key("key");
MutableSet<Key> set3 = UnifiedSetWithHashingStrategy.newSet(
HashingStrategies.<Key>defaultStrategy()).with(key, new Key("not a dupe"), duplicateKey3);
Verify.assertSize(2, set3);
Verify.assertContainsAll(set3, key, new Key("not a dupe"));
Assert.assertSame(key, set3.detect(key::equals));
}
@Test
public void withSameIfNotModified()
{
UnifiedSetWithHashingStrategy<Integer> integers = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY);
Assert.assertEquals(UnifiedSet.newSetWith(1, 2), integers.with(1, 2));
Assert.assertEquals(UnifiedSet.newSetWith(1, 2, 3, 4), integers.with(2, 3, 4));
Assert.assertSame(integers, integers.with(5, 6, 7));
}
@Override
@Test
public void retainAll()
{
super.retainAll();
MutableSet<Object> setWithNull = this.newWith((Object) null);
Assert.assertFalse(setWithNull.retainAll(FastList.newListWith((Object) null)));
Assert.assertEquals(UnifiedSet.newSetWith((Object) null), setWithNull);
}
@Override
public void getFirst()
{
super.getFirst();
int size = MORE_COLLISIONS.size();
for (int i = 1; i <= size - 1; i++)
{
MutableSet<Integer> unifiedSet = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 1).withAll(MORE_COLLISIONS.subList(0, i));
Assert.assertSame(MORE_COLLISIONS.get(0), unifiedSet.getFirst());
}
}
@Override
public void getLast()
{
super.getLast();
int size = MORE_COLLISIONS.size();
for (int i = 1; i <= size - 1; i++)
{
MutableSet<Integer> unifiedSet = UnifiedSetWithHashingStrategy.newSet(INTEGER_HASHING_STRATEGY, 1).withAll(MORE_COLLISIONS.subList(0, i));
Assert.assertSame(MORE_COLLISIONS.get(i - 1), unifiedSet.getLast());
}
MutableSet<Integer> chainedWithOneSlot = UnifiedSetWithHashingStrategy.newSetWith(INTEGER_HASHING_STRATEGY, COLLISION_1, COLLISION_2);
chainedWithOneSlot.remove(COLLISION_2);
Assert.assertSame(COLLISION_1, chainedWithOneSlot.getLast());
}
}