| /* |
| * 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) {} |
| } |
| } |