/* * 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.map.strategy.mutable; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.gs.collections.api.block.HashingStrategy; import com.gs.collections.api.block.function.Function2; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.tuple.Pair; import com.gs.collections.impl.block.factory.Functions; import com.gs.collections.impl.block.factory.HashingStrategies; import com.gs.collections.impl.block.factory.Procedures; import com.gs.collections.impl.block.function.PassThruFunction0; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.map.mutable.UnifiedMap; import com.gs.collections.impl.map.mutable.UnifiedMapTestCase; 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.parallel.BatchIterable; import com.gs.collections.impl.set.mutable.UnifiedSet; import com.gs.collections.impl.test.Verify; import com.gs.collections.impl.test.domain.Person; import com.gs.collections.impl.tuple.ImmutableEntry; import com.gs.collections.impl.tuple.Tuples; import org.junit.Assert; import org.junit.Test; public class UnifiedMapWithHashingStrategyTest extends UnifiedMapTestCase { //Not using the static factor 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"); @Override public <K, V> MutableMap<K, V> newMap() { return UnifiedMapWithHashingStrategy.newMap( HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<K>defaultStrategy())); } @Override public <K, V> MutableMap<K, V> newMapWithKeyValue(K key, V value) { return UnifiedMapWithHashingStrategy.newWithKeysValues( HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<K>defaultStrategy()), key, value); } @Override public <K, V> MutableMap<K, V> newMapWithKeysValues(K key1, V value1, K key2, V value2) { return UnifiedMapWithHashingStrategy.newWithKeysValues( HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<K>defaultStrategy()), key1, value1, key2, value2); } @Override public <K, V> MutableMap<K, V> newMapWithKeysValues( K key1, V value1, K key2, V value2, K key3, V value3) { return UnifiedMapWithHashingStrategy.newWithKeysValues( HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<K>defaultStrategy()), key1, value1, key2, value2, key3, value3); } @Override public <K, V> MutableMap<K, V> newMapWithKeysValues( K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) { return UnifiedMapWithHashingStrategy.newWithKeysValues( HashingStrategies.nullSafeHashingStrategy(HashingStrategies.<K>defaultStrategy()), key1, value1, key2, value2, key3, value3, key4, value4); } @Test public void constructorOfPairs() { Assert.assertEquals( UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, 1, "one", 2, "two", 3, "three"), UnifiedMapWithHashingStrategy.newMapWith(INTEGER_HASHING_STRATEGY, Tuples.pair(1, "one"), Tuples.pair(2, "two"), Tuples.pair(3, "three"))); } @Test public void constructorOfIterableOfPairs() { Pair<Integer, String> pair1 = Tuples.pair(1, "One"); Pair<Integer, String> pair2 = Tuples.pair(2, "Two"); Pair<Integer, String> pair3 = Tuples.pair(3, "Three"); Pair<Integer, String> pair4 = Tuples.pair(4, "Four"); UnifiedMapWithHashingStrategy<Integer, String> expected = UnifiedMapWithHashingStrategy.newMapWith(INTEGER_HASHING_STRATEGY, pair1, pair2, pair3, pair4); UnifiedMapWithHashingStrategy<Integer, String> actual1 = UnifiedMapWithHashingStrategy.newMapWith(INTEGER_HASHING_STRATEGY, FastList.<Pair<Integer, String>>newListWith(pair1, pair2, pair3, pair4)); Assert.assertEquals(expected, actual1); Assert.assertEquals(expected.hashingStrategy(), actual1.hashingStrategy()); UnifiedMapWithHashingStrategy<Integer, String> actual2 = UnifiedMapWithHashingStrategy.newMapWith(INTEGER_HASHING_STRATEGY, UnifiedSet.<Pair<Integer, String>>newSetWith(pair1, pair2, pair3, pair4)); Assert.assertEquals(expected, actual2); Assert.assertEquals(expected.hashingStrategy(), actual2.hashingStrategy()); } @Test public void newMap_throws() { Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedMapWithHashingStrategy<Integer, Integer>(INTEGER_HASHING_STRATEGY, -1, 0.5f)); Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedMapWithHashingStrategy<Integer, Integer>(INTEGER_HASHING_STRATEGY, 1, -0.5f)); Verify.assertThrows(IllegalArgumentException.class, () -> new UnifiedMapWithHashingStrategy<Integer, Integer>(INTEGER_HASHING_STRATEGY, 1, 1.5f)); } @Override @Test public void selectMap() { super.selectMap(); UnifiedMapWithHashingStrategy<Person, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4); Assert.assertEquals(UnifiedMap.newWithKeysValues(JOHNDOE, 2), map.select((argument1, argument2) -> "Doe".equals(argument1.getLastName()))); } @Override @Test public void rejectMap() { super.rejectMap(); UnifiedMapWithHashingStrategy<Person, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4); Assert.assertEquals(UnifiedMap.newWithKeysValues(JOHNDOE, 2), map.reject((argument1, argument2) -> "Smith".equals(argument1.getLastName()))); } @Override @Test public void collectMap() { super.collectMap(); UnifiedMapWithHashingStrategy<Person, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JOHNSMITH, 2, JANEDOE, 3, JANESMITH, 4); Function2<Person, Integer, Pair<Integer, Person>> function = (Person argument1, Integer argument2) -> Tuples.pair(argument2, argument1); MutableMap<Integer, Person> collect = map.collect(function); Verify.assertSetsEqual(UnifiedSet.newSetWith(3, 4), collect.keySet()); Verify.assertContainsAll(collect.values(), JOHNDOE, JOHNSMITH); } @Test public void contains_with_hashing_strategy() { UnifiedMapWithHashingStrategy<Person, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4); Assert.assertTrue(map.containsKey(JOHNDOE)); Assert.assertTrue(map.containsValue(2)); Assert.assertTrue(map.containsKey(JOHNSMITH)); Assert.assertTrue(map.containsValue(4)); Assert.assertTrue(map.containsKey(JANEDOE)); Assert.assertTrue(map.containsKey(JANESMITH)); Assert.assertFalse(map.containsValue(1)); Assert.assertFalse(map.containsValue(3)); } @Test public void remove_with_hashing_strategy() { UnifiedMapWithHashingStrategy<Person, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4); //Testing removing people Assert.assertEquals(2, map.remove(JANEDOE).intValue()); Assert.assertEquals(4, map.remove(JOHNSMITH).intValue()); Verify.assertEmpty(map); //Testing removing from a chain UnifiedMapWithHashingStrategy<Integer, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, COLLISION_4, 4); Assert.assertEquals(4, map2.remove(COLLISION_4).intValue()); Assert.assertEquals(1, map2.remove(COLLISION_1).intValue()); Verify.assertSize(2, map2); //Testing removing null from a chain UnifiedMapWithHashingStrategy<Integer, Integer> map3 = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, COLLISION_1, 1, null, 2, 3, 3, 4, null); Assert.assertEquals(2, map3.remove(null).intValue()); Verify.assertSize(3, map3); Assert.assertNull(map3.remove(4)); Verify.assertSize(2, map3); } @Test public void keySet_isEmpty() { Set<Integer> keySet = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, 1, 1, 2, 2).keySet(); Assert.assertFalse(keySet.isEmpty()); keySet.clear(); Verify.assertEmpty(keySet); } @Test public void keySet_with_hashing_strategy() { Set<Person> people = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4).keySet(); Verify.assertSize(2, people); Verify.assertContains(JANEDOE, people); Verify.assertContains(JOHNDOE, people); Verify.assertContains(JANESMITH, people); Verify.assertContains(JOHNSMITH, people); } @Test public void keySet_Iterator_removeFromNonChain() { Set<Integer> keys = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, 1, 1, 2, 2, 3, 3, 4, 4).keySet(); Iterator<Integer> keysIterator = keys.iterator(); keysIterator.next(); keysIterator.remove(); Verify.assertSetsEqual(UnifiedSet.newSetWith(2, 3, 4), keys); } @Test public void weakEntryToString() { Iterator<Map.Entry<Integer, Integer>> iterator = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, 1, 1).entrySet().iterator(); Map.Entry<Integer, Integer> element = iterator.next(); Assert.assertEquals("1=1", element.toString()); } @Override @Test public void valuesCollection_Iterator_remove() { // a map with a chain, remove one UnifiedMapWithHashingStrategy<Integer, Integer> map = this.mapWithCollisionsOfSize(3); Iterator<Integer> iterator = map.iterator(); iterator.next(); iterator.remove(); Verify.assertSize(2, map); // remove all values in chain iterator.next(); iterator.remove(); iterator.next(); iterator.remove(); Verify.assertEmpty(map); } @Test public void entry_equals_with_hashingStrategy() { UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, 1, 1, 2, 2, 3, 3, 4, 4); Iterator<Map.Entry<Integer, Integer>> entryIterator = map.entrySet().iterator(); Map.Entry<Integer, Integer> entry = entryIterator.next(); ImmutableEntry<Integer, Integer> immutableEntry = ImmutableEntry.of(entry.getKey(), entry.getValue()); Verify.assertEqualsAndHashCode(immutableEntry, entry); } @Test public void entrySet_with_hashing_strategy() { Set<Map.Entry<Person, Integer>> entries = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4).entrySet(); Verify.assertSize(2, entries); Verify.assertContains(ImmutableEntry.of(JOHNDOE, 2), entries); Verify.assertContains(ImmutableEntry.of(JANEDOE, 2), entries); Verify.assertContains(ImmutableEntry.of(JOHNSMITH, 4), entries); Verify.assertContains(ImmutableEntry.of(JANESMITH, 4), entries); Verify.assertNotContains(ImmutableEntry.of(JOHNDOE, 1), entries); Verify.assertNotContains(ImmutableEntry.of(JANESMITH, 3), entries); Assert.assertTrue(entries.remove(ImmutableEntry.of(JANESMITH, 4))); Verify.assertNotContains(ImmutableEntry.of(JOHNSMITH, 4), entries); Assert.assertTrue(entries.remove(ImmutableEntry.of(JOHNDOE, 2))); Verify.assertEmpty(entries); } @Test public void valuesCollection_containsAll() { Collection<Integer> values = this.newMapWithKeysValues(1, 1, 2, 2, 3, 3, 4, 4).values(); Assert.assertTrue(values.containsAll(FastList.newListWith(1, 2))); Assert.assertTrue(values.containsAll(FastList.newListWith(1, 2, 3, 4))); Assert.assertFalse(values.containsAll(FastList.newListWith(1, 2, 3, 4, 5))); } @Test public void batchForEach() { UnifiedMapWithHashingStrategy<String, Integer> map = UnifiedMapWithHashingStrategy.<String, Integer>newMap( STRING_HASHING_STRATEGY, 5).withKeysValues("1", 1, "2", 2, "3", 3, "4", 4); this.batchForEachTestCases(map, 10); UnifiedMapWithHashingStrategy<Integer, Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6); this.batchForEachChains(collisions, 21); UnifiedMapWithHashingStrategy<Integer, Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null); this.batchForEachNullHandling(nulls, 36); this.batchForEachEmptyBatchIterable(UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY)); } @Test public void batchForEachKey() { Set<Integer> keys = UnifiedMapWithHashingStrategy.<Integer, String>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(1, "1", 2, "2", 3, "3", 4, "4").keySet(); this.batchForEachTestCases((BatchIterable<Integer>) keys, 10); Set<Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).keySet(); this.batchForEachChains((BatchIterable<Integer>) collisions, 57); Set<Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).keySet(); this.batchForEachNullHandling((BatchIterable<Integer>) nulls, 16); this.batchForEachEmptyBatchIterable((BatchIterable<Integer>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY).keySet()); } @Test public void batchForEachValue() { Collection<Integer> values = UnifiedMapWithHashingStrategy.<String, Integer>newMap( STRING_HASHING_STRATEGY, 5).withKeysValues("1", 1, "2", 2, "3", 3, "4", 4).values(); this.batchForEachTestCases((BatchIterable<Integer>) values, 10); Collection<Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).values(); this.batchForEachChains((BatchIterable<Integer>) collisions, 21); Collection<Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).values(); this.batchForEachNullHandling((BatchIterable<Integer>) nulls, 36); this.batchForEachEmptyBatchIterable( (BatchIterable<Integer>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY).values()); } @Test public void batchForEachEntry() { //Testing batch size of 1 to 16 with no chains BatchIterable<Map.Entry<Integer, Integer>> entries = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, 1, 1, 2, 2, 3, 3, 4, 4).entrySet(); for (int sectionCount = 1; sectionCount <= 16; ++sectionCount) { Sum sum = new IntegerSum(0); for (int sectionIndex = 0; sectionIndex < sectionCount; ++sectionIndex) { entries.batchForEach(new EntrySumProcedure(sum), sectionIndex, sectionCount); } Assert.assertEquals(20, sum.getValue()); } } @Test public void batchForEachEntry_chains() { BatchIterable<Map.Entry<Integer, Integer>> collisions = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues( COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).entrySet(); //Testing 1 batch with chains Sum sum2 = new IntegerSum(0); //testing getBatchCount returns 1 int batchCount = collisions.getBatchCount(100000); for (int i = 0; i < batchCount; ++i) { collisions.batchForEach(new EntrySumProcedure(sum2), i, batchCount); } Assert.assertEquals(1, batchCount); Assert.assertEquals(78, sum2.getValue()); //Testing 3 batches with chains and uneven last batch Sum sum3 = new IntegerSum(0); for (int i = 0; i < 5; ++i) { collisions.batchForEach(new EntrySumProcedure(sum3), i, 5); } Assert.assertEquals(78, sum3.getValue()); } @Test public void batchForEachEntry_null_handling() { //Testing batchForEach handling null keys and null values Sum sum4 = new IntegerSum(0); BatchIterable<Map.Entry<Integer, Integer>> nulls = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues( null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).entrySet(); int numBatches = nulls.getBatchCount(7); for (int i = 0; i < numBatches; ++i) { nulls.batchForEach(each -> { sum4.add(each.getKey() == null ? 1 : each.getKey()); sum4.add(each.getValue() == null ? 1 : each.getValue()); }, i, numBatches); } Assert.assertEquals(52, sum4.getValue()); } @Test public void batchForEachEntry_emptySet() { //Test batchForEach on empty set, it should simply do nothing and not throw any exceptions Sum sum5 = new IntegerSum(0); BatchIterable<Map.Entry<Integer, Integer>> empty = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.newMap(INTEGER_HASHING_STRATEGY).entrySet(); empty.batchForEach(new EntrySumProcedure(sum5), 0, empty.getBatchCount(1)); Assert.assertEquals(0, sum5.getValue()); } private void batchForEachTestCases(BatchIterable<Integer> batchIterable, int expectedValue) { //Testing batch size of 1 to 16 with no chains for (int sectionCount = 1; sectionCount <= 16; ++sectionCount) { Sum sum = new IntegerSum(0); for (int sectionIndex = 0; sectionIndex < sectionCount; ++sectionIndex) { batchIterable.batchForEach(new SumProcedure<>(sum), sectionIndex, sectionCount); } Assert.assertEquals(expectedValue, sum.getValue()); } } private void batchForEachChains(BatchIterable<Integer> batchIterable, int expectedValue) { //Testing 1 batch with chains Sum sum = new IntegerSum(0); //testing getBatchCount returns 1 int numBatches = batchIterable.getBatchCount(100000); for (int i = 0; i < numBatches; ++i) { batchIterable.batchForEach(new SumProcedure<>(sum), i, numBatches); } Assert.assertEquals(1, numBatches); Assert.assertEquals(expectedValue, sum.getValue()); //Testing 3 batches with chains and uneven last batch Sum sum2 = new IntegerSum(0); for (int i = 0; i < 5; ++i) { batchIterable.batchForEach(new SumProcedure<>(sum2), i, 5); } Assert.assertEquals(expectedValue, sum2.getValue()); } private void batchForEachNullHandling(BatchIterable<Integer> batchIterable, int expectedValue) { //Testing batchForEach handling null keys and null values Sum sum = new IntegerSum(0); for (int i = 0; i < batchIterable.getBatchCount(7); ++i) { batchIterable.batchForEach(each -> sum.add(each == null ? 1 : each), i, batchIterable.getBatchCount(7)); } Assert.assertEquals(expectedValue, sum.getValue()); } private void batchForEachEmptyBatchIterable(BatchIterable<Integer> batchIterable) { //Test batchForEach on empty set, it should simply do nothing and not throw any exceptions Sum sum = new IntegerSum(0); batchIterable.batchForEach(new SumProcedure<>(sum), 0, batchIterable.getBatchCount(1)); Assert.assertEquals(0, sum.getValue()); } @Test public void batchIterable_forEach() { UnifiedMapWithHashingStrategy<String, Integer> map = UnifiedMapWithHashingStrategy.<String, Integer>newMap( STRING_HASHING_STRATEGY, 5).withKeysValues("1", 1, "2", 2, "3", 3, "4", 4); this.batchIterable_forEach(map, 10); UnifiedMapWithHashingStrategy<Integer, Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6); this.batchIterable_forEach(collisions, 21); UnifiedMapWithHashingStrategy<Integer, Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null); this.batchIterable_forEachNullHandling(nulls, 33); this.batchIterable_forEachEmptyBatchIterable(UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY)); } @Test public void batchIterable_forEachKey() { Set<Integer> keys = UnifiedMapWithHashingStrategy.<Integer, String>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(1, "1", 2, "2", 3, "3", 4, "4").keySet(); this.batchIterable_forEach((BatchIterable<Integer>) keys, 10); Set<Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).keySet(); this.batchIterable_forEach((BatchIterable<Integer>) collisions, 57); Set<Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).keySet(); this.batchIterable_forEachNullHandling((BatchIterable<Integer>) nulls, 15); this.batchIterable_forEachEmptyBatchIterable((BatchIterable<Integer>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY).keySet()); } @Test public void batchIterable_forEachValue() { Collection<Integer> values = UnifiedMapWithHashingStrategy.<String, Integer>newMap( STRING_HASHING_STRATEGY, 5).withKeysValues("1", 1, "2", 2, "3", 3, "4", 4).values(); this.batchIterable_forEach((BatchIterable<Integer>) values, 10); Collection<Integer> collisions = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues(COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).values(); this.batchIterable_forEach((BatchIterable<Integer>) collisions, 21); Collection<Integer> nulls = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues(null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).values(); this.batchIterable_forEachNullHandling((BatchIterable<Integer>) nulls, 33); this.batchIterable_forEachEmptyBatchIterable( (BatchIterable<Integer>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap(INTEGER_HASHING_STRATEGY).values()); } @Test public void batchIterable_forEachEntry() { BatchIterable<Map.Entry<Integer, Integer>> entries = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, 1, 1, 2, 2, 3, 3, 4, 4).entrySet(); Sum sum = new IntegerSum(0); entries.forEach(new EntrySumProcedure(sum)); Assert.assertEquals(20, sum.getValue()); } @Test public void batchIterable_forEachEntry_chains() { BatchIterable<Map.Entry<Integer, Integer>> collisions = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 5).withKeysValues( COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4).withKeysValues(2, 5, 3, 6).entrySet(); Sum sum = new IntegerSum(0); collisions.forEach(new EntrySumProcedure(sum)); Assert.assertEquals(78, sum.getValue()); } @Test public void batchIterable_forEachEntry_null_handling() { //Testing batchForEach handling null keys and null values Sum sum = new IntegerSum(0); BatchIterable<Map.Entry<Integer, Integer>> nulls = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 100).withKeysValues( null, 10, 1, null, 2, 11, 3, 12).withKeysValues(4, null, 5, null).entrySet(); nulls.forEach(each -> { sum.add(each.getKey() == null ? 0 : each.getKey()); sum.add(each.getValue() == null ? 0 : each.getValue()); }); Assert.assertEquals(48, sum.getValue()); } @Test public void batchIterable_forEachEntry_emptySet() { //Test forEach on empty set, it should simply do nothing and not throw any exceptions Sum sum = new IntegerSum(0); BatchIterable<Map.Entry<Integer, Integer>> empty = (BatchIterable<Map.Entry<Integer, Integer>>) UnifiedMapWithHashingStrategy.newMap(INTEGER_HASHING_STRATEGY).entrySet(); empty.forEach(new EntrySumProcedure(sum)); Assert.assertEquals(0, sum.getValue()); } private void batchIterable_forEach(BatchIterable<Integer> batchIterable, int expectedValue) { IntegerSum sum = new IntegerSum(0); batchIterable.forEach(new SumProcedure<>(sum)); Assert.assertEquals(expectedValue, sum.getValue()); } private void batchIterable_forEachNullHandling(BatchIterable<Integer> batchIterable, int expectedValue) { //Testing forEach handling null keys and null values Sum sum = new IntegerSum(0); batchIterable.forEach(each -> sum.add(each == null ? 0 : each)); Assert.assertEquals(expectedValue, sum.getValue()); } private void batchIterable_forEachEmptyBatchIterable(BatchIterable<Integer> batchIterable) { //Test forEach on empty set, it should simply do nothing and not throw any exceptions Sum sum = new IntegerSum(0); batchIterable.batchForEach(new SumProcedure<>(sum), 0, batchIterable.getBatchCount(1)); Assert.assertEquals(0, sum.getValue()); } @Override @Test public void forEachKeyValue() { super.forEachKeyValue(); // Testing full chain UnifiedSet<Integer> keys = UnifiedSet.newSet(); UnifiedSet<Integer> values = UnifiedSet.newSet(); UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, COLLISION_4, 4).withKeysValues(1, 5); map.forEachKeyValue((argument1, argument2) -> { keys.add(argument1); values.add(argument2); }); Verify.assertSetsEqual(UnifiedSet.newSetWith(COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, 1), keys); Verify.assertSetsEqual(UnifiedSet.newSetWith(1, 2, 3, 4, 5), values); // Testing when chain contains null UnifiedSet<Integer> keys2 = UnifiedSet.newSet(); UnifiedSet<Integer> values2 = UnifiedSet.newSet(); UnifiedMapWithHashingStrategy<Integer, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, 1, 4); map2.forEachKeyValue((argument1, argument2) -> { keys2.add(argument1); values2.add(argument2); }); Verify.assertSetsEqual(UnifiedSet.newSetWith(COLLISION_1, COLLISION_2, COLLISION_3, 1), keys2); Verify.assertSetsEqual(UnifiedSet.newSetWith(1, 2, 3, 4), values2); } @Test public void getMapMemoryUsedInWords() { UnifiedMapWithHashingStrategy<String, String> map = UnifiedMapWithHashingStrategy.newMap(STRING_HASHING_STRATEGY); Assert.assertEquals(34, map.getMapMemoryUsedInWords()); map.put("1", "1"); Assert.assertEquals(34, map.getMapMemoryUsedInWords()); UnifiedMapWithHashingStrategy<Integer, Integer> map2 = this.mapWithCollisionsOfSize(2); Assert.assertEquals(16, map2.getMapMemoryUsedInWords()); } @Test public void getHashingStrategy() { UnifiedMapWithHashingStrategy<Integer, Object> map = UnifiedMapWithHashingStrategy.newMap(INTEGER_HASHING_STRATEGY); Assert.assertSame(INTEGER_HASHING_STRATEGY, map.hashingStrategy()); } @Test public void getCollidingBuckets() { UnifiedMapWithHashingStrategy<Object, Object> map = UnifiedMapWithHashingStrategy.newMap(HashingStrategies.defaultStrategy()); Assert.assertEquals(0, map.getCollidingBuckets()); UnifiedMapWithHashingStrategy<Integer, Integer> map2 = this.mapWithCollisionsOfSize(2); Assert.assertEquals(1, map2.getCollidingBuckets()); map2.put(42, 42); Assert.assertEquals(1, map2.getCollidingBuckets()); UnifiedMapWithHashingStrategy<String, String> map3 = UnifiedMapWithHashingStrategy.newWithKeysValues( STRING_HASHING_STRATEGY, "Six", "6", "Bar", "-", "Three", "3", "Five", "5"); Assert.assertEquals(2, map3.getCollidingBuckets()); } @Override @Test public void getIfAbsentPut() { super.getIfAbsentPut(); // this map is deliberately small to force a rehash to occur from the put method, in a map with a chained bucket UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap( INTEGER_HASHING_STRATEGY, 2, 0.75f); MORE_COLLISIONS.forEach(Procedures.cast(each -> map.getIfAbsentPut(each, new PassThruFunction0<>(each)))); Assert.assertEquals(this.mapWithCollisionsOfSize(9), map); //Testing getting element present in chain UnifiedMapWithHashingStrategy<Integer, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, COLLISION_4, 4); Assert.assertEquals(2, map2.getIfAbsentPut(COLLISION_2, () -> { Assert.fail(); return null; }).intValue()); //Testing rehashing while creating a new chained key UnifiedMapWithHashingStrategy<Integer, Integer> map3 = UnifiedMapWithHashingStrategy.<Integer, Integer>newMap( INTEGER_HASHING_STRATEGY, 2, 0.75f).withKeysValues(COLLISION_1, 1, 2, 2, 3, 3); Assert.assertEquals(4, map3.getIfAbsentPut(COLLISION_2, new PassThruFunction0<>(4)).intValue()); } @Override @Test public void getIfAbsentPutValue() { super.getIfAbsentPutValue(); // this map is deliberately small to force a rehash to occur from the put method, in a map with a chained bucket UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap( INTEGER_HASHING_STRATEGY, 2, 0.75f); MORE_COLLISIONS.forEach(Procedures.cast(each -> map.getIfAbsentPut(each, each))); Assert.assertEquals(this.mapWithCollisionsOfSize(9), map); //Testing getting element present in chain UnifiedMapWithHashingStrategy<Integer, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, COLLISION_4, 4); Assert.assertEquals(Integer.valueOf(2), map2.getIfAbsentPut(COLLISION_2, Integer.valueOf(5))); Assert.assertEquals(Integer.valueOf(5), map2.getIfAbsentPut(5, Integer.valueOf(5))); } @Override @Test public void getIfAbsentPutWith() { super.getIfAbsentPutWith(); // this map is deliberately small to force a rehash to occur from the put method, in a map with a chained bucket UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap( INTEGER_HASHING_STRATEGY, 2, 0.75f); MORE_COLLISIONS.forEach(Procedures.cast(each -> map.getIfAbsentPutWith(each, Functions.getIntegerPassThru(), each))); Assert.assertEquals(this.mapWithCollisionsOfSize(9), map); //Testing getting element present in chain UnifiedMapWithHashingStrategy<Integer, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues( INTEGER_HASHING_STRATEGY, COLLISION_1, 1, COLLISION_2, 2, COLLISION_3, 3, COLLISION_4, 4); Assert.assertEquals(Integer.valueOf(2), map2.getIfAbsentPutWith(COLLISION_2, Functions.getIntegerPassThru(), Integer.valueOf(5))); Assert.assertEquals(Integer.valueOf(5), map2.getIfAbsentPutWith(5, Functions.getIntegerPassThru(), Integer.valueOf(5))); } @Test public void equals_with_hashing_strategy() { UnifiedMapWithHashingStrategy<Person, Integer> map1 = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 1, JOHNSMITH, 1, JANESMITH, 1); UnifiedMapWithHashingStrategy<Person, Integer> map2 = UnifiedMapWithHashingStrategy.newWithKeysValues( FIRST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 1, JOHNSMITH, 1, JANESMITH, 1); Assert.assertEquals(map1, map2); Assert.assertEquals(map2, map1); Assert.assertNotEquals(map1.hashCode(), map2.hashCode()); UnifiedMapWithHashingStrategy<Person, Integer> map3 = UnifiedMapWithHashingStrategy.newWithKeysValues( LAST_NAME_HASHING_STRATEGY, JOHNDOE, 1, JANEDOE, 2, JOHNSMITH, 3, JANESMITH, 4); UnifiedMapWithHashingStrategy<Person, Integer> map4 = UnifiedMapWithHashingStrategy.newMap(map3); HashMap<Person, Integer> hashMap = new HashMap<>(map3); Verify.assertEqualsAndHashCode(map3, map4); Assert.assertTrue(map3.equals(hashMap) && hashMap.equals(map3) && map3.hashCode() != hashMap.hashCode()); UnifiedMap<Person, Integer> unifiedMap = UnifiedMap.newWithKeysValues(JOHNDOE, 1, JANEDOE, 1, JOHNSMITH, 1, JANESMITH, 1); UnifiedMapWithHashingStrategy<Person, Integer> map5 = UnifiedMapWithHashingStrategy.newMap(LAST_NAME_HASHING_STRATEGY, unifiedMap); Assert.assertNotEquals(map5, unifiedMap); } @Override @Test public void put() { super.put(); // this map is deliberately small to force a rehash to occur from the put method, in a map with a chained bucket UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap( INTEGER_HASHING_STRATEGY, 2, 0.75f); COLLISIONS.forEach(0, 4, each -> Assert.assertNull(map.put(each, each))); Assert.assertEquals(this.mapWithCollisionsOfSize(5), map); } @Test public void put_get_with_hashing_strategy() { UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap(INTEGER_HASHING_STRATEGY); //Testing putting values in non chains Assert.assertNull(map.put(1, 1)); Assert.assertNull(map.put(2, 2)); Assert.assertNull(map.put(3, 3)); Assert.assertNull(map.put(4, 4)); Assert.assertNull(map.put(5, null)); //Testing getting values from no chains Assert.assertEquals(1, map.get(1).intValue()); Assert.assertEquals(2, map.get(2).intValue()); Assert.assertNull(map.get(5)); //Testing putting and getting elements in a chain Assert.assertNull(map.put(COLLISION_1, 1)); Assert.assertNull(map.get(COLLISION_2)); Assert.assertNull(map.put(COLLISION_2, 2)); Assert.assertNull(map.get(COLLISION_3)); Assert.assertNull(map.put(COLLISION_3, null)); Assert.assertNull(map.put(COLLISION_4, 4)); Assert.assertNull(map.put(COLLISION_5, 5)); Assert.assertEquals(1, map.get(COLLISION_1).intValue()); Assert.assertEquals(5, map.get(COLLISION_5).intValue()); Assert.assertNull(map.get(COLLISION_3)); map.remove(COLLISION_2); Assert.assertNull(map.get(COLLISION_2)); //Testing for casting exceptions HashingStrategy<Person> lastName = new HashingStrategy<Person>() { public int computeHashCode(Person object) { return object.getLastName().hashCode(); } public boolean equals(Person object1, Person object2) { return object1.equals(object2); } }; UnifiedMapWithHashingStrategy<Person, Integer> map2 = UnifiedMapWithHashingStrategy.newMap(lastName); Assert.assertNull(map2.put(new Person("abe", "smith"), 1)); Assert.assertNull(map2.put(new Person("brad", "smith"), 2)); Assert.assertNull(map2.put(new Person("charlie", "smith"), 3)); } @Test public void hashingStrategy() { UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newWithKeysValues(INTEGER_HASHING_STRATEGY, 1, 1, 2, 2); Assert.assertSame(INTEGER_HASHING_STRATEGY, map.hashingStrategy()); } @Override protected UnifiedMapWithHashingStrategy<Integer, Integer> mapWithCollisionsOfSize(int size) { UnifiedMapWithHashingStrategy<Integer, Integer> map = UnifiedMapWithHashingStrategy.newMap( INTEGER_HASHING_STRATEGY, size); return this.populateMapWithCollisionsOfSize(size, map); } private static final class EntrySumProcedure implements Procedure<Map.Entry<Integer, Integer>> { private final Sum sum; private EntrySumProcedure(Sum sum) { this.sum = sum; } @Override public void value(Map.Entry<Integer, Integer> each) { this.sum.add(each.getKey()); this.sum.add(each.getValue()); } } }