1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * @test 19 * @bug 7126277 20 * @run testng/othervm -Dtest.map.collisions.shortrun=true Collisions 21 * @summary Ensure Maps behave well with lots of hashCode() collisions. 22 */ 23 package test.java.util.Map; 24 25 import java.util.BitSet; 26 import java.util.IdentityHashMap; 27 import java.util.Iterator; 28 import java.util.Map; 29 import java.util.function.Supplier; 30 31 import org.testng.annotations.Test; 32 import static org.testng.Assert.assertTrue; 33 import static org.testng.Assert.assertFalse; 34 import static org.testng.Assert.assertEquals; 35 import static org.testng.Assert.assertNotNull; 36 37 public class Collisions extends MapWithCollisionsProviders { 38 39 @Test(dataProvider = "mapsWithObjects") testIntegerIteration(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val)40 public void testIntegerIteration(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) { 41 Map<IntKey, IntKey> map = ms.get(); 42 int mapSize = map.size(); 43 44 BitSet all = new BitSet(mapSize); 45 for (Map.Entry<IntKey, IntKey> each : map.entrySet()) { 46 assertFalse(all.get(each.getKey().getValue()), "Iteration: key already seen"); 47 all.set(each.getKey().getValue()); 48 } 49 50 all.flip(0, mapSize); 51 assertTrue(all.isEmpty(), "Iteration: some keys not visited"); 52 53 for (IntKey each : map.keySet()) { 54 assertFalse(all.get(each.getValue()), "Iteration: key already seen"); 55 all.set(each.getValue()); 56 } 57 58 all.flip(0, mapSize); 59 assertTrue(all.isEmpty(), "Iteration: some keys not visited"); 60 61 int count = 0; 62 for (IntKey each : map.values()) { 63 count++; 64 } 65 66 assertEquals(map.size(), count, 67 String.format("Iteration: value count matches size m%d != c%d", map.size(), count)); 68 } 69 70 @Test(dataProvider = "mapsWithStrings") testStringIteration(String desc, Supplier<Map<String, String>> ms, String val)71 public void testStringIteration(String desc, Supplier<Map<String, String>> ms, String val) { 72 Map<String, String> map = ms.get(); 73 int mapSize = map.size(); 74 75 BitSet all = new BitSet(mapSize); 76 for (Map.Entry<String, String> each : map.entrySet()) { 77 String key = each.getKey(); 78 boolean longKey = key.length() > 5; 79 int index = key.hashCode() + (longKey ? mapSize / 2 : 0); 80 assertFalse(all.get(index), "key already seen"); 81 all.set(index); 82 } 83 84 all.flip(0, mapSize); 85 assertTrue(all.isEmpty(), "some keys not visited"); 86 87 for (String each : map.keySet()) { 88 boolean longKey = each.length() > 5; 89 int index = each.hashCode() + (longKey ? mapSize / 2 : 0); 90 assertFalse(all.get(index), "key already seen"); 91 all.set(index); 92 } 93 94 all.flip(0, mapSize); 95 assertTrue(all.isEmpty(), "some keys not visited"); 96 97 int count = 0; 98 for (String each : map.values()) { 99 count++; 100 } 101 102 assertEquals(map.size(), mapSize, 103 String.format("value count matches size m%d != k%d", map.size(), mapSize)); 104 } 105 106 @Test(dataProvider = "mapsWithObjectsAndStrings") testRemove(String desc, Supplier<Map<Object, Object>> ms, Object val)107 public void testRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) { 108 Map<Object, Object> map = ms.get(); 109 Object[] keys = map.keySet().toArray(); 110 111 for (int i = 0; i < keys.length; i++) { 112 Object each = keys[i]; 113 assertNotNull(map.remove(each), 114 String.format("remove: %s[%d]%s", desc, i, each)); 115 } 116 117 assertTrue(map.size() == 0 && map.isEmpty(), 118 String.format("remove: map empty. size=%d", map.size())); 119 } 120 121 @Test(dataProvider = "mapsWithObjectsAndStrings") testKeysIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val)122 public void testKeysIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) { 123 Map<Object, Object> map = ms.get(); 124 125 Iterator<Object> each = map.keySet().iterator(); 126 while (each.hasNext()) { 127 Object t = each.next(); 128 each.remove(); 129 assertFalse(map.containsKey(t), String.format("not removed: %s", each)); 130 } 131 132 assertTrue(map.size() == 0 && map.isEmpty(), 133 String.format("remove: map empty. size=%d", map.size())); 134 } 135 136 @Test(dataProvider = "mapsWithObjectsAndStrings") testValuesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val)137 public void testValuesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) { 138 Map<Object, Object> map = ms.get(); 139 140 Iterator<Object> each = map.values().iterator(); 141 while (each.hasNext()) { 142 Object t = each.next(); 143 each.remove(); 144 assertFalse(map.containsValue(t), String.format("not removed: %s", each)); 145 } 146 147 assertTrue(map.size() == 0 && map.isEmpty(), 148 String.format("remove: map empty. size=%d", map.size())); 149 } 150 151 @Test(dataProvider = "mapsWithObjectsAndStrings") testEntriesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val)152 public void testEntriesIteratorRemove(String desc, Supplier<Map<Object, Object>> ms, Object val) { 153 Map<Object, Object> map = ms.get(); 154 155 Iterator<Map.Entry<Object, Object>> each = map.entrySet().iterator(); 156 while (each.hasNext()) { 157 Map.Entry<Object, Object> t = each.next(); 158 Object key = t.getKey(); 159 Object value = t.getValue(); 160 each.remove(); 161 assertTrue((map instanceof IdentityHashMap) || !map.entrySet().contains(t), 162 String.format("not removed: %s", each)); 163 assertFalse(map.containsKey(key), 164 String.format("not removed: %s", each)); 165 assertFalse(map.containsValue(value), 166 String.format("not removed: %s", each)); 167 } 168 169 assertTrue(map.size() == 0 && map.isEmpty(), 170 String.format("remove: map empty. size=%d", map.size())); 171 } 172 173 }