1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.harmony.tests.java.util; 19 20 import java.util.AbstractMap; 21 import java.util.Arrays; 22 import java.util.ArrayList; 23 import java.util.Collection; 24 import java.util.Comparator; 25 import java.util.ConcurrentModificationException; 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Set; 32 import java.util.Spliterator; 33 import java.util.WeakHashMap; 34 import libcore.java.lang.ref.FinalizationTester; 35 36 import libcore.java.util.SpliteratorTester; 37 import tests.support.Support_MapTest2; 38 39 public class WeakHashMapTest extends junit.framework.TestCase { 40 class MockMap extends AbstractMap { entrySet()41 public Set entrySet() { 42 return null; 43 } 44 size()45 public int size() { 46 return 0; 47 } 48 } 49 50 Object[] keyArray = new Object[100]; 51 52 Object[] valueArray = new Object[100]; 53 54 WeakHashMap whm; 55 56 /** 57 * java.util.WeakHashMap#WeakHashMap() 58 */ test_Constructor()59 public void test_Constructor() { 60 // Test for method java.util.WeakHashMap() 61 new Support_MapTest2(new WeakHashMap()).runTest(); 62 63 whm = new WeakHashMap(); 64 for (int i = 0; i < 100; i++) 65 whm.put(keyArray[i], valueArray[i]); 66 for (int i = 0; i < 100; i++) 67 assertTrue("Incorrect value retrieved", whm.get(keyArray[i]) == valueArray[i]); 68 69 } 70 71 /** 72 * java.util.WeakHashMap#WeakHashMap(int) 73 */ test_ConstructorI()74 public void test_ConstructorI() { 75 // Test for method java.util.WeakHashMap(int) 76 whm = new WeakHashMap(50); 77 for (int i = 0; i < 100; i++) 78 whm.put(keyArray[i], valueArray[i]); 79 for (int i = 0; i < 100; i++) 80 assertTrue("Incorrect value retrieved", whm.get(keyArray[i]) == valueArray[i]); 81 82 WeakHashMap empty = new WeakHashMap(0); 83 assertNull("Empty weakhashmap access", empty.get("nothing")); 84 empty.put("something", "here"); 85 assertTrue("cannot get element", empty.get("something") == "here"); 86 87 try { 88 new WeakHashMap(-50); 89 fail("IllegalArgumentException expected"); 90 } catch (IllegalArgumentException e) { 91 //expected 92 } 93 } 94 95 /** 96 * java.util.WeakHashMap#WeakHashMap(int, float) 97 */ test_ConstructorIF()98 public void test_ConstructorIF() { 99 // Test for method java.util.WeakHashMap(int, float) 100 whm = new WeakHashMap(50, 0.5f); 101 for (int i = 0; i < 100; i++) 102 whm.put(keyArray[i], valueArray[i]); 103 for (int i = 0; i < 100; i++) 104 assertTrue("Incorrect value retrieved", whm.get(keyArray[i]) == valueArray[i]); 105 106 WeakHashMap empty = new WeakHashMap(0, 0.75f); 107 assertNull("Empty hashtable access", empty.get("nothing")); 108 empty.put("something", "here"); 109 assertTrue("cannot get element", empty.get("something") == "here"); 110 111 try { 112 new WeakHashMap(50, -0.5f); 113 fail("IllegalArgumentException expected"); 114 } catch (IllegalArgumentException e) { 115 //expected 116 } 117 } 118 119 /** 120 * java.util.WeakHashMap#WeakHashMap(java.util.Map) 121 */ test_ConstructorLjava_util_Map()122 public void test_ConstructorLjava_util_Map() { 123 Map mockMap = new MockMap(); 124 WeakHashMap map = new WeakHashMap(mockMap); 125 assertEquals("Size should be 0", 0, map.size()); 126 127 try { 128 new WeakHashMap(null); 129 fail("NullPointerException expected"); 130 } catch (NullPointerException e) { 131 //expected 132 } 133 } 134 135 /** 136 * java.util.WeakHashMap#clear() 137 */ test_clear()138 public void test_clear() { 139 // Test for method boolean java.util.WeakHashMap.clear() 140 whm = new WeakHashMap(); 141 for (int i = 0; i < 100; i++) 142 whm.put(keyArray[i], valueArray[i]); 143 whm.clear(); 144 assertTrue("Cleared map should be empty", whm.isEmpty()); 145 for (int i = 0; i < 100; i++) 146 assertNull("Cleared map should only return null", whm.get(keyArray[i])); 147 148 } 149 150 /** 151 * java.util.WeakHashMap#containsKey(java.lang.Object) 152 */ test_containsKeyLjava_lang_Object()153 public void test_containsKeyLjava_lang_Object() { 154 // Test for method boolean java.util.WeakHashMap.containsKey() 155 whm = new WeakHashMap(); 156 for (int i = 0; i < 100; i++) 157 whm.put(keyArray[i], valueArray[i]); 158 for (int i = 0; i < 100; i++) 159 assertTrue("Should contain referenced key", whm.containsKey(keyArray[i])); 160 keyArray[25] = null; 161 keyArray[50] = null; 162 } 163 164 /** 165 * java.util.WeakHashMap#containsValue(java.lang.Object) 166 */ test_containsValueLjava_lang_Object()167 public void test_containsValueLjava_lang_Object() { 168 // Test for method boolean java.util.WeakHashMap.containsValue() 169 whm = new WeakHashMap(); 170 for (int i = 0; i < 100; i++) 171 whm.put(keyArray[i], valueArray[i]); 172 for (int i = 0; i < 100; i++) 173 assertTrue("Should contain referenced value", whm.containsValue(valueArray[i])); 174 keyArray[25] = null; 175 keyArray[50] = null; 176 } 177 178 /** 179 * java.util.WeakHashMap#entrySet() 180 */ test_entrySet()181 public void test_entrySet() { 182 // Test for method java.util.Set java.util.WeakHashMap.entrySet() 183 whm = new WeakHashMap(); 184 for (int i = 0; i < 100; i++) 185 whm.put(keyArray[i], valueArray[i]); 186 List keys = Arrays.asList(keyArray); 187 List values = Arrays.asList(valueArray); 188 Set entrySet = whm.entrySet(); 189 assertTrue("Incorrect number of entries returned--wanted 100, got: " + entrySet.size(), 190 entrySet.size() == 100); 191 Iterator it = entrySet.iterator(); 192 while (it.hasNext()) { 193 Map.Entry entry = (Map.Entry) it.next(); 194 assertTrue("Invalid map entry returned--bad key", keys.contains(entry.getKey())); 195 assertTrue("Invalid map entry returned--bad key", values.contains(entry.getValue())); 196 } 197 keys = null; 198 values = null; 199 keyArray[50] = null; 200 201 FinalizationTester.induceFinalization(); 202 long startTime = System.currentTimeMillis(); 203 // We use a busy wait loop here since we cannot know when the ReferenceQueue 204 // daemon will enqueue the cleared references on their internal reference 205 // queues. The current timeout is 5 seconds. 206 do { 207 try { 208 Thread.sleep(100); 209 } catch (InterruptedException e) { 210 } 211 } while (entrySet.size() != 99 && 212 System.currentTimeMillis() - startTime < 5000); 213 214 assertEquals("Incorrect number of keys returned after gc,", 99, entrySet.size()); 215 } 216 217 /** 218 * java.util.WeakHashMap#isEmpty() 219 */ test_isEmpty()220 public void test_isEmpty() { 221 // Test for method boolean java.util.WeakHashMap.isEmpty() 222 whm = new WeakHashMap(); 223 assertTrue("New map should be empty", whm.isEmpty()); 224 Object myObject = new Object(); 225 whm.put(myObject, myObject); 226 assertTrue("Map should not be empty", !whm.isEmpty()); 227 whm.remove(myObject); 228 assertTrue("Map with elements removed should be empty", whm.isEmpty()); 229 } 230 231 /** 232 * java.util.WeakHashMap#put(java.lang.Object, java.lang.Object) 233 */ test_putLjava_lang_ObjectLjava_lang_Object()234 public void test_putLjava_lang_ObjectLjava_lang_Object() { 235 // Test for method java.lang.Object 236 // java.util.WeakHashMap.put(java.lang.Object, java.lang.Object) 237 WeakHashMap map = new WeakHashMap(); 238 map.put(null, "value"); // add null key 239 System.gc(); 240 System.gc(); 241 FinalizationTester.induceFinalization(); 242 map.remove("nothing"); // Cause objects in queue to be removed 243 assertEquals("null key was removed", 1, map.size()); 244 } 245 246 /** 247 * java.util.WeakHashMap#putAll(java.util.Map) 248 */ test_putAllLjava_util_Map()249 public void test_putAllLjava_util_Map() { 250 Map mockMap = new MockMap(); 251 WeakHashMap map = new WeakHashMap(); 252 map.putAll(mockMap); 253 assertEquals("Size should be 0", 0, map.size()); 254 255 try { 256 map.putAll(null); 257 fail("NullPointerException exected"); 258 } catch (NullPointerException e) { 259 //expected 260 } 261 } 262 263 /** 264 * java.util.WeakHashMap#remove(java.lang.Object) 265 */ test_removeLjava_lang_Object()266 public void test_removeLjava_lang_Object() { 267 // Test for method java.lang.Object 268 // java.util.WeakHashMap.remove(java.lang.Object) 269 whm = new WeakHashMap(); 270 for (int i = 0; i < 100; i++) 271 whm.put(keyArray[i], valueArray[i]); 272 273 assertTrue("Remove returned incorrect value", whm.remove(keyArray[25]) == valueArray[25]); 274 assertNull("Remove returned incorrect value", whm.remove(keyArray[25])); 275 assertEquals("Size should be 99 after remove", 99, whm.size()); 276 } 277 278 /** 279 * java.util.WeakHashMap#size() 280 */ test_size()281 public void test_size() { 282 whm = new WeakHashMap(); 283 assertEquals(0, whm.size()); 284 } 285 286 /** 287 * java.util.WeakHashMap#keySet() 288 */ test_keySet()289 public void test_keySet() { 290 // Test for method java.util.Set java.util.WeakHashMap.keySet() 291 whm = new WeakHashMap(); 292 for (int i = 0; i < 100; i++) 293 whm.put(keyArray[i], valueArray[i]); 294 295 List keys = Arrays.asList(keyArray); 296 List values = Arrays.asList(valueArray); 297 298 Set keySet = whm.keySet(); 299 assertEquals("Incorrect number of keys returned,", 100, keySet.size()); 300 Iterator it = keySet.iterator(); 301 while (it.hasNext()) { 302 Object key = it.next(); 303 assertTrue("Invalid map entry returned--bad key", keys.contains(key)); 304 } 305 keys = null; 306 values = null; 307 keyArray[50] = null; 308 309 FinalizationTester.induceFinalization(); 310 long startTime = System.currentTimeMillis(); 311 // We use a busy wait loop here since we cannot know when the ReferenceQueue 312 // daemon will enqueue the cleared references on their internal reference 313 // queues. 314 // The timeout after which the reference should be cleared. This test used to 315 // be flaky when it was set to 5 seconds. Daemons.MAX_FINALIZE_NANOS is 316 // currently 10 seconds so that seems like the correct value. 317 // We allow an extra 500msec buffer to minimize races between finalizer, 318 // keySet.size() evaluation and time check. 319 long timeout = 10000 + 500; 320 do { 321 try { 322 Thread.sleep(100); 323 } catch (InterruptedException e) { 324 } 325 } while (keySet.size() != 99 && 326 System.currentTimeMillis() - startTime < timeout); 327 328 assertEquals("Incorrect number of keys returned after gc,", 99, keySet.size()); 329 } 330 331 /** 332 * Regression test for HARMONY-3883 333 * 334 * java.util.WeakHashMap#keySet() 335 */ test_keySet_hasNext()336 public void test_keySet_hasNext() { 337 WeakHashMap map = new WeakHashMap(); 338 ConstantHashClass cl = new ConstantHashClass(2); 339 map.put(new ConstantHashClass(1), null); 340 map.put(cl, null); 341 map.put(new ConstantHashClass(3), null); 342 Iterator iter = map.keySet().iterator(); 343 iter.next(); 344 iter.next(); 345 int count = 0; 346 do { 347 System.gc(); 348 System.gc(); 349 FinalizationTester.induceFinalization(); 350 count++; 351 } while (count <= 5); 352 assertFalse("Wrong hasNext() value", iter.hasNext()); 353 } 354 355 static class ConstantHashClass { 356 private int id = 0; 357 ConstantHashClass(int id)358 public ConstantHashClass(int id) { 359 this.id = id; 360 } 361 hashCode()362 public int hashCode() { 363 return 0; 364 } 365 toString()366 public String toString() { 367 return "ConstantHashClass[id=" + id + "]"; 368 } 369 } 370 371 372 /** 373 * java.util.WeakHashMap#values() 374 */ test_values()375 public void test_values() { 376 // Test for method java.util.Set java.util.WeakHashMap.values() 377 whm = new WeakHashMap(); 378 for (int i = 0; i < 100; i++) 379 whm.put(keyArray[i], valueArray[i]); 380 381 List keys = Arrays.asList(keyArray); 382 List values = Arrays.asList(valueArray); 383 384 Collection valuesCollection = whm.values(); 385 assertEquals("Incorrect number of keys returned,", 100, valuesCollection.size()); 386 Iterator it = valuesCollection.iterator(); 387 while (it.hasNext()) { 388 Object value = it.next(); 389 assertTrue("Invalid map entry returned--bad value", values.contains(value)); 390 } 391 keys = null; 392 values = null; 393 keyArray[50] = null; 394 395 FinalizationTester.induceFinalization(); 396 long startTime = System.currentTimeMillis(); 397 // We use a busy wait loop here since we cannot know when the ReferenceQueue 398 // daemon will enqueue the cleared references on their internal reference 399 // queues. The current timeout is 5 seconds. 400 do { 401 try { 402 Thread.sleep(100); 403 } catch (InterruptedException e) { 404 } 405 } while (valuesCollection.size() != 99 && 406 System.currentTimeMillis() - startTime < 5000); 407 408 assertEquals("Incorrect number of keys returned after gc,", 99, valuesCollection.size()); 409 } 410 test_forEach()411 public void test_forEach() throws Exception { 412 WeakHashMap map = new WeakHashMap(); 413 for (int i = 0; i < 100; i++) 414 map.put(keyArray[i], valueArray[i]); 415 416 WeakHashMap output = new WeakHashMap(); 417 map.forEach((k, v) -> output.put(k,v)); 418 assertEquals(map, output); 419 420 HashSet setOutput = new HashSet(); 421 map.keySet().forEach((k) -> setOutput.add(k)); 422 assertEquals(map.keySet(), setOutput); 423 424 setOutput.clear(); 425 map.values().forEach((v) -> setOutput.add(v)); 426 assertEquals(new HashSet(map.values()), setOutput); 427 428 HashSet entrySetOutput = new HashSet(); 429 map.entrySet().forEach((v) -> entrySetOutput.add(v)); 430 assertEquals(map.entrySet(), entrySetOutput); 431 } 432 test_forEach_NPE()433 public void test_forEach_NPE() throws Exception { 434 WeakHashMap map = new WeakHashMap(); 435 try { 436 map.forEach(null); 437 fail(); 438 } catch(NullPointerException expected) {} 439 440 try { 441 map.keySet().forEach(null); 442 fail(); 443 } catch(NullPointerException expected) {} 444 445 try { 446 map.values().forEach(null); 447 fail(); 448 } catch(NullPointerException expected) {} 449 450 try { 451 map.entrySet().forEach(null); 452 fail(); 453 } catch(NullPointerException expected) {} 454 455 } 456 test_forEach_CME()457 public void test_forEach_CME() throws Exception { 458 WeakHashMap map = new WeakHashMap(); 459 for (int i = 0; i < 100; i++) 460 map.put(keyArray[i], valueArray[i]); 461 ArrayList<Object> processed = new ArrayList<>(); 462 try { 463 map.forEach(new java.util.function.BiConsumer<Object, Object>() { 464 @Override 465 public void accept(Object k, Object v) { 466 processed.add(k); 467 map.put("foo", v); 468 } 469 }); 470 fail(); 471 } catch(ConcurrentModificationException expected) {} 472 // We should get a CME and DO NOT continue forEach evaluation 473 assertEquals(1, processed.size()); 474 475 processed.clear(); 476 try { 477 map.keySet().forEach(new java.util.function.Consumer<Object>() { 478 @Override 479 public void accept(Object k) { 480 processed.add(k); 481 map.put("foo2", "boo"); 482 } 483 }); 484 fail(); 485 } catch(ConcurrentModificationException expected) {} 486 // We should get a CME and DO NOT continue forEach evaluation 487 assertEquals(1, processed.size()); 488 489 processed.clear(); 490 try { 491 map.values().forEach(new java.util.function.Consumer<Object>() { 492 @Override 493 public void accept(Object k) { 494 processed.add(k); 495 map.put("foo3", "boo"); 496 } 497 }); 498 fail(); 499 } catch(ConcurrentModificationException expected) {} 500 // We should get a CME and DO NOT continue forEach evaluation 501 assertEquals(1, processed.size()); 502 503 processed.clear(); 504 try { 505 map.entrySet().forEach(new java.util.function.Consumer<Map.Entry<Object, Object>>() { 506 @Override 507 public void accept(Map.Entry<Object, Object> k) { 508 processed.add(k.getKey()); 509 map.put("foo4", "boo"); 510 } 511 }); 512 fail(); 513 } catch(ConcurrentModificationException expected) {} 514 // We should get a CME and DO NOT continue forEach evaluation 515 assertEquals(1, processed.size()); 516 } 517 test_spliterator_keySet()518 public void test_spliterator_keySet() { 519 WeakHashMap<String, String> hashMap = new WeakHashMap<>(); 520 hashMap.put("a", "1"); 521 hashMap.put("b", "2"); 522 hashMap.put("c", "3"); 523 hashMap.put("d", "4"); 524 hashMap.put("e", "5"); 525 hashMap.put("f", "6"); 526 hashMap.put("g", "7"); 527 hashMap.put("h", "8"); 528 hashMap.put("i", "9"); 529 hashMap.put("j", "10"); 530 hashMap.put("k", "11"); 531 hashMap.put("l", "12"); 532 hashMap.put("m", "13"); 533 hashMap.put("n", "14"); 534 hashMap.put("o", "15"); 535 hashMap.put("p", "16"); 536 537 Set<String> keys = hashMap.keySet(); 538 ArrayList<String> expectedKeys = new ArrayList<>(keys); 539 540 SpliteratorTester.runBasicIterationTests_unordered(keys.spliterator(), expectedKeys, 541 String::compareTo); 542 SpliteratorTester.runBasicSplitTests(keys, expectedKeys); 543 SpliteratorTester.testSpliteratorNPE(keys.spliterator()); 544 545 assertTrue(keys.spliterator().hasCharacteristics(Spliterator.DISTINCT)); 546 547 SpliteratorTester.runDistinctTests(keys); 548 SpliteratorTester.assertSupportsTrySplit(keys); 549 } 550 test_spliterator_valueSet()551 public void test_spliterator_valueSet() { 552 WeakHashMap<String, String> hashMap = new WeakHashMap<>(); 553 hashMap.put("a", "1"); 554 hashMap.put("b", "2"); 555 hashMap.put("c", "3"); 556 hashMap.put("d", "4"); 557 hashMap.put("e", "5"); 558 hashMap.put("f", "6"); 559 hashMap.put("g", "7"); 560 hashMap.put("h", "8"); 561 hashMap.put("i", "9"); 562 hashMap.put("j", "10"); 563 hashMap.put("k", "11"); 564 hashMap.put("l", "12"); 565 hashMap.put("m", "13"); 566 hashMap.put("n", "14"); 567 hashMap.put("o", "15"); 568 hashMap.put("p", "16"); 569 570 Collection<String> values = hashMap.values(); 571 ArrayList<String> expectedValues = new ArrayList<>(values); 572 573 SpliteratorTester.runBasicIterationTests_unordered( 574 values.spliterator(), expectedValues, String::compareTo); 575 SpliteratorTester.runBasicSplitTests(values, expectedValues); 576 SpliteratorTester.testSpliteratorNPE(values.spliterator()); 577 } 578 test_spliterator_entrySet()579 public void test_spliterator_entrySet() { 580 WeakHashMap<String, String> hashMap = new WeakHashMap<>(); 581 hashMap.put("a", "1"); 582 hashMap.put("b", "2"); 583 hashMap.put("c", "3"); 584 hashMap.put("d", "4"); 585 hashMap.put("e", "5"); 586 hashMap.put("f", "6"); 587 hashMap.put("g", "7"); 588 hashMap.put("h", "8"); 589 hashMap.put("i", "9"); 590 hashMap.put("j", "10"); 591 hashMap.put("k", "11"); 592 hashMap.put("l", "12"); 593 hashMap.put("m", "13"); 594 hashMap.put("n", "14"); 595 hashMap.put("o", "15"); 596 hashMap.put("p", "16"); 597 598 Set<Map.Entry<String, String>> values = hashMap.entrySet(); 599 ArrayList<Map.Entry<String, String>> expectedValues = new ArrayList<>(values); 600 601 Comparator<Map.Entry<String, String>> comparator = 602 (a, b) -> (a.getKey().compareTo(b.getKey())); 603 604 SpliteratorTester.runBasicIterationTests_unordered(values.spliterator(), expectedValues, 605 (a, b) -> (a.getKey().compareTo(b.getKey()))); 606 SpliteratorTester.runBasicSplitTests(values, expectedValues, comparator); 607 SpliteratorTester.testSpliteratorNPE(values.spliterator()); 608 609 assertTrue(values.spliterator().hasCharacteristics(Spliterator.DISTINCT)); 610 611 SpliteratorTester.runDistinctTests(values); 612 SpliteratorTester.assertSupportsTrySplit(values); 613 } 614 615 /** 616 * Sets up the fixture, for example, open a network connection. This method 617 * is called before a test is executed. 618 */ setUp()619 protected void setUp() { 620 for (int i = 0; i < 100; i++) { 621 keyArray[i] = new Object(); 622 valueArray[i] = new Object(); 623 } 624 625 } 626 627 /** 628 * Tears down the fixture, for example, close a network connection. This 629 * method is called after a test is executed. 630 */ tearDown()631 protected void tearDown() { 632 } 633 } 634