/* * 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 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 expectedKeys = new ArrayList<>( Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")); Set 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 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 expectedValues = new ArrayList<>( Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ); Collection 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 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 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 m = new HashMap<>(); for (int i = 0; i < 100; i++) { m.put(i, "value"); } Set> 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 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> parent = m.entrySet().spliterator(); Spliterator> 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 void assertSubsizeEstimate(Spliterator spliterator, long expectedEstimate) { Spliterator child = spliterator.trySplit(); assertNotNull(child); assertEquals(expectedEstimate, spliterator.estimateSize()); assertEquals(expectedEstimate, child.estimateSize()); } public void test_replaceAll() throws Exception { HashMap 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) {} } }