blob: a5ee1f6dd7c0b0103ca7bb51177a9dd510aea09f [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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 libcore.java.util;
import org.mockito.InOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.TreeMap;
public class HashMapTest extends junit.framework.TestCase {
public void test_getOrDefault() {
MapDefaultMethodTester.test_getOrDefault(new HashMap<>(), true /*acceptsNullKey*/,
true /*acceptsNullValue*/, true /*getAcceptsAnyObject*/);
}
public void test_forEach() {
MapDefaultMethodTester.test_forEach(new HashMap<>());
}
public void test_putIfAbsent() {
MapDefaultMethodTester.test_putIfAbsent(new HashMap<>(), true /*acceptsNullKey*/,
true /*acceptsNullValue*/);
}
public void test_remove() {
MapDefaultMethodTester
.test_remove(new HashMap<>(), true /*acceptsNullKey*/, true /*acceptsNullValue*/);
}
public void test_replace$K$V$V() {
MapDefaultMethodTester
.test_replace$K$V$V(new HashMap<>(), true /*acceptsNullKey*/,
true /*acceptsNullValue*/);
}
public void test_replace$K$V() {
MapDefaultMethodTester.test_replace$K$V(new HashMap<>(), true /*acceptsNullKey*/,
true /*acceptsNullValue*/);
}
public void test_computeIfAbsent() {
MapDefaultMethodTester.test_computeIfAbsent(new HashMap<>(), true /*acceptsNullKey*/,
true /*acceptsNullValue*/);
}
public void test_computeIfPresent() {
MapDefaultMethodTester.test_computeIfPresent(new HashMap<>(), true /*acceptsNullKey*/);
}
public void test_compute() {
MapDefaultMethodTester
.test_compute(new HashMap<>(), true /*acceptsNullKey*/);
}
public void test_merge() {
MapDefaultMethodTester
.test_merge(new HashMap<>(), true /*acceptsNullKey*/);
}
public void test_spliterator_keySet() {
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
m.put("b", 2);
m.put("c", 3);
m.put("d", 4);
m.put("e", 5);
m.put("f", 6);
m.put("g", 7);
m.put("h", 8);
m.put("i", 9);
m.put("j", 10);
ArrayList<String> expectedKeys = new ArrayList<>(
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"));
Set<String> keys = m.keySet();
SpliteratorTester.runBasicIterationTests(keys.spliterator(), expectedKeys);
SpliteratorTester.runBasicSplitTests(keys, expectedKeys);
SpliteratorTester.testSpliteratorNPE(keys.spliterator());
SpliteratorTester.runSizedTests(keys.spliterator(), 10);
assertEquals(Spliterator.DISTINCT | Spliterator.SIZED,
keys.spliterator().characteristics());
SpliteratorTester.assertSupportsTrySplit(keys);
}
public void test_spliterator_values() {
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
m.put("b", 2);
m.put("c", 3);
m.put("d", 4);
m.put("e", 5);
m.put("f", 6);
m.put("g", 7);
m.put("h", 8);
m.put("i", 9);
m.put("j", 10);
ArrayList<Integer> expectedValues = new ArrayList<>(
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
);
Collection<Integer> values = m.values();
SpliteratorTester.runBasicIterationTests(values.spliterator(), expectedValues);
SpliteratorTester.runBasicSplitTests(values, expectedValues);
SpliteratorTester.testSpliteratorNPE(values.spliterator());
SpliteratorTester.runSizedTests(values, 10);
assertEquals(Spliterator.SIZED, values.spliterator().characteristics());
SpliteratorTester.assertSupportsTrySplit(values);
}
public void test_spliterator_entrySet() {
MapDefaultMethodTester.test_entrySet_spliterator_unordered(new HashMap<>());
Map<String, Integer> m = new HashMap<>(Collections.singletonMap("key", 42));
assertEquals(Spliterator.DISTINCT | Spliterator.SIZED,
m.entrySet().spliterator().characteristics());
}
/**
* Checks that {@code HashMap.entrySet().spliterator().trySplit()}
* estimates half of the parents' estimate (rounded down, which
* can be an underestimate) but is not itself SIZED.
*
* These assertions are still stronger than what the documentation
* guarantees since un-SIZED Spliterators' size estimates may be off by
* an arbitrary amount.
*/
public void test_entrySet_subsizeEstimates() {
Map<String, String> m = new HashMap<>();
assertNull(m.entrySet().spliterator().trySplit());
// For the empty map, the estimates are exact
assertEquals(0, m.entrySet().spliterator().estimateSize());
assertEquals(0, m.entrySet().spliterator().getExactSizeIfKnown());
m.put("key1", "value1");
assertSubsizeEstimate(m.entrySet().spliterator(), 0);
m.put("key2", "value2");
assertSubsizeEstimate(m.entrySet().spliterator(), 1);
m.put("key3", "value3");
m.put("key4", "value4");
m.put("key5", "value5");
m.put("key6", "value6");
m.put("key7", "value7");
m.put("key8", "value8");
assertSubsizeEstimate(m.entrySet().spliterator(), 4);
m.put("key9", "value9");
assertSubsizeEstimate(m.entrySet().spliterator(), 4);
assertFalse(m.entrySet().spliterator().trySplit().hasCharacteristics(Spliterator.SIZED));
}
/**
* Checks that HashMap.entrySet()'s spliterator halfs its estimate (rounding down)
* for each split, even though this estimate may be inaccurate.
*/
public void test_entrySet_subsizeEstimates_recursive() {
Map<Integer, String> m = new HashMap<>();
for (int i = 0; i < 100; i++) {
m.put(i, "value");
}
Set<Map.Entry<Integer, String>> entries = m.entrySet();
// Recursive splitting - HashMap will estimate the size halving each split, rounding down.
assertSubsizeEstimate(entries.spliterator(), 50);
assertSubsizeEstimate(entries.spliterator().trySplit(), 25);
assertSubsizeEstimate(entries.spliterator().trySplit().trySplit(), 12);
assertSubsizeEstimate(entries.spliterator().trySplit().trySplit().trySplit(), 6);
assertSubsizeEstimate(entries.spliterator().trySplit().trySplit().trySplit().trySplit(), 3);
assertSubsizeEstimate(
entries.spliterator().trySplit().trySplit().trySplit().trySplit().trySplit(), 1);
assertSubsizeEstimate(entries.spliterator().trySplit().trySplit().trySplit().trySplit()
.trySplit().trySplit(), 0);
}
/**
* Checks that HashMap.EntryIterator is SIZED but not SUBSIZED.
*/
public void test_entrySet_spliterator_sizedButNotSubsized() {
Map<String, String> m = new HashMap<>();
assertTrue(m.entrySet().spliterator().hasCharacteristics(Spliterator.SIZED));
assertFalse(m.entrySet().spliterator().hasCharacteristics(Spliterator.SUBSIZED));
m.put("key1", "value1");
m.put("key2", "value2");
assertTrue(m.entrySet().spliterator().hasCharacteristics(Spliterator.SIZED));
assertFalse(m.entrySet().spliterator().hasCharacteristics(Spliterator.SUBSIZED));
Spliterator<Map.Entry<String, String>> parent = m.entrySet().spliterator();
Spliterator<Map.Entry<String, String>> child = parent.trySplit();
assertFalse(parent.hasCharacteristics(Spliterator.SIZED));
assertFalse(child.hasCharacteristics(Spliterator.SIZED));
assertFalse(parent.hasCharacteristics(Spliterator.SUBSIZED));
assertFalse(child.hasCharacteristics(Spliterator.SUBSIZED));
}
/**
* Tests that the given spliterator can be trySplit(), resulting in children that each
* estimate the specified size.
*/
private static<T> void assertSubsizeEstimate(Spliterator<T> spliterator,
long expectedEstimate) {
Spliterator<T> child = spliterator.trySplit();
assertNotNull(child);
assertEquals(expectedEstimate, spliterator.estimateSize());
assertEquals(expectedEstimate, child.estimateSize());
}
public void test_replaceAll() throws Exception {
HashMap<String, String> map = new HashMap<>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");
map.replaceAll((k, v) -> k + v);
assertEquals("one1", map.get("one"));
assertEquals("two2", map.get("two"));
assertEquals("three3", map.get("three"));
assertEquals(3, map.size());
try {
map.replaceAll((k, v) -> {
map.put("foo1", v);
return v;
});
fail();
} catch(ConcurrentModificationException expected) {}
try {
map.replaceAll(null);
fail();
} catch(NullPointerException expected) {}
}
}