/*
* 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.mutable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.api.map.MutableMap;
import com.gs.collections.api.set.MutableSet;
import com.gs.collections.impl.block.factory.Comparators;
import com.gs.collections.impl.block.factory.Functions;
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.fixed.ArrayAdapter;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.collections.impl.test.SerializeTestHelper;
import com.gs.collections.impl.test.Verify;
import com.gs.collections.impl.tuple.ImmutableEntry;
import com.gs.collections.impl.utility.ArrayIterate;
import com.gs.collections.impl.utility.Iterate;
import org.junit.Assert;
import org.junit.Test;
import static com.gs.collections.impl.factory.Iterables.iMap;
import static com.gs.collections.impl.factory.Iterables.mList;
public abstract class UnifiedMapTestCase extends MutableMapTestCase
{
protected static final Integer COLLISION_1 = 0;
protected static final Integer COLLISION_2 = 17;
protected static final Integer COLLISION_3 = 34;
protected static final Integer COLLISION_4 = 51;
protected static final Integer COLLISION_5 = 68;
protected static final Integer COLLISION_6 = 85;
protected static final Integer COLLISION_7 = 102;
protected static final Integer COLLISION_8 = 119;
protected static final Integer COLLISION_9 = 136;
protected static final Integer COLLISION_10 = 152;
protected static final MutableList<Integer> COLLISIONS =
Lists.mutable.of(COLLISION_1, COLLISION_2, COLLISION_3, COLLISION_4, COLLISION_5);
protected static final MutableList<Integer> MORE_COLLISIONS = FastList.newList(COLLISIONS)
.with(COLLISION_6, COLLISION_7, COLLISION_8, COLLISION_9);
protected static final String[] FREQUENT_COLLISIONS = {"\u9103\ufffe", "\u9104\uffdf",
"\u9105\uffc0", "\u9106\uffa1", "\u9107\uff82", "\u9108\uff63", "\u9109\uff44",
"\u910a\uff25", "\u910b\uff06", "\u910c\ufee7"};
@Test
public void valuesCollection_toArray()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One").asUnmodifiable();
Object[] values = map.values().toArray();
Verify.assertItemAtIndex("One", 0, values);
// map containing chain
MutableMap<Integer, Integer> chainedMap = this.mapWithCollisionsOfSize(2);
Object[] chainedValues = chainedMap.values().toArray();
Arrays.sort(chainedValues);
Assert.assertArrayEquals(new Integer[]{COLLISION_1, COLLISION_2}, chainedValues);
// map containing chain with empty slots
MutableMap<Integer, Integer> chainedMapWithEmpties = this.mapWithCollisionsOfSize(3);
Object[] chainedValuesWithEmpties = chainedMapWithEmpties.values().toArray();
Arrays.sort(chainedValuesWithEmpties);
Assert.assertArrayEquals(new Integer[]{COLLISION_1, COLLISION_2, COLLISION_3}, chainedValuesWithEmpties);
}
@Test
public void valuesCollection_toArray_WithEmptyTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
String[] values = map.values().toArray(new String[0]);
Assert.assertArrayEquals(new String[]{"One"}, values);
Object[] objects = map.values().toArray(new Object[0]);
Assert.assertArrayEquals(new String[]{"One"}, objects);
}
@Test
public void valuesCollection_toArray_withPreSizedTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two");
String[] values = map.values().toArray(new String[2]);
Arrays.sort(values);
Assert.assertArrayEquals(new String[]{"One", "Two"}, values);
String[] target = new String[3];
target[0] = "HERE";
target[1] = "HERE";
target[2] = "HERE";
String[] array = this.newMapWithKeyValue(1, "One").values().toArray(target);
Assert.assertArrayEquals(new String[]{"One", null, "HERE"}, array);
}
@Test
public void valuesCollection_toArray_withLargeTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two");
String[] target = new String[3];
target[2] = "yow!";
String[] values = map.values().toArray(target);
ArrayIterate.sort(values, values.length, Comparators.safeNullsHigh(String::compareTo));
Assert.assertArrayEquals(new String[]{"One", "Two", null}, values);
}
@Test
public void entrySet_clear()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two");
Set<Map.Entry<Integer, String>> entries = map.entrySet();
entries.clear();
Verify.assertEmpty(entries);
Verify.assertEmpty(map);
}
@Test
public void valuesCollection_clear()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three");
Collection<String> values = map.values();
values.clear();
Verify.assertEmpty(values);
Verify.assertEmpty(map);
}
@Test
public void keySet_toArray_withSmallTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
Integer[] destination = new Integer[2]; // deliberately to small to force the method to allocate one of the correct size
Integer[] result = map.keySet().toArray(destination);
Arrays.sort(result);
Assert.assertArrayEquals(new Integer[]{1, 2, 3, 4}, result);
}
@Test
public void keySet_ToArray_withLargeTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
Integer[] target = new Integer[6]; // deliberately large to force the extra to be set to null
target[4] = 42;
target[5] = 42;
Integer[] result = map.keySet().toArray(target);
ArrayIterate.sort(result, result.length, Comparators.safeNullsHigh(Integer::compareTo));
Assert.assertArrayEquals(new Integer[]{1, 2, 3, 4, 42, null}, result);
}
@Test
public void noInstanceOfEquals()
{
MutableMap<NoInstanceOfInEquals, Integer> map = this.newMap();
map.put(new NoInstanceOfInEquals(10), 12);
map.put(new NoInstanceOfInEquals(12), 15);
map.put(new NoInstanceOfInEquals(14), 18);
Assert.assertEquals(3, map.size());
}
@Test
public void keySet_hashCode()
{
// a map with a null key
MutableMap<Integer, Integer> map1 = this.newMapWithKeyValue(null, 0);
UnifiedSet<Object> set = UnifiedSet.newSet();
set.add(null);
Verify.assertEqualsAndHashCode(set, map1.keySet());
// a map with a chain containing empty slots
MutableMap<Integer, Integer> map2 = this.mapWithCollisionsOfSize(5);
Verify.assertEqualsAndHashCode(UnifiedSet.newSetWith(0, 17, 34, 51, 68), map2.keySet());
// a map with a chain containing empty slots and a null key
MutableMap<Integer, Integer> map3 = this.mapWithCollisionsOfSize(5);
map3.put(null, 42);
Verify.assertEqualsAndHashCode(UnifiedSet.newSetWith(0, 17, 34, 51, 68, null), map3.keySet());
}
@Test
public void keySet_copyKeys()
{
// a map with a null key
MutableMap<Integer, Integer> map1 = this.newMapWithKeyValue(null, 0);
Assert.assertArrayEquals(new Object[]{null}, map1.keySet().toArray());
// a map with a chain containing empty slots
MutableMap<Integer, Integer> map2 = this.mapWithCollisionsOfSize(5);
Assert.assertArrayEquals(new Object[]{0, 17, 34, 51, 68}, map2.keySet().toArray());
// a map with a chain containing empty slots and null key
MutableMap<Integer, Integer> map3 = this.mapWithCollisionsOfSize(5);
map3.put(null, 42);
Integer[] array = map3.keySet().toArray(new Integer[map3.size()]);
ArrayIterate.sort(array, array.length, Comparators.safeNullsHigh(Integer::compareTo));
Assert.assertArrayEquals(new Object[]{0, 17, 34, 51, 68, null}, array);
}
@Test
public void entrySet_toArray()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Object[] entries = map.entrySet().toArray();
Assert.assertArrayEquals(new Map.Entry[]{ImmutableEntry.of(1, "One")}, entries);
}
@Test
public void entrySet_toArray_withEmptyTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Map.Entry<Integer, String>[] entries = map.entrySet().toArray(new Map.Entry[0]);
Assert.assertArrayEquals(new Map.Entry[]{ImmutableEntry.of(1, "One")}, entries);
Object[] objects = map.entrySet().toArray(new Object[0]);
Assert.assertArrayEquals(new Map.Entry[]{ImmutableEntry.of(1, "One")}, objects);
}
@Test
public void entrySet_toArray_withPreSizedTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Map.Entry<Integer, String>[] entries = map.entrySet().toArray(new Map.Entry[map.size()]);
Assert.assertArrayEquals(new Map.Entry[]{ImmutableEntry.of(1, "One")}, entries);
}
@Test
public void entrySet_toArray_withLargeTarget()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Map.Entry<Integer, String>[] target = new Map.Entry[4];
ImmutableEntry<Integer, String> immutableEntry = new ImmutableEntry<>(null, null);
target[1] = immutableEntry;
target[2] = immutableEntry;
target[3] = immutableEntry;
Map.Entry<Integer, String>[] entries = map.entrySet().toArray(target);
Assert.assertArrayEquals(new Map.Entry[]{ImmutableEntry.of(1, "One"), null, immutableEntry, immutableEntry}, entries);
}
protected MutableMap<Integer, Integer> mapWithCollisionsOfSize(int size)
{
MutableMap<Integer, Integer> map = this.newMap();
return this.populateMapWithCollisionsOfSize(size, map);
}
protected <M extends MutableMap<Integer, Integer>> M populateMapWithCollisionsOfSize(int size, M map)
{
MORE_COLLISIONS.subList(0, size).forEach(Procedures.cast(each -> map.put(each, each)));
return map;
}
@Test
public void entrySet_PostSerializedEqualsAndHashCode()
{
MutableMap<String, Integer> map = this.newMapWithKeysValues("One", 1, "Two", 2, "Three", 3);
Verify.assertPostSerializedEqualsAndHashCode(map.entrySet());
}
@Test
public void keySet_PostSerializedEqualsAndHashCode()
{
MutableMap<String, Integer> map = this.newMapWithKeysValues("One", 1, "Two", 2, "Three", 3);
Verify.assertPostSerializedEqualsAndHashCode(map.keySet());
}
@Test
public void keySet_PostSerializedEqualsAndHashCode_chainWithEmptySlot()
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(5);
Verify.assertPostSerializedEqualsAndHashCode(map.keySet());
}
@Test
public void valuesCollection_PostSerializedEquality()
{
MutableMap<Integer, Integer> map = this.newMapWithKeysValues(1, 1, 2, 2, 3, 3);
Collection<Integer> values = map.values();
// This test is not using Verify.assertPostSerializedEqualsAndHashCode b/c the deserialized form of the values view is a FastList, which will not be equals to the original view (a Collection).
Collection<Integer> revived = SerializeTestHelper.serializeDeserialize(values);
Assert.assertNotNull(revived);
Verify.assertSize(values.size(), revived);
Assert.assertTrue(revived.containsAll(values));
}
@Test
public void valuesCollection_PostSerializedEquality_chainedMap()
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(2);
Collection<Integer> values = map.values();
Collection<Integer> revived = SerializeTestHelper.serializeDeserialize(values);
Assert.assertNotNull(revived);
Verify.assertSize(values.size(), revived);
Assert.assertTrue(revived.containsAll(values));
}
@Test
public void valuesCollection_PostSerializedEquality_chainedMapWithEmptySlot()
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(4);
map.put(42, 42); // add non-colliding key
Collection<Integer> values = map.values();
// This test is not using Verify.assertPostSerializedEqualsAndHashCode b/c the deserialized form of the values view is a FastList, which will not be equals to the orginal view (a Collection).
Collection<Integer> revived = SerializeTestHelper.serializeDeserialize(values);
Assert.assertNotNull(revived);
Verify.assertSize(values.size(), revived);
Assert.assertTrue(revived.containsAll(values));
}
@Test
public void contains_key_and_value()
{
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Assert.assertTrue(map.containsKey(COLLISIONS.get(i - 1)));
Assert.assertTrue(map.containsValue(COLLISIONS.get(i - 1)));
Assert.assertFalse(map.containsKey(COLLISION_10));
Assert.assertFalse(map.containsValue(COLLISION_10));
Assert.assertFalse(map.containsKey(null));
Assert.assertFalse(map.containsValue(null));
map.put(null, null);
Assert.assertTrue(map.containsKey(null));
Assert.assertTrue(map.containsValue(null));
}
}
@Test
public void remove()
{
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Assert.assertNull(map.put(null, null));
Assert.assertNull(map.remove(null));
Assert.assertNull(map.remove(COLLISION_10));
Integer biggestValue = COLLISIONS.get(i - 1);
Assert.assertEquals(biggestValue, map.remove(biggestValue));
}
}
@Test
public void getIfAbsentPutValueWithCollisions()
{
MutableMap<Integer, Object> map = this.newMapWithKeyValue(COLLISION_1, null);
Assert.assertNull(map.getIfAbsentPut(COLLISION_1, 5));
Assert.assertNull(map.getIfAbsentPut(COLLISION_3, (Integer) null));
Assert.assertNull(map.getIfAbsentPut(COLLISION_3, 7));
Assert.assertEquals(Integer.valueOf(9), map.getIfAbsentPut(COLLISION_2, 9));
Assert.assertEquals(Integer.valueOf(10), map.getIfAbsentPut(COLLISION_4, 10));
Assert.assertEquals(UnifiedMap.newWithKeysValues(COLLISION_1, null, COLLISION_2, 9, COLLISION_3, null, COLLISION_4, 10), map);
}
@Test
public void getIfAbsentPutWithWithCollisions()
{
MutableMap<Integer, Object> map = this.newMapWithKeyValue(COLLISION_1, null);
Assert.assertNull(map.getIfAbsentPutWith(COLLISION_1, String::valueOf, 5));
Assert.assertNull(map.getIfAbsentPutWith(COLLISION_3, Functions.getPassThru(), null));
Assert.assertNull(map.getIfAbsentPutWith(COLLISION_3, String::valueOf, 7));
Assert.assertEquals("9", map.getIfAbsentPutWith(COLLISION_2, String::valueOf, 9));
Assert.assertEquals(Integer.valueOf(10), map.getIfAbsentPutWith(COLLISION_4, Functions.getIntegerPassThru(), 10));
Assert.assertEquals(UnifiedMap.newWithKeysValues(COLLISION_1, null, COLLISION_2, "9", COLLISION_3, null, COLLISION_4, 10), map);
}
@Override
@Test
public void removeFromEntrySet()
{
super.removeFromEntrySet();
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Integer biggestValue = COLLISIONS.get(i - 1);
Assert.assertTrue(map.entrySet().remove(ImmutableEntry.of(biggestValue, biggestValue)));
Assert.assertEquals(this.mapWithCollisionsOfSize(i - 1), map);
Assert.assertFalse(map.entrySet().remove(ImmutableEntry.of(COLLISION_10, COLLISION_10)));
Assert.assertEquals(this.mapWithCollisionsOfSize(i - 1), map);
Assert.assertFalse(map.entrySet().remove(null));
}
}
@Override
@Test
public void retainAllFromEntrySet()
{
super.retainAllFromEntrySet();
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Assert.assertFalse(map.entrySet().retainAll(
FastList.newList(map.entrySet()).with(ImmutableEntry.of(COLLISION_10, COLLISION_10))));
Assert.assertTrue(map.entrySet().retainAll(
this.mapWithCollisionsOfSize(i - 1).entrySet()));
Assert.assertEquals(this.mapWithCollisionsOfSize(i - 1), map);
}
for (Integer item : MORE_COLLISIONS)
{
MutableMap<Integer, Integer> integers = this.mapWithCollisionsOfSize(9);
@SuppressWarnings("BoxingBoxedValue")
Integer keyCopy = new Integer(item);
Assert.assertTrue(integers.entrySet().retainAll(mList(ImmutableEntry.of(keyCopy, keyCopy))));
Assert.assertEquals(iMap(keyCopy, keyCopy), integers);
Assert.assertNotSame(keyCopy, Iterate.getOnly(integers.entrySet()).getKey());
}
// simple map, collection to retain contains non-entry element
MutableMap<Integer, String> map4 = this.newMapWithKeysValues(1, "One", 2, "Two");
FastList<Object> toRetain = FastList.newListWith(ImmutableEntry.of(1, "One"), "explosion!", ImmutableEntry.of(2, "Two"));
Assert.assertFalse(map4.entrySet().retainAll(toRetain));
}
@Override
@Test
public void forEachWith()
{
super.forEachWith();
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Object sentinel = new Object();
UnifiedSet<Integer> result = UnifiedSet.newSet();
map.forEachWith((argument1, argument2) -> {
Assert.assertSame(sentinel, argument2);
result.add(argument1);
}, sentinel);
Assert.assertEquals(map.keySet(), result);
}
}
@Test
public void keySet_retainAll()
{
// a map with a null key
MutableMap<Integer, Integer> map = this.newMapWithKeyValue(null, 0);
MutableList<Object> retained = Lists.mutable.of();
retained.add(null);
Assert.assertFalse(map.keySet().retainAll(retained));
Verify.assertContains(null, map.keySet());
// a map with a chain containing empty slots
MutableMap<Integer, Integer> map2 = this.mapWithCollisionsOfSize(5);
Assert.assertFalse(map2.keySet().retainAll(FastList.newListWith(0, 17, 34, 51, 68)));
Verify.assertContainsAll(map2.keySet(), 0, 17, 34, 51, 68);
// a map with no chaining, nothing retained
MutableMap<Integer, String> map3 = this.newMapWithKeyValue(1, "One");
Assert.assertTrue(map3.keySet().retainAll(FastList.newListWith(9)));
Verify.assertEmpty(map3);
Set<Integer> keys = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four").keySet();
Assert.assertTrue(keys.retainAll(FastList.newListWith(1, 2, 3)));
Verify.assertContainsAll(keys, 1, 2, 3);
}
@Test
public void keySet_containsAll()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
Assert.assertFalse(map.keySet().containsAll(FastList.newListWith(5)));
Assert.assertTrue(map.keySet().containsAll(FastList.newListWith(1, 2, 4)));
}
@Test
public void keySet_equals()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
Assert.assertNotEquals(UnifiedSet.newSetWith(1, 2, 3, 4, 5), map.keySet());
}
@Test(expected = UnsupportedOperationException.class)
public void keySet_add()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
map.keySet().add(5);
}
@Test(expected = UnsupportedOperationException.class)
public void keySet_addAll()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
map.keySet().addAll(UnifiedSet.newSetWith(5, 6));
}
@Test(expected = NoSuchElementException.class)
public void keySet_Iterator()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Iterator<Integer> iterator = map.keySet().iterator();
iterator.next();
iterator.next();
}
@Test(expected = NoSuchElementException.class)
public void entrySet_Iterator_incrementPastEnd()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
iterator.next();
iterator.next();
}
@Test(expected = IllegalStateException.class)
public void keySet_Iterator_removeBeforeIncrement()
{
// remove w/o incrementing
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Iterator<Integer> iterator = map.keySet().iterator();
iterator.remove();
}
@Test
public void valuesCollection_Iterator_remove()
{
// a map with a chain, remove one
MutableMap<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 iterator_many_collisions()
{
Iterator<Integer> iterator = this.mapWithCollisionsOfSize(9).iterator();
for (Integer collision : MORE_COLLISIONS)
{
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(collision, iterator.next());
}
Assert.assertFalse(iterator.hasNext());
}
@Test
public void entry_setValue()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Map.Entry<Integer, String> entry = Iterate.getFirst(map.entrySet());
String value = "Ninety-Nine";
Assert.assertEquals("One", entry.setValue(value));
Assert.assertEquals(value, entry.getValue());
Verify.assertContainsKeyValue(1, value, map);
map.remove(1);
Verify.assertEmpty(map);
Assert.assertNull(entry.setValue("Ignored"));
}
@Test
public void entry_hashCodeForNullKeyAndValue()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(null, null);
Map.Entry<Integer, String> entry = Iterate.getFirst(map.entrySet());
Assert.assertEquals(0, entry.hashCode());
}
@Test
public void entry_equalsWithNonEntry()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(null, null);
Map.Entry<Integer, String> entry = Iterate.getFirst(map.entrySet());
Assert.assertNotEquals(entry, new Object());
}
@Test
public void entrySet_remove()
{
// map with chaining, attempt to remove non-existent entry
MutableMap<Integer, Integer> chainedMap = this.mapWithCollisionsOfSize(3);
Set<Map.Entry<Integer, Integer>> chainedEntries = chainedMap.entrySet();
Assert.assertFalse(chainedEntries.remove(ImmutableEntry.of(5, 5)));
// map with chaining, attempt to remove non-existent collding entry
MutableMap<Integer, Integer> chainedMap2 = this.mapWithCollisionsOfSize(2);
Set<Map.Entry<Integer, Integer>> chainedEntries2 = chainedMap2.entrySet();
Assert.assertFalse(chainedEntries2.remove(ImmutableEntry.of(COLLISION_4, COLLISION_4)));
// map with chaining, attempt to remove non-existent colliding entry (key exists, but value does not)
MutableMap<Integer, Integer> chainedMap3 = this.mapWithCollisionsOfSize(3);
Set<Map.Entry<Integer, Integer>> chainedEntries3 = chainedMap3.entrySet();
Assert.assertFalse(chainedEntries3.remove(ImmutableEntry.of(COLLISION_2, COLLISION_4)));
// map with no chaining, attempt to remove non-existent entry
MutableMap<Integer, String> unchainedMap = this.newMapWithKeyValue(1, "One");
Set<Map.Entry<Integer, String>> unchainedEntries = unchainedMap.entrySet();
Assert.assertFalse(unchainedEntries.remove(ImmutableEntry.of(5, "Five")));
}
@Test
public void entrySet_contains()
{
// simple map, test for null key
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Set<Map.Entry<Integer, String>> entries = map.entrySet();
Verify.assertNotContains(ImmutableEntry.of(null, "Null"), entries);
// chained map, test for null value
MutableMap<Integer, Integer> chainedMap = this.newMapWithKeysValues(COLLISION_1, COLLISION_1, COLLISION_2, null);
Set<Map.Entry<Integer, Integer>> chainedEntries = chainedMap.entrySet();
Verify.assertContains(ImmutableEntry.of(COLLISION_2, null), chainedEntries);
}
@Test
public void entrySet_containsAll()
{
// simple map, test for non-existent entries
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 3, "Three");
Set<Map.Entry<Integer, String>> entries = map.entrySet();
Assert.assertFalse(entries.containsAll(FastList.newListWith(ImmutableEntry.of(2, "Two"))));
Assert.assertTrue(entries.containsAll(FastList.newListWith(ImmutableEntry.of(1, "One"), ImmutableEntry.of(3, "Three"))));
}
@Test(expected = UnsupportedOperationException.class)
public void entrySet_add()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Set<Map.Entry<Integer, String>> entries = map.entrySet();
entries.add(ImmutableEntry.of(2, "Two"));
}
@Test(expected = UnsupportedOperationException.class)
public void entrySet_addAll()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Set<Map.Entry<Integer, String>> entries = map.entrySet();
entries.addAll(FastList.newListWith(ImmutableEntry.of(2, "Two")));
}
@Test
public void entrySet_equals()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", null, null);
Assert.assertNotEquals(UnifiedSet.newSetWith(ImmutableEntry.of(5, "Five")), map.entrySet());
UnifiedSet<ImmutableEntry<Integer, String>> expected = UnifiedSet.newSetWith(
ImmutableEntry.of(1, "One"),
ImmutableEntry.of(2, "Two"),
ImmutableEntry.of(3, "Three"),
ImmutableEntry.<Integer, String>of(null, null));
Verify.assertEqualsAndHashCode(expected, map.entrySet());
}
@Test(expected = UnsupportedOperationException.class)
public void valuesCollection_add()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
map.values().add("explosion!");
}
@Test(expected = UnsupportedOperationException.class)
public void valuesCollection_addAll()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
map.values().addAll(UnifiedSet.newSetWith("explosion!", "kaboom!"));
}
@Test(expected = NoSuchElementException.class)
public void valueCollection_Iterator()
{
MutableMap<Integer, String> map = this.newMapWithKeyValue(1, "One");
Iterator<String> iterator = map.values().iterator();
iterator.next();
iterator.next();
}
@Test
public void valueCollection_equals()
{
MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", null, null);
Assert.assertNotEquals(UnifiedSet.newSetWith("One", "Two", "Three", null), map.values());
}
@Override
@Test
public void forEachWithIndex()
{
super.forEachWithIndex();
UnifiedSet<String> set = UnifiedSet.newSet();
// map with a chain and no empty slots
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(2);
map.forEachWithIndex((each, index) -> set.add(index + ":" + each));
Assert.assertEquals(UnifiedSet.newSetWith("0:0", "1:17"), set);
set.clear();
// map with a chain and empty slots
MutableMap<Integer, Integer> map2 = this.mapWithCollisionsOfSize(5);
map2.forEachWithIndex((each, index) -> set.add(index + ":" + each));
Assert.assertEquals(UnifiedSet.newSetWith("0:0", "1:17", "2:34", "3:51", "4:68"), set);
}
@Override
@Test
public void forEachKey()
{
super.forEachKey();
UnifiedSet<String> set = UnifiedSet.newSet(5);
// map with a chain and empty slots
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(5);
map.forEachKey(each -> set.add(each.toString()));
Assert.assertEquals(UnifiedSet.newSetWith("0", "17", "34", "51", "68"), set);
}
@Override
@Test
public void forEachValue()
{
super.forEachValue();
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(9).withKeyValue(null, null);
MutableSet<Integer> result = UnifiedSet.newSet();
map.forEachValue(each -> {
Assert.assertTrue(each == null || each.getClass() == Integer.class);
result.add(each);
});
Assert.assertEquals(MORE_COLLISIONS.toSet().with(null), result);
}
@Override
@Test
public void equalsAndHashCode()
{
super.equalsAndHashCode();
for (int i = 1; i < COLLISIONS.size(); i++)
{
MutableMap<Integer, Integer> map = this.mapWithCollisionsOfSize(i);
Map<Integer, Integer> expectedMap = new HashMap<>(map);
Verify.assertEqualsAndHashCode(expectedMap, map);
MutableMap<Integer, Integer> clone1 = map.clone();
clone1.put(COLLISION_10, COLLISION_10);
Assert.assertNotEquals(expectedMap, clone1);
MutableMap<Integer, Integer> clone2 = map.clone();
clone2.put(null, null);
Assert.assertNotEquals(expectedMap, clone2);
expectedMap.put(null, null);
Assert.assertNotEquals(expectedMap, map);
expectedMap.remove(null);
expectedMap.put(COLLISION_10, COLLISION_10);
Assert.assertNotEquals(expectedMap, map);
}
MutableMap<Integer, Integer> mapA = this.mapWithCollisionsOfSize(3);
MutableMap<Integer, Integer> mapB = this.mapWithCollisionsOfSize(3);
// map with a chain, compare the null key (and value) with a non-null key
mapA.put(null, null);
mapB.put(42, 84);
Assert.assertNotEquals(mapA, mapB);
Assert.assertNotEquals(mapA.hashCode(), mapB.hashCode());
// map with a chain, compare the two null keys with different values (one null, one not)
mapB.remove(42);
mapB.put(null, 42);
Assert.assertNotEquals(mapA, mapB);
// map with a chain, compare a non-null key (null value) with a non-null key and value
mapB.remove(null);
mapB.remove(42);
mapA.remove(null);
mapA.put(17, null);
Assert.assertNotEquals(mapA, mapB);
MutableMap<Integer, String> mapC = this.newMapWithKeysValues(1, "One", 2, "Two", null, null);
MutableMap<Integer, String> mapD = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three");
// compare the null key (and value) with a non-null key
Assert.assertNotEquals(mapC, mapD);
// compare a non-null key (and null value) with a non-null key
mapC.remove(null);
mapC.put(3, null);
Assert.assertNotEquals(mapC, mapD);
// reset
mapC.remove(3);
mapC.put(null, null);
// compare the null key (and null value) with a null key (and non-null value)
mapD.remove(3);
mapD.put(null, "Three");
// compare the two null keys with different values (one null, one not)
Assert.assertNotEquals(mapC, mapD);
Assert.assertEquals(0, this.newMapWithKeyValue(null, null).hashCode());
}
@Test
public void frequentCollision()
{
String[] expected = ArrayAdapter.adapt(FREQUENT_COLLISIONS)
.subList(0, FREQUENT_COLLISIONS.length - 2)
.toArray(new String[FREQUENT_COLLISIONS.length - 2]);
MutableMap<String, String> map = this.newMap();
MutableSet<String> set = Sets.mutable.of(expected);
ArrayIterate.forEach(FREQUENT_COLLISIONS, each -> map.put(each, each));
Iterator<String> itr = map.iterator();
while (itr.hasNext())
{
if (!set.contains(itr.next()))
{
itr.remove();
}
}
Verify.assertArrayEquals(expected, map.keysView().toArray());
}
private static final class NoInstanceOfInEquals
{
private final int value;
private NoInstanceOfInEquals(int value)
{
this.value = value;
}
@Override
public boolean equals(Object o)
{
NoInstanceOfInEquals that = (NoInstanceOfInEquals) o;
return this.value == that.value;
}
@Override
public int hashCode()
{
return 12;
}
}
}