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 package org.apache.commons.collections.map; 18 19 import java.io.Serializable; 20 import java.util.ArrayList; 21 import java.util.Collection; 22 import java.util.HashMap; 23 import java.util.Iterator; 24 import java.util.List; 25 import java.util.Map; 26 import java.util.Set; 27 28 import org.apache.commons.collections.AbstractTestObject; 29 import org.apache.commons.collections.BulkTest; 30 import org.apache.commons.collections.collection.AbstractTestCollection; 31 import org.apache.commons.collections.set.AbstractTestSet; 32 33 /** 34 * Abstract test class for {@link java.util.Map} methods and contracts. 35 * <p> 36 * The forces at work here are similar to those in {@link AbstractTestCollection}. 37 * If your class implements the full Map interface, including optional 38 * operations, simply extend this class, and implement the 39 * {@link #makeEmptyMap()} method. 40 * <p> 41 * On the other hand, if your map implementation is weird, you may have to 42 * override one or more of the other protected methods. They're described 43 * below. 44 * <p> 45 * <b>Entry Population Methods</b> 46 * <p> 47 * Override these methods if your map requires special entries: 48 * 49 * <ul> 50 * <li>{@link #getSampleKeys()} 51 * <li>{@link #getSampleValues()} 52 * <li>{@link #getNewSampleValues()} 53 * <li>{@link #getOtherKeys()} 54 * <li>{@link #getOtherValues()} 55 * </ul> 56 * 57 * <b>Supported Operation Methods</b> 58 * <p> 59 * Override these methods if your map doesn't support certain operations: 60 * 61 * <ul> 62 * <li> {@link #isPutAddSupported()} 63 * <li> {@link #isPutChangeSupported()} 64 * <li> {@link #isSetValueSupported()} 65 * <li> {@link #isRemoveSupported()} 66 * <li> {@link #isGetStructuralModify()} 67 * <li> {@link #isAllowDuplicateValues()} 68 * <li> {@link #isAllowNullKey()} 69 * <li> {@link #isAllowNullValue()} 70 * </ul> 71 * 72 * <b>Fixture Methods</b> 73 * <p> 74 * For tests on modification operations (puts and removes), fixtures are used 75 * to verify that that operation results in correct state for the map and its 76 * collection views. Basically, the modification is performed against your 77 * map implementation, and an identical modification is performed against 78 * a <I>confirmed</I> map implementation. A confirmed map implementation is 79 * something like <Code>java.util.HashMap</Code>, which is known to conform 80 * exactly to the {@link Map} contract. After the modification takes place 81 * on both your map implementation and the confirmed map implementation, the 82 * two maps are compared to see if their state is identical. The comparison 83 * also compares the collection views to make sure they're still the same.<P> 84 * 85 * The upshot of all that is that <I>any</I> test that modifies the map in 86 * <I>any</I> way will verify that <I>all</I> of the map's state is still 87 * correct, including the state of its collection views. So for instance 88 * if a key is removed by the map's key set's iterator, then the entry set 89 * is checked to make sure the key/value pair no longer appears.<P> 90 * 91 * The {@link #map} field holds an instance of your collection implementation. 92 * The {@link #entrySet}, {@link #keySet} and {@link #values} fields hold 93 * that map's collection views. And the {@link #confirmed} field holds 94 * an instance of the confirmed collection implementation. The 95 * {@link #resetEmpty()} and {@link #resetFull()} methods set these fields to 96 * empty or full maps, so that tests can proceed from a known state.<P> 97 * 98 * After a modification operation to both {@link #map} and {@link #confirmed}, 99 * the {@link #verify()} method is invoked to compare the results. The 100 * {@link #verify} method calls separate methods to verify the map and its three 101 * collection views ({@link #verifyMap}, {@link #verifyEntrySet}, 102 * {@link #verifyKeySet}, and {@link #verifyValues}). You may want to override 103 * one of the verification methodsto perform additional verifications. For 104 * instance, TestDoubleOrderedMap would want override its 105 * {@link #verifyValues()} method to verify that the values are unique and in 106 * ascending order.<P> 107 * 108 * <b>Other Notes</b> 109 * <p> 110 * If your {@link Map} fails one of these tests by design, you may still use 111 * this base set of cases. Simply override the test case (method) your map 112 * fails and/or the methods that define the assumptions used by the test 113 * cases. For example, if your map does not allow duplicate values, override 114 * {@link #isAllowDuplicateValues()} and have it return <code>false</code> 115 * 116 * @author Michael Smith 117 * @author Rodney Waldhoff 118 * @author Paul Jack 119 * @author Stephen Colebourne 120 * @version $Revision: 646780 $ $Date: 2008-04-10 14:48:07 +0200 (Thu, 10 Apr 2008) $ 121 */ 122 public abstract class AbstractTestMap extends AbstractTestObject { 123 124 /** 125 * JDK1.2 has bugs in null handling of Maps, especially HashMap.Entry.toString 126 * This avoids nulls for JDK1.2 127 */ 128 private static final boolean JDK12; 129 static { 130 String str = System.getProperty("java.version"); 131 JDK12 = str.startsWith("1.2"); 132 } 133 134 // These instance variables are initialized with the reset method. 135 // Tests for map methods that alter the map (put, putAll, remove) 136 // first call reset() to create the map and its views; then perform 137 // the modification on the map; perform the same modification on the 138 // confirmed; and then call verify() to ensure that the map is equal 139 // to the confirmed, that the already-constructed collection views 140 // are still equal to the confirmed's collection views. 141 142 143 /** Map created by reset(). */ 144 protected Map map; 145 146 /** Entry set of map created by reset(). */ 147 protected Set entrySet; 148 149 /** Key set of map created by reset(). */ 150 protected Set keySet; 151 152 /** Values collection of map created by reset(). */ 153 protected Collection values; 154 155 /** HashMap created by reset(). */ 156 protected Map confirmed; 157 158 /** 159 * JUnit constructor. 160 * 161 * @param testName the test name 162 */ AbstractTestMap(String testName)163 public AbstractTestMap(String testName) { 164 super(testName); 165 } 166 167 /** 168 * Returns true if the maps produced by 169 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 170 * support the <code>put</code> and <code>putAll</code> operations 171 * adding new mappings. 172 * <p> 173 * Default implementation returns true. 174 * Override if your collection class does not support put adding. 175 */ isPutAddSupported()176 public boolean isPutAddSupported() { 177 return true; 178 } 179 180 /** 181 * Returns true if the maps produced by 182 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 183 * support the <code>put</code> and <code>putAll</code> operations 184 * changing existing mappings. 185 * <p> 186 * Default implementation returns true. 187 * Override if your collection class does not support put changing. 188 */ isPutChangeSupported()189 public boolean isPutChangeSupported() { 190 return true; 191 } 192 193 /** 194 * Returns true if the maps produced by 195 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 196 * support the <code>setValue</code> operation on entrySet entries. 197 * <p> 198 * Default implementation returns isPutChangeSupported(). 199 * Override if your collection class does not support setValue but does 200 * support put changing. 201 */ isSetValueSupported()202 public boolean isSetValueSupported() { 203 return isPutChangeSupported(); 204 } 205 206 /** 207 * Returns true if the maps produced by 208 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 209 * support the <code>remove</code> and <code>clear</code> operations. 210 * <p> 211 * Default implementation returns true. 212 * Override if your collection class does not support removal operations. 213 */ isRemoveSupported()214 public boolean isRemoveSupported() { 215 return true; 216 } 217 218 /** 219 * Returns true if the maps produced by 220 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 221 * can cause structural modification on a get(). The example is LRUMap. 222 * <p> 223 * Default implementation returns false. 224 * Override if your map class structurally modifies on get. 225 */ isGetStructuralModify()226 public boolean isGetStructuralModify() { 227 return false; 228 } 229 230 /** 231 * Returns whether the sub map views of SortedMap are serializable. 232 * If the class being tested is based around a TreeMap then you should 233 * override and return false as TreeMap has a bug in deserialization. 234 * 235 * @return false 236 */ isSubMapViewsSerializable()237 public boolean isSubMapViewsSerializable() { 238 return true; 239 } 240 241 /** 242 * Returns true if the maps produced by 243 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 244 * supports null keys. 245 * <p> 246 * Default implementation returns true. 247 * Override if your collection class does not support null keys. 248 */ isAllowNullKey()249 public boolean isAllowNullKey() { 250 return true; 251 } 252 253 /** 254 * Returns true if the maps produced by 255 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 256 * supports null values. 257 * <p> 258 * Default implementation returns true. 259 * Override if your collection class does not support null values. 260 */ isAllowNullValue()261 public boolean isAllowNullValue() { 262 return true; 263 } 264 265 /** 266 * Returns true if the maps produced by 267 * {@link #makeEmptyMap()} and {@link #makeFullMap()} 268 * supports duplicate values. 269 * <p> 270 * Default implementation returns true. 271 * Override if your collection class does not support duplicate values. 272 */ isAllowDuplicateValues()273 public boolean isAllowDuplicateValues() { 274 return true; 275 } 276 277 /** 278 * Returns the set of keys in the mappings used to test the map. This 279 * method must return an array with the same length as {@link 280 * #getSampleValues()} and all array elements must be different. The 281 * default implementation constructs a set of String keys, and includes a 282 * single null key if {@link #isAllowNullKey()} returns <code>true</code>. 283 */ getSampleKeys()284 public Object[] getSampleKeys() { 285 Object[] result = new Object[] { 286 "blah", "foo", "bar", "baz", "tmp", "gosh", "golly", "gee", 287 "hello", "goodbye", "we'll", "see", "you", "all", "again", 288 "key", 289 "key2", 290 (isAllowNullKey() && !JDK12) ? null : "nonnullkey" 291 }; 292 return result; 293 } 294 295 getOtherKeys()296 public Object[] getOtherKeys() { 297 return getOtherNonNullStringElements(); 298 } 299 getOtherValues()300 public Object[] getOtherValues() { 301 return getOtherNonNullStringElements(); 302 } 303 304 /** 305 * Returns a list of string elements suitable for return by 306 * {@link #getOtherKeys()} or {@link #getOtherValues}. 307 * 308 * <p>Override getOtherElements to returnthe results of this method if your 309 * collection does not support heterogenous elements or the null element. 310 * </p> 311 */ getOtherNonNullStringElements()312 public Object[] getOtherNonNullStringElements() { 313 return new Object[] { 314 "For","then","despite",/* of */"space","I","would","be","brought", 315 "From","limits","far","remote","where","thou","dost","stay" 316 }; 317 } 318 319 /** 320 * Returns the set of values in the mappings used to test the map. This 321 * method must return an array with the same length as 322 * {@link #getSampleKeys()}. The default implementation constructs a set of 323 * String values and includes a single null value if 324 * {@link #isAllowNullValue()} returns <code>true</code>, and includes 325 * two values that are the same if {@link #isAllowDuplicateValues()} returns 326 * <code>true</code>. 327 */ getSampleValues()328 public Object[] getSampleValues() { 329 Object[] result = new Object[] { 330 "blahv", "foov", "barv", "bazv", "tmpv", "goshv", "gollyv", "geev", 331 "hellov", "goodbyev", "we'llv", "seev", "youv", "allv", "againv", 332 (isAllowNullValue() && !JDK12) ? null : "nonnullvalue", 333 "value", 334 (isAllowDuplicateValues()) ? "value" : "value2", 335 }; 336 return result; 337 } 338 339 /** 340 * Returns a the set of values that can be used to replace the values 341 * returned from {@link #getSampleValues()}. This method must return an 342 * array with the same length as {@link #getSampleValues()}. The values 343 * returned from this method should not be the same as those returned from 344 * {@link #getSampleValues()}. The default implementation constructs a 345 * set of String values and includes a single null value if 346 * {@link #isAllowNullValue()} returns <code>true</code>, and includes two values 347 * that are the same if {@link #isAllowDuplicateValues()} returns 348 * <code>true</code>. 349 */ getNewSampleValues()350 public Object[] getNewSampleValues() { 351 Object[] result = new Object[] { 352 (isAllowNullValue() && !JDK12 && isAllowDuplicateValues()) ? null : "newnonnullvalue", 353 "newvalue", 354 (isAllowDuplicateValues()) ? "newvalue" : "newvalue2", 355 "newblahv", "newfoov", "newbarv", "newbazv", "newtmpv", "newgoshv", 356 "newgollyv", "newgeev", "newhellov", "newgoodbyev", "newwe'llv", 357 "newseev", "newyouv", "newallv", "newagainv", 358 }; 359 return result; 360 } 361 362 /** 363 * Helper method to add all the mappings described by 364 * {@link #getSampleKeys()} and {@link #getSampleValues()}. 365 */ addSampleMappings(Map m)366 public void addSampleMappings(Map m) { 367 368 Object[] keys = getSampleKeys(); 369 Object[] values = getSampleValues(); 370 371 for(int i = 0; i < keys.length; i++) { 372 try { 373 m.put(keys[i], values[i]); 374 } catch (NullPointerException exception) { 375 assertTrue("NullPointerException only allowed to be thrown " + 376 "if either the key or value is null.", 377 keys[i] == null || values[i] == null); 378 379 assertTrue("NullPointerException on null key, but " + 380 "isAllowNullKey is not overridden to return false.", 381 keys[i] == null || !isAllowNullKey()); 382 383 assertTrue("NullPointerException on null value, but " + 384 "isAllowNullValue is not overridden to return false.", 385 values[i] == null || !isAllowNullValue()); 386 387 assertTrue("Unknown reason for NullPointer.", false); 388 } 389 } 390 assertEquals("size must reflect number of mappings added.", 391 keys.length, m.size()); 392 } 393 394 //----------------------------------------------------------------------- 395 /** 396 * Return a new, empty {@link Map} to be used for testing. 397 * 398 * @return the map to be tested 399 */ makeEmptyMap()400 public abstract Map makeEmptyMap(); 401 402 /** 403 * Return a new, populated map. The mappings in the map should match the 404 * keys and values returned from {@link #getSampleKeys()} and 405 * {@link #getSampleValues()}. The default implementation uses makeEmptyMap() 406 * and calls {@link #addSampleMappings} to add all the mappings to the 407 * map. 408 * 409 * @return the map to be tested 410 */ makeFullMap()411 public Map makeFullMap() { 412 Map m = makeEmptyMap(); 413 addSampleMappings(m); 414 return m; 415 } 416 417 /** 418 * Implements the superclass method to return the map to be tested. 419 * 420 * @return the map to be tested 421 */ makeObject()422 public Object makeObject() { 423 return makeEmptyMap(); 424 } 425 426 /** 427 * Override to return a map other than HashMap as the confirmed map. 428 * 429 * @return a map that is known to be valid 430 */ makeConfirmedMap()431 public Map makeConfirmedMap() { 432 return new HashMap(); 433 } 434 435 /** 436 * Creates a new Map Entry that is independent of the first and the map. 437 */ cloneMapEntry(Map.Entry entry)438 public Map.Entry cloneMapEntry(Map.Entry entry) { 439 HashMap map = new HashMap(); 440 map.put(entry.getKey(), entry.getValue()); 441 return (Map.Entry) map.entrySet().iterator().next(); 442 } 443 444 /** 445 * Gets the compatability version, needed for package access. 446 */ getCompatibilityVersion()447 public String getCompatibilityVersion() { 448 return super.getCompatibilityVersion(); 449 } 450 //----------------------------------------------------------------------- 451 /** 452 * Test to ensure the test setup is working properly. This method checks 453 * to ensure that the getSampleKeys and getSampleValues methods are 454 * returning results that look appropriate. That is, they both return a 455 * non-null array of equal length. The keys array must not have any 456 * duplicate values, and may only contain a (single) null key if 457 * isNullKeySupported() returns true. The values array must only have a null 458 * value if useNullValue() is true and may only have duplicate values if 459 * isAllowDuplicateValues() returns true. 460 */ testSampleMappings()461 public void testSampleMappings() { 462 Object[] keys = getSampleKeys(); 463 Object[] values = getSampleValues(); 464 Object[] newValues = getNewSampleValues(); 465 466 assertTrue("failure in test: Must have keys returned from " + 467 "getSampleKeys.", keys != null); 468 469 assertTrue("failure in test: Must have values returned from " + 470 "getSampleValues.", values != null); 471 472 // verify keys and values have equivalent lengths (in case getSampleX are 473 // overridden) 474 assertEquals("failure in test: not the same number of sample " + 475 "keys and values.", keys.length, values.length); 476 477 assertEquals("failure in test: not the same number of values and new values.", 478 values.length, newValues.length); 479 480 // verify there aren't duplicate keys, and check values 481 for(int i = 0; i < keys.length - 1; i++) { 482 for(int j = i + 1; j < keys.length; j++) { 483 assertTrue("failure in test: duplicate null keys.", 484 (keys[i] != null || keys[j] != null)); 485 assertTrue("failure in test: duplicate non-null key.", 486 (keys[i] == null || keys[j] == null || 487 (!keys[i].equals(keys[j]) && 488 !keys[j].equals(keys[i])))); 489 } 490 assertTrue("failure in test: found null key, but isNullKeySupported " + 491 "is false.", keys[i] != null || isAllowNullKey()); 492 assertTrue("failure in test: found null value, but isNullValueSupported " + 493 "is false.", values[i] != null || isAllowNullValue()); 494 assertTrue("failure in test: found null new value, but isNullValueSupported " + 495 "is false.", newValues[i] != null || isAllowNullValue()); 496 assertTrue("failure in test: values should not be the same as new value", 497 values[i] != newValues[i] && 498 (values[i] == null || !values[i].equals(newValues[i]))); 499 } 500 } 501 502 // tests begin here. Each test adds a little bit of tested functionality. 503 // Many methods assume previous methods passed. That is, they do not 504 // exhaustively recheck things that have already been checked in a previous 505 // test methods. 506 507 /** 508 * Test to ensure that makeEmptyMap and makeFull returns a new non-null 509 * map with each invocation. 510 */ testMakeMap()511 public void testMakeMap() { 512 Map em = makeEmptyMap(); 513 assertTrue("failure in test: makeEmptyMap must return a non-null map.", 514 em != null); 515 516 Map em2 = makeEmptyMap(); 517 assertTrue("failure in test: makeEmptyMap must return a non-null map.", 518 em != null); 519 520 assertTrue("failure in test: makeEmptyMap must return a new map " + 521 "with each invocation.", em != em2); 522 523 Map fm = makeFullMap(); 524 assertTrue("failure in test: makeFullMap must return a non-null map.", 525 fm != null); 526 527 Map fm2 = makeFullMap(); 528 assertTrue("failure in test: makeFullMap must return a non-null map.", 529 fm != null); 530 531 assertTrue("failure in test: makeFullMap must return a new map " + 532 "with each invocation.", fm != fm2); 533 } 534 535 /** 536 * Tests Map.isEmpty() 537 */ testMapIsEmpty()538 public void testMapIsEmpty() { 539 resetEmpty(); 540 assertEquals("Map.isEmpty() should return true with an empty map", 541 true, map.isEmpty()); 542 verify(); 543 544 resetFull(); 545 assertEquals("Map.isEmpty() should return false with a non-empty map", 546 false, map.isEmpty()); 547 verify(); 548 } 549 550 /** 551 * Tests Map.size() 552 */ testMapSize()553 public void testMapSize() { 554 resetEmpty(); 555 assertEquals("Map.size() should be 0 with an empty map", 556 0, map.size()); 557 verify(); 558 559 resetFull(); 560 assertEquals("Map.size() should equal the number of entries " + 561 "in the map", getSampleKeys().length, map.size()); 562 verify(); 563 } 564 565 /** 566 * Tests {@link Map#clear()}. If the map {@link #isRemoveSupported()} 567 * can add and remove elements}, then {@link Map#size()} and 568 * {@link Map#isEmpty()} are used to ensure that map has no elements after 569 * a call to clear. If the map does not support adding and removing 570 * elements, this method checks to ensure clear throws an 571 * UnsupportedOperationException. 572 */ testMapClear()573 public void testMapClear() { 574 if (!isRemoveSupported()) { 575 try { 576 resetFull(); 577 map.clear(); 578 fail("Expected UnsupportedOperationException on clear"); 579 } catch (UnsupportedOperationException ex) {} 580 return; 581 } 582 583 resetEmpty(); 584 map.clear(); 585 confirmed.clear(); 586 verify(); 587 588 resetFull(); 589 map.clear(); 590 confirmed.clear(); 591 verify(); 592 } 593 594 595 /** 596 * Tests Map.containsKey(Object) by verifying it returns false for all 597 * sample keys on a map created using an empty map and returns true for 598 * all sample keys returned on a full map. 599 */ testMapContainsKey()600 public void testMapContainsKey() { 601 Object[] keys = getSampleKeys(); 602 603 resetEmpty(); 604 for(int i = 0; i < keys.length; i++) { 605 assertTrue("Map must not contain key when map is empty", 606 !map.containsKey(keys[i])); 607 } 608 verify(); 609 610 resetFull(); 611 for(int i = 0; i < keys.length; i++) { 612 assertTrue("Map must contain key for a mapping in the map. " + 613 "Missing: " + keys[i], map.containsKey(keys[i])); 614 } 615 verify(); 616 } 617 618 /** 619 * Tests Map.containsValue(Object) by verifying it returns false for all 620 * sample values on an empty map and returns true for all sample values on 621 * a full map. 622 */ testMapContainsValue()623 public void testMapContainsValue() { 624 Object[] values = getSampleValues(); 625 626 resetEmpty(); 627 for(int i = 0; i < values.length; i++) { 628 assertTrue("Empty map must not contain value", 629 !map.containsValue(values[i])); 630 } 631 verify(); 632 633 resetFull(); 634 for(int i = 0; i < values.length; i++) { 635 assertTrue("Map must contain value for a mapping in the map.", 636 map.containsValue(values[i])); 637 } 638 verify(); 639 } 640 641 642 /** 643 * Tests Map.equals(Object) 644 */ testMapEquals()645 public void testMapEquals() { 646 resetEmpty(); 647 assertTrue("Empty maps unequal.", map.equals(confirmed)); 648 verify(); 649 650 resetFull(); 651 assertTrue("Full maps unequal.", map.equals(confirmed)); 652 verify(); 653 654 resetFull(); 655 // modify the HashMap created from the full map and make sure this 656 // change results in map.equals() to return false. 657 Iterator iter = confirmed.keySet().iterator(); 658 iter.next(); 659 iter.remove(); 660 assertTrue("Different maps equal.", !map.equals(confirmed)); 661 662 resetFull(); 663 assertTrue("equals(null) returned true.", !map.equals(null)); 664 assertTrue("equals(new Object()) returned true.", 665 !map.equals(new Object())); 666 verify(); 667 } 668 669 670 /** 671 * Tests Map.get(Object) 672 */ testMapGet()673 public void testMapGet() { 674 resetEmpty(); 675 676 Object[] keys = getSampleKeys(); 677 Object[] values = getSampleValues(); 678 679 for (int i = 0; i < keys.length; i++) { 680 assertTrue("Empty map.get() should return null.", 681 map.get(keys[i]) == null); 682 } 683 verify(); 684 685 resetFull(); 686 for (int i = 0; i < keys.length; i++) { 687 assertEquals("Full map.get() should return value from mapping.", 688 values[i], map.get(keys[i])); 689 } 690 } 691 692 /** 693 * Tests Map.hashCode() 694 */ testMapHashCode()695 public void testMapHashCode() { 696 resetEmpty(); 697 assertTrue("Empty maps have different hashCodes.", 698 map.hashCode() == confirmed.hashCode()); 699 700 resetFull(); 701 assertTrue("Equal maps have different hashCodes.", 702 map.hashCode() == confirmed.hashCode()); 703 } 704 705 /** 706 * Tests Map.toString(). Since the format of the string returned by the 707 * toString() method is not defined in the Map interface, there is no 708 * common way to test the results of the toString() method. Thereforce, 709 * it is encouraged that Map implementations override this test with one 710 * that checks the format matches any format defined in its API. This 711 * default implementation just verifies that the toString() method does 712 * not return null. 713 */ testMapToString()714 public void testMapToString() { 715 resetEmpty(); 716 assertTrue("Empty map toString() should not return null", 717 map.toString() != null); 718 verify(); 719 720 resetFull(); 721 assertTrue("Empty map toString() should not return null", 722 map.toString() != null); 723 verify(); 724 } 725 726 727 /** 728 * Compare the current serialized form of the Map 729 * against the canonical version in CVS. 730 */ testEmptyMapCompatibility()731 public void testEmptyMapCompatibility() throws Exception { 732 /** 733 * Create canonical objects with this code 734 Map map = makeEmptyMap(); 735 if (!(map instanceof Serializable)) return; 736 737 writeExternalFormToDisk((Serializable) map, getCanonicalEmptyCollectionName(map)); 738 */ 739 740 // test to make sure the canonical form has been preserved 741 Map map = makeEmptyMap(); 742 if (map instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) { 743 Map map2 = (Map) readExternalFormFromDisk(getCanonicalEmptyCollectionName(map)); 744 assertEquals("Map is empty", 0, map2.size()); 745 } 746 } 747 748 /** 749 * Compare the current serialized form of the Map 750 * against the canonical version in CVS. 751 */ testFullMapCompatibility()752 public void testFullMapCompatibility() throws Exception { 753 /** 754 * Create canonical objects with this code 755 Map map = makeFullMap(); 756 if (!(map instanceof Serializable)) return; 757 758 writeExternalFormToDisk((Serializable) map, getCanonicalFullCollectionName(map)); 759 */ 760 761 // test to make sure the canonical form has been preserved 762 Map map = makeFullMap(); 763 if (map instanceof Serializable && !skipSerializedCanonicalTests() && isTestSerialization()) { 764 Map map2 = (Map) readExternalFormFromDisk(getCanonicalFullCollectionName(map)); 765 assertEquals("Map is the right size", getSampleKeys().length, map2.size()); 766 } 767 } 768 769 /** 770 * Tests Map.put(Object, Object) 771 */ testMapPut()772 public void testMapPut() { 773 resetEmpty(); 774 Object[] keys = getSampleKeys(); 775 Object[] values = getSampleValues(); 776 Object[] newValues = getNewSampleValues(); 777 778 if (isPutAddSupported()) { 779 for (int i = 0; i < keys.length; i++) { 780 Object o = map.put(keys[i], values[i]); 781 confirmed.put(keys[i], values[i]); 782 verify(); 783 assertTrue("First map.put should return null", o == null); 784 assertTrue("Map should contain key after put", 785 map.containsKey(keys[i])); 786 assertTrue("Map should contain value after put", 787 map.containsValue(values[i])); 788 } 789 if (isPutChangeSupported()) { 790 for (int i = 0; i < keys.length; i++) { 791 Object o = map.put(keys[i], newValues[i]); 792 confirmed.put(keys[i], newValues[i]); 793 verify(); 794 assertEquals("Map.put should return previous value when changed", 795 values[i], o); 796 assertTrue("Map should still contain key after put when changed", 797 map.containsKey(keys[i])); 798 assertTrue("Map should contain new value after put when changed", 799 map.containsValue(newValues[i])); 800 801 // if duplicates are allowed, we're not guaranteed that the value 802 // no longer exists, so don't try checking that. 803 if (!isAllowDuplicateValues()) { 804 assertTrue("Map should not contain old value after put when changed", 805 !map.containsValue(values[i])); 806 } 807 } 808 } else { 809 try { 810 // two possible exception here, either valid 811 map.put(keys[0], newValues[0]); 812 fail("Expected IllegalArgumentException or UnsupportedOperationException on put (change)"); 813 } catch (IllegalArgumentException ex) { 814 } catch (UnsupportedOperationException ex) {} 815 } 816 817 } else if (isPutChangeSupported()) { 818 resetEmpty(); 819 try { 820 map.put(keys[0], values[0]); 821 fail("Expected UnsupportedOperationException or IllegalArgumentException on put (add) when fixed size"); 822 } catch (IllegalArgumentException ex) { 823 } catch (UnsupportedOperationException ex) { 824 } 825 826 resetFull(); 827 int i = 0; 828 for (Iterator it = map.keySet().iterator(); it.hasNext() && i < newValues.length; i++) { 829 Object key = it.next(); 830 Object o = map.put(key, newValues[i]); 831 Object value = confirmed.put(key, newValues[i]); 832 verify(); 833 assertEquals("Map.put should return previous value when changed", 834 value, o); 835 assertTrue("Map should still contain key after put when changed", 836 map.containsKey(key)); 837 assertTrue("Map should contain new value after put when changed", 838 map.containsValue(newValues[i])); 839 840 // if duplicates are allowed, we're not guaranteed that the value 841 // no longer exists, so don't try checking that. 842 if (!isAllowDuplicateValues()) { 843 assertTrue("Map should not contain old value after put when changed", 844 !map.containsValue(values[i])); 845 } 846 } 847 } else { 848 try { 849 map.put(keys[0], values[0]); 850 fail("Expected UnsupportedOperationException on put (add)"); 851 } catch (UnsupportedOperationException ex) {} 852 } 853 } 854 855 /** 856 * Tests Map.put(null, value) 857 */ testMapPutNullKey()858 public void testMapPutNullKey() { 859 resetFull(); 860 Object[] values = getSampleValues(); 861 862 if (isPutAddSupported()) { 863 if (isAllowNullKey()) { 864 map.put(null, values[0]); 865 } else { 866 try { 867 map.put(null, values[0]); 868 fail("put(null, value) should throw NPE/IAE"); 869 } catch (NullPointerException ex) { 870 } catch (IllegalArgumentException ex) {} 871 } 872 } 873 } 874 875 /** 876 * Tests Map.put(null, value) 877 */ testMapPutNullValue()878 public void testMapPutNullValue() { 879 resetFull(); 880 Object[] keys = getSampleKeys(); 881 882 if (isPutAddSupported()) { 883 if (isAllowNullValue()) { 884 map.put(keys[0], null); 885 } else { 886 try { 887 map.put(keys[0], null); 888 fail("put(key, null) should throw NPE/IAE"); 889 } catch (NullPointerException ex) { 890 } catch (IllegalArgumentException ex) {} 891 } 892 } 893 } 894 895 /** 896 * Tests Map.putAll(map) 897 */ testMapPutAll()898 public void testMapPutAll() { 899 if (!isPutAddSupported()) { 900 if (!isPutChangeSupported()) { 901 Map temp = makeFullMap(); 902 resetEmpty(); 903 try { 904 map.putAll(temp); 905 fail("Expected UnsupportedOperationException on putAll"); 906 } catch (UnsupportedOperationException ex) {} 907 } 908 return; 909 } 910 911 // check putAll OK adding empty map to empty map 912 resetEmpty(); 913 assertEquals(0, map.size()); 914 map.putAll(new HashMap()); 915 assertEquals(0, map.size()); 916 917 // check putAll OK adding empty map to non-empty map 918 resetFull(); 919 int size = map.size(); 920 map.putAll(new HashMap()); 921 assertEquals(size, map.size()); 922 923 // check putAll OK adding non-empty map to empty map 924 resetEmpty(); 925 Map m2 = makeFullMap(); 926 map.putAll(m2); 927 confirmed.putAll(m2); 928 verify(); 929 930 // check putAll OK adding non-empty JDK map to empty map 931 resetEmpty(); 932 m2 = makeConfirmedMap(); 933 Object[] keys = getSampleKeys(); 934 Object[] values = getSampleValues(); 935 for(int i = 0; i < keys.length; i++) { 936 m2.put(keys[i], values[i]); 937 } 938 map.putAll(m2); 939 confirmed.putAll(m2); 940 verify(); 941 942 // check putAll OK adding non-empty JDK map to non-empty map 943 resetEmpty(); 944 m2 = makeConfirmedMap(); 945 map.put(keys[0], values[0]); 946 confirmed.put(keys[0], values[0]); 947 verify(); 948 for(int i = 1; i < keys.length; i++) { 949 m2.put(keys[i], values[i]); 950 } 951 map.putAll(m2); 952 confirmed.putAll(m2); 953 verify(); 954 } 955 956 /** 957 * Tests Map.remove(Object) 958 */ testMapRemove()959 public void testMapRemove() { 960 if (!isRemoveSupported()) { 961 try { 962 resetFull(); 963 map.remove(map.keySet().iterator().next()); 964 fail("Expected UnsupportedOperationException on remove"); 965 } catch (UnsupportedOperationException ex) {} 966 return; 967 } 968 969 resetEmpty(); 970 971 Object[] keys = getSampleKeys(); 972 Object[] values = getSampleValues(); 973 for(int i = 0; i < keys.length; i++) { 974 Object o = map.remove(keys[i]); 975 assertTrue("First map.remove should return null", o == null); 976 } 977 verify(); 978 979 resetFull(); 980 981 for(int i = 0; i < keys.length; i++) { 982 Object o = map.remove(keys[i]); 983 confirmed.remove(keys[i]); 984 verify(); 985 986 assertEquals("map.remove with valid key should return value", 987 values[i], o); 988 } 989 990 Object[] other = getOtherKeys(); 991 992 resetFull(); 993 int size = map.size(); 994 for (int i = 0; i < other.length; i++) { 995 Object o = map.remove(other[i]); 996 assertEquals("map.remove for nonexistent key should return null", 997 o, null); 998 assertEquals("map.remove for nonexistent key should not " + 999 "shrink map", size, map.size()); 1000 } 1001 verify(); 1002 } 1003 1004 //----------------------------------------------------------------------- 1005 /** 1006 * Tests that the {@link Map#values} collection is backed by 1007 * the underlying map for clear(). 1008 */ testValuesClearChangesMap()1009 public void testValuesClearChangesMap() { 1010 if (!isRemoveSupported()) return; 1011 1012 // clear values, reflected in map 1013 resetFull(); 1014 Collection values = map.values(); 1015 assertTrue(map.size() > 0); 1016 assertTrue(values.size() > 0); 1017 values.clear(); 1018 assertTrue(map.size() == 0); 1019 assertTrue(values.size() == 0); 1020 1021 // clear map, reflected in values 1022 resetFull(); 1023 values = map.values(); 1024 assertTrue(map.size() > 0); 1025 assertTrue(values.size() > 0); 1026 map.clear(); 1027 assertTrue(map.size() == 0); 1028 assertTrue(values.size() == 0); 1029 } 1030 1031 /** 1032 * Tests that the {@link Map#keySet} collection is backed by 1033 * the underlying map for clear(). 1034 */ testKeySetClearChangesMap()1035 public void testKeySetClearChangesMap() { 1036 if (!isRemoveSupported()) return; 1037 1038 // clear values, reflected in map 1039 resetFull(); 1040 Set keySet = map.keySet(); 1041 assertTrue(map.size() > 0); 1042 assertTrue(keySet.size() > 0); 1043 keySet.clear(); 1044 assertTrue(map.size() == 0); 1045 assertTrue(keySet.size() == 0); 1046 1047 // clear map, reflected in values 1048 resetFull(); 1049 keySet = map.keySet(); 1050 assertTrue(map.size() > 0); 1051 assertTrue(keySet.size() > 0); 1052 map.clear(); 1053 assertTrue(map.size() == 0); 1054 assertTrue(keySet.size() == 0); 1055 } 1056 1057 /** 1058 * Tests that the {@link Map#entrySet()} collection is backed by 1059 * the underlying map for clear(). 1060 */ testEntrySetClearChangesMap()1061 public void testEntrySetClearChangesMap() { 1062 if (!isRemoveSupported()) return; 1063 1064 // clear values, reflected in map 1065 resetFull(); 1066 Set entrySet = map.entrySet(); 1067 assertTrue(map.size() > 0); 1068 assertTrue(entrySet.size() > 0); 1069 entrySet.clear(); 1070 assertTrue(map.size() == 0); 1071 assertTrue(entrySet.size() == 0); 1072 1073 // clear map, reflected in values 1074 resetFull(); 1075 entrySet = map.entrySet(); 1076 assertTrue(map.size() > 0); 1077 assertTrue(entrySet.size() > 0); 1078 map.clear(); 1079 assertTrue(map.size() == 0); 1080 assertTrue(entrySet.size() == 0); 1081 } 1082 1083 //----------------------------------------------------------------------- testEntrySetContains1()1084 public void testEntrySetContains1() { 1085 resetFull(); 1086 Set entrySet = map.entrySet(); 1087 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1088 assertEquals(true, entrySet.contains(entry)); 1089 } testEntrySetContains2()1090 public void testEntrySetContains2() { 1091 resetFull(); 1092 Set entrySet = map.entrySet(); 1093 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1094 Map.Entry test = cloneMapEntry(entry); 1095 assertEquals(true, entrySet.contains(test)); 1096 } testEntrySetContains3()1097 public void testEntrySetContains3() { 1098 resetFull(); 1099 Set entrySet = map.entrySet(); 1100 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1101 HashMap temp = new HashMap(); 1102 temp.put(entry.getKey(), "A VERY DIFFERENT VALUE"); 1103 Map.Entry test = (Map.Entry) temp.entrySet().iterator().next(); 1104 assertEquals(false, entrySet.contains(test)); 1105 } 1106 testEntrySetRemove1()1107 public void testEntrySetRemove1() { 1108 if (!isRemoveSupported()) return; 1109 resetFull(); 1110 int size = map.size(); 1111 Set entrySet = map.entrySet(); 1112 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1113 Object key = entry.getKey(); 1114 1115 assertEquals(true, entrySet.remove(entry)); 1116 assertEquals(false, map.containsKey(key)); 1117 assertEquals(size - 1, map.size()); 1118 } testEntrySetRemove2()1119 public void testEntrySetRemove2() { 1120 if (!isRemoveSupported()) return; 1121 resetFull(); 1122 int size = map.size(); 1123 Set entrySet = map.entrySet(); 1124 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1125 Object key = entry.getKey(); 1126 Map.Entry test = cloneMapEntry(entry); 1127 1128 assertEquals(true, entrySet.remove(test)); 1129 assertEquals(false, map.containsKey(key)); 1130 assertEquals(size - 1, map.size()); 1131 } testEntrySetRemove3()1132 public void testEntrySetRemove3() { 1133 if (!isRemoveSupported()) return; 1134 resetFull(); 1135 int size = map.size(); 1136 Set entrySet = map.entrySet(); 1137 Map.Entry entry = (Map.Entry) entrySet.iterator().next(); 1138 Object key = entry.getKey(); 1139 HashMap temp = new HashMap(); 1140 temp.put(entry.getKey(), "A VERY DIFFERENT VALUE"); 1141 Map.Entry test = (Map.Entry) temp.entrySet().iterator().next(); 1142 1143 assertEquals(false, entrySet.remove(test)); 1144 assertEquals(true, map.containsKey(key)); 1145 assertEquals(size, map.size()); 1146 } 1147 1148 //----------------------------------------------------------------------- 1149 /** 1150 * Tests that the {@link Map#values} collection is backed by 1151 * the underlying map by removing from the values collection 1152 * and testing if the value was removed from the map. 1153 * <p> 1154 * We should really test the "vice versa" case--that values removed 1155 * from the map are removed from the values collection--also, 1156 * but that's a more difficult test to construct (lacking a 1157 * "removeValue" method.) 1158 * </p> 1159 * <p> 1160 * See bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=9573"> 1161 * 9573</a>. 1162 * </p> 1163 */ testValuesRemoveChangesMap()1164 public void testValuesRemoveChangesMap() { 1165 resetFull(); 1166 Object[] sampleValues = getSampleValues(); 1167 Collection values = map.values(); 1168 for (int i = 0; i < sampleValues.length; i++) { 1169 if (map.containsValue(sampleValues[i])) { 1170 int j = 0; // loop counter prevents infinite loops when remove is broken 1171 while (values.contains(sampleValues[i]) && j < 10000) { 1172 try { 1173 values.remove(sampleValues[i]); 1174 } catch (UnsupportedOperationException e) { 1175 // if values.remove is unsupported, just skip this test 1176 return; 1177 } 1178 j++; 1179 } 1180 assertTrue("values().remove(obj) is broken", j < 10000); 1181 assertTrue( 1182 "Value should have been removed from the underlying map.", 1183 !map.containsValue(sampleValues[i])); 1184 } 1185 } 1186 } 1187 1188 /** 1189 * Tests that the {@link Map#keySet} set is backed by 1190 * the underlying map by removing from the keySet set 1191 * and testing if the key was removed from the map. 1192 */ testKeySetRemoveChangesMap()1193 public void testKeySetRemoveChangesMap() { 1194 resetFull(); 1195 Object[] sampleKeys = getSampleKeys(); 1196 Set keys = map.keySet(); 1197 for (int i = 0; i < sampleKeys.length; i++) { 1198 try { 1199 keys.remove(sampleKeys[i]); 1200 } catch (UnsupportedOperationException e) { 1201 // if key.remove is unsupported, just skip this test 1202 return; 1203 } 1204 assertTrue( 1205 "Key should have been removed from the underlying map.", 1206 !map.containsKey(sampleKeys[i])); 1207 } 1208 } 1209 1210 // TODO: Need: 1211 // testValuesRemovedFromEntrySetAreRemovedFromMap 1212 // same for EntrySet/KeySet/values's 1213 // Iterator.remove, removeAll, retainAll 1214 1215 1216 /** 1217 * Utility methods to create an array of Map.Entry objects 1218 * out of the given key and value arrays.<P> 1219 * 1220 * @param keys the array of keys 1221 * @param values the array of values 1222 * @return an array of Map.Entry of those keys to those values 1223 */ makeEntryArray(Object[] keys, Object[] values)1224 private Map.Entry[] makeEntryArray(Object[] keys, Object[] values) { 1225 Map.Entry[] result = new Map.Entry[keys.length]; 1226 for (int i = 0; i < keys.length; i++) { 1227 Map map = makeConfirmedMap(); 1228 map.put(keys[i], values[i]); 1229 result[i] = (Map.Entry) map.entrySet().iterator().next(); 1230 } 1231 return result; 1232 } 1233 1234 1235 /** 1236 * Bulk test {@link Map#entrySet()}. This method runs through all of 1237 * the tests in {@link AbstractTestSet}. 1238 * After modification operations, {@link #verify()} is invoked to ensure 1239 * that the map and the other collection views are still valid. 1240 * 1241 * @return a {@link AbstractTestSet} instance for testing the map's entry set 1242 */ bulkTestMapEntrySet()1243 public BulkTest bulkTestMapEntrySet() { 1244 return new TestMapEntrySet(); 1245 } 1246 1247 public class TestMapEntrySet extends AbstractTestSet { TestMapEntrySet()1248 public TestMapEntrySet() { 1249 super("MapEntrySet"); 1250 } 1251 1252 // Have to implement manually; entrySet doesn't support addAll getFullElements()1253 public Object[] getFullElements() { 1254 Object[] k = getSampleKeys(); 1255 Object[] v = getSampleValues(); 1256 return makeEntryArray(k, v); 1257 } 1258 1259 // Have to implement manually; entrySet doesn't support addAll getOtherElements()1260 public Object[] getOtherElements() { 1261 Object[] k = getOtherKeys(); 1262 Object[] v = getOtherValues(); 1263 return makeEntryArray(k, v); 1264 } 1265 makeEmptySet()1266 public Set makeEmptySet() { 1267 return makeEmptyMap().entrySet(); 1268 } 1269 makeFullSet()1270 public Set makeFullSet() { 1271 return makeFullMap().entrySet(); 1272 } 1273 isAddSupported()1274 public boolean isAddSupported() { 1275 // Collection views don't support add operations. 1276 return false; 1277 } isRemoveSupported()1278 public boolean isRemoveSupported() { 1279 // Entry set should only support remove if map does 1280 return AbstractTestMap.this.isRemoveSupported(); 1281 } isGetStructuralModify()1282 public boolean isGetStructuralModify() { 1283 return AbstractTestMap.this.isGetStructuralModify(); 1284 } isTestSerialization()1285 public boolean isTestSerialization() { 1286 return false; 1287 } 1288 resetFull()1289 public void resetFull() { 1290 AbstractTestMap.this.resetFull(); 1291 collection = map.entrySet(); 1292 TestMapEntrySet.this.confirmed = AbstractTestMap.this.confirmed.entrySet(); 1293 } 1294 resetEmpty()1295 public void resetEmpty() { 1296 AbstractTestMap.this.resetEmpty(); 1297 collection = map.entrySet(); 1298 TestMapEntrySet.this.confirmed = AbstractTestMap.this.confirmed.entrySet(); 1299 } 1300 testMapEntrySetIteratorEntry()1301 public void testMapEntrySetIteratorEntry() { 1302 resetFull(); 1303 Iterator it = collection.iterator(); 1304 int count = 0; 1305 while (it.hasNext()) { 1306 Map.Entry entry = (Map.Entry) it.next(); 1307 assertEquals(true, AbstractTestMap.this.map.containsKey(entry.getKey())); 1308 assertEquals(true, AbstractTestMap.this.map.containsValue(entry.getValue())); 1309 if (isGetStructuralModify() == false) { 1310 assertEquals(AbstractTestMap.this.map.get(entry.getKey()), entry.getValue()); 1311 } 1312 count++; 1313 } 1314 assertEquals(collection.size(), count); 1315 } 1316 testMapEntrySetIteratorEntrySetValue()1317 public void testMapEntrySetIteratorEntrySetValue() { 1318 Object key1 = getSampleKeys()[0]; 1319 Object key2 = (getSampleKeys().length ==1 ? getSampleKeys()[0] : getSampleKeys()[1]); 1320 Object newValue1 = getNewSampleValues()[0]; 1321 Object newValue2 = (getNewSampleValues().length ==1 ? getNewSampleValues()[0] : getNewSampleValues()[1]); 1322 1323 resetFull(); 1324 // explicitly get entries as sample values/keys are connected for some maps 1325 // such as BeanMap 1326 Iterator it = TestMapEntrySet.this.collection.iterator(); 1327 Map.Entry entry1 = getEntry(it, key1); 1328 it = TestMapEntrySet.this.collection.iterator(); 1329 Map.Entry entry2 = getEntry(it, key2); 1330 Iterator itConfirmed = TestMapEntrySet.this.confirmed.iterator(); 1331 Map.Entry entryConfirmed1 = getEntry(itConfirmed, key1); 1332 itConfirmed = TestMapEntrySet.this.confirmed.iterator(); 1333 Map.Entry entryConfirmed2 = getEntry(itConfirmed, key2); 1334 verify(); 1335 1336 if (isSetValueSupported() == false) { 1337 try { 1338 entry1.setValue(newValue1); 1339 } catch (UnsupportedOperationException ex) { 1340 } 1341 return; 1342 } 1343 1344 entry1.setValue(newValue1); 1345 entryConfirmed1.setValue(newValue1); 1346 assertEquals(newValue1, entry1.getValue()); 1347 assertEquals(true, AbstractTestMap.this.map.containsKey(entry1.getKey())); 1348 assertEquals(true, AbstractTestMap.this.map.containsValue(newValue1)); 1349 assertEquals(newValue1, AbstractTestMap.this.map.get(entry1.getKey())); 1350 verify(); 1351 1352 entry1.setValue(newValue1); 1353 entryConfirmed1.setValue(newValue1); 1354 assertEquals(newValue1, entry1.getValue()); 1355 assertEquals(true, AbstractTestMap.this.map.containsKey(entry1.getKey())); 1356 assertEquals(true, AbstractTestMap.this.map.containsValue(newValue1)); 1357 assertEquals(newValue1, AbstractTestMap.this.map.get(entry1.getKey())); 1358 verify(); 1359 1360 entry2.setValue(newValue2); 1361 entryConfirmed2.setValue(newValue2); 1362 assertEquals(newValue2, entry2.getValue()); 1363 assertEquals(true, AbstractTestMap.this.map.containsKey(entry2.getKey())); 1364 assertEquals(true, AbstractTestMap.this.map.containsValue(newValue2)); 1365 assertEquals(newValue2, AbstractTestMap.this.map.get(entry2.getKey())); 1366 verify(); 1367 } 1368 getEntry(Iterator itConfirmed, Object key)1369 public Map.Entry getEntry(Iterator itConfirmed, Object key) { 1370 Map.Entry entry = null; 1371 while (itConfirmed.hasNext()) { 1372 Map.Entry temp = (Map.Entry) itConfirmed.next(); 1373 if (temp.getKey() == null) { 1374 if (key == null) { 1375 entry = temp; 1376 break; 1377 } 1378 } else if (temp.getKey().equals(key)) { 1379 entry = temp; 1380 break; 1381 } 1382 } 1383 assertNotNull("No matching entry in map for key '" + key + "'", entry); 1384 return entry; 1385 } 1386 testMapEntrySetRemoveNonMapEntry()1387 public void testMapEntrySetRemoveNonMapEntry() { 1388 if (isRemoveSupported() == false) return; 1389 resetFull(); 1390 assertEquals(false, getSet().remove(null)); 1391 assertEquals(false, getSet().remove(new Object())); 1392 } 1393 verify()1394 public void verify() { 1395 super.verify(); 1396 AbstractTestMap.this.verify(); 1397 } 1398 } 1399 1400 1401 /** 1402 * Bulk test {@link Map#keySet()}. This method runs through all of 1403 * the tests in {@link AbstractTestSet}. 1404 * After modification operations, {@link #verify()} is invoked to ensure 1405 * that the map and the other collection views are still valid. 1406 * 1407 * @return a {@link AbstractTestSet} instance for testing the map's key set 1408 */ bulkTestMapKeySet()1409 public BulkTest bulkTestMapKeySet() { 1410 return new TestMapKeySet(); 1411 } 1412 1413 public class TestMapKeySet extends AbstractTestSet { TestMapKeySet()1414 public TestMapKeySet() { 1415 super(""); 1416 } getFullElements()1417 public Object[] getFullElements() { 1418 return getSampleKeys(); 1419 } 1420 getOtherElements()1421 public Object[] getOtherElements() { 1422 return getOtherKeys(); 1423 } 1424 makeEmptySet()1425 public Set makeEmptySet() { 1426 return makeEmptyMap().keySet(); 1427 } 1428 makeFullSet()1429 public Set makeFullSet() { 1430 return makeFullMap().keySet(); 1431 } 1432 isNullSupported()1433 public boolean isNullSupported() { 1434 return AbstractTestMap.this.isAllowNullKey(); 1435 } isAddSupported()1436 public boolean isAddSupported() { 1437 return false; 1438 } isRemoveSupported()1439 public boolean isRemoveSupported() { 1440 return AbstractTestMap.this.isRemoveSupported(); 1441 } isTestSerialization()1442 public boolean isTestSerialization() { 1443 return false; 1444 } 1445 resetEmpty()1446 public void resetEmpty() { 1447 AbstractTestMap.this.resetEmpty(); 1448 collection = map.keySet(); 1449 TestMapKeySet.this.confirmed = AbstractTestMap.this.confirmed.keySet(); 1450 } 1451 resetFull()1452 public void resetFull() { 1453 AbstractTestMap.this.resetFull(); 1454 collection = map.keySet(); 1455 TestMapKeySet.this.confirmed = AbstractTestMap.this.confirmed.keySet(); 1456 } 1457 verify()1458 public void verify() { 1459 super.verify(); 1460 AbstractTestMap.this.verify(); 1461 } 1462 } 1463 1464 1465 /** 1466 * Bulk test {@link Map#values()}. This method runs through all of 1467 * the tests in {@link AbstractTestCollection}. 1468 * After modification operations, {@link #verify()} is invoked to ensure 1469 * that the map and the other collection views are still valid. 1470 * 1471 * @return a {@link AbstractTestCollection} instance for testing the map's 1472 * values collection 1473 */ bulkTestMapValues()1474 public BulkTest bulkTestMapValues() { 1475 return new TestMapValues(); 1476 } 1477 1478 public class TestMapValues extends AbstractTestCollection { TestMapValues()1479 public TestMapValues() { 1480 super(""); 1481 } 1482 getFullElements()1483 public Object[] getFullElements() { 1484 return getSampleValues(); 1485 } 1486 getOtherElements()1487 public Object[] getOtherElements() { 1488 return getOtherValues(); 1489 } 1490 makeCollection()1491 public Collection makeCollection() { 1492 return makeEmptyMap().values(); 1493 } 1494 makeFullCollection()1495 public Collection makeFullCollection() { 1496 return makeFullMap().values(); 1497 } 1498 isNullSupported()1499 public boolean isNullSupported() { 1500 return AbstractTestMap.this.isAllowNullKey(); 1501 } isAddSupported()1502 public boolean isAddSupported() { 1503 return false; 1504 } isRemoveSupported()1505 public boolean isRemoveSupported() { 1506 return AbstractTestMap.this.isRemoveSupported(); 1507 } isTestSerialization()1508 public boolean isTestSerialization() { 1509 return false; 1510 } 1511 areEqualElementsDistinguishable()1512 public boolean areEqualElementsDistinguishable() { 1513 // equal values are associated with different keys, so they are 1514 // distinguishable. 1515 return true; 1516 } 1517 makeConfirmedCollection()1518 public Collection makeConfirmedCollection() { 1519 // never gets called, reset methods are overridden 1520 return null; 1521 } 1522 makeConfirmedFullCollection()1523 public Collection makeConfirmedFullCollection() { 1524 // never gets called, reset methods are overridden 1525 return null; 1526 } 1527 resetFull()1528 public void resetFull() { 1529 AbstractTestMap.this.resetFull(); 1530 collection = map.values(); 1531 TestMapValues.this.confirmed = AbstractTestMap.this.confirmed.values(); 1532 } 1533 resetEmpty()1534 public void resetEmpty() { 1535 AbstractTestMap.this.resetEmpty(); 1536 collection = map.values(); 1537 TestMapValues.this.confirmed = AbstractTestMap.this.confirmed.values(); 1538 } 1539 verify()1540 public void verify() { 1541 super.verify(); 1542 AbstractTestMap.this.verify(); 1543 } 1544 1545 // TODO: should test that a remove on the values collection view 1546 // removes the proper mapping and not just any mapping that may have 1547 // the value equal to the value returned from the values iterator. 1548 } 1549 1550 1551 /** 1552 * Resets the {@link #map}, {@link #entrySet}, {@link #keySet}, 1553 * {@link #values} and {@link #confirmed} fields to empty. 1554 */ resetEmpty()1555 public void resetEmpty() { 1556 this.map = makeEmptyMap(); 1557 views(); 1558 this.confirmed = makeConfirmedMap(); 1559 } 1560 1561 /** 1562 * Resets the {@link #map}, {@link #entrySet}, {@link #keySet}, 1563 * {@link #values} and {@link #confirmed} fields to full. 1564 */ resetFull()1565 public void resetFull() { 1566 this.map = makeFullMap(); 1567 views(); 1568 this.confirmed = makeConfirmedMap(); 1569 Object[] k = getSampleKeys(); 1570 Object[] v = getSampleValues(); 1571 for (int i = 0; i < k.length; i++) { 1572 confirmed.put(k[i], v[i]); 1573 } 1574 } 1575 1576 1577 /** 1578 * Resets the collection view fields. 1579 */ views()1580 private void views() { 1581 this.keySet = map.keySet(); 1582 this.values = map.values(); 1583 this.entrySet = map.entrySet(); 1584 } 1585 1586 1587 /** 1588 * Verifies that {@link #map} is still equal to {@link #confirmed}. 1589 * This method checks that the map is equal to the HashMap, 1590 * <I>and</I> that the map's collection views are still equal to 1591 * the HashMap's collection views. An <Code>equals</Code> test 1592 * is done on the maps and their collection views; their size and 1593 * <Code>isEmpty</Code> results are compared; their hashCodes are 1594 * compared; and <Code>containsAll</Code> tests are run on the 1595 * collection views. 1596 */ verify()1597 public void verify() { 1598 verifyMap(); 1599 verifyEntrySet(); 1600 verifyKeySet(); 1601 verifyValues(); 1602 } 1603 verifyMap()1604 public void verifyMap() { 1605 int size = confirmed.size(); 1606 boolean empty = confirmed.isEmpty(); 1607 assertEquals("Map should be same size as HashMap", 1608 size, map.size()); 1609 assertEquals("Map should be empty if HashMap is", 1610 empty, map.isEmpty()); 1611 assertEquals("hashCodes should be the same", 1612 confirmed.hashCode(), map.hashCode()); 1613 // this fails for LRUMap because confirmed.equals() somehow modifies 1614 // map, causing concurrent modification exceptions. 1615 //assertEquals("Map should still equal HashMap", confirmed, map); 1616 // this works though and performs the same verification: 1617 assertTrue("Map should still equal HashMap", map.equals(confirmed)); 1618 // TODO: this should really be reexamined to figure out why LRU map 1619 // behaves like it does (the equals shouldn't modify since all accesses 1620 // by the confirmed collection should be through an iterator, thus not 1621 // causing LRUMap to change). 1622 } 1623 verifyEntrySet()1624 public void verifyEntrySet() { 1625 int size = confirmed.size(); 1626 boolean empty = confirmed.isEmpty(); 1627 assertEquals("entrySet should be same size as HashMap's" + 1628 "\nTest: " + entrySet + "\nReal: " + confirmed.entrySet(), 1629 size, entrySet.size()); 1630 assertEquals("entrySet should be empty if HashMap is" + 1631 "\nTest: " + entrySet + "\nReal: " + confirmed.entrySet(), 1632 empty, entrySet.isEmpty()); 1633 assertTrue("entrySet should contain all HashMap's elements" + 1634 "\nTest: " + entrySet + "\nReal: " + confirmed.entrySet(), 1635 entrySet.containsAll(confirmed.entrySet())); 1636 assertEquals("entrySet hashCodes should be the same" + 1637 "\nTest: " + entrySet + "\nReal: " + confirmed.entrySet(), 1638 confirmed.entrySet().hashCode(), entrySet.hashCode()); 1639 assertEquals("Map's entry set should still equal HashMap's", 1640 confirmed.entrySet(), entrySet); 1641 } 1642 verifyKeySet()1643 public void verifyKeySet() { 1644 int size = confirmed.size(); 1645 boolean empty = confirmed.isEmpty(); 1646 assertEquals("keySet should be same size as HashMap's" + 1647 "\nTest: " + keySet + "\nReal: " + confirmed.keySet(), 1648 size, keySet.size()); 1649 assertEquals("keySet should be empty if HashMap is" + 1650 "\nTest: " + keySet + "\nReal: " + confirmed.keySet(), 1651 empty, keySet.isEmpty()); 1652 assertTrue("keySet should contain all HashMap's elements" + 1653 "\nTest: " + keySet + "\nReal: " + confirmed.keySet(), 1654 keySet.containsAll(confirmed.keySet())); 1655 assertEquals("keySet hashCodes should be the same" + 1656 "\nTest: " + keySet + "\nReal: " + confirmed.keySet(), 1657 confirmed.keySet().hashCode(), keySet.hashCode()); 1658 assertEquals("Map's key set should still equal HashMap's", 1659 confirmed.keySet(), keySet); 1660 } 1661 verifyValues()1662 public void verifyValues() { 1663 List known = new ArrayList(confirmed.values()); 1664 List test = new ArrayList(values); 1665 1666 int size = confirmed.size(); 1667 boolean empty = confirmed.isEmpty(); 1668 assertEquals("values should be same size as HashMap's" + 1669 "\nTest: " + test + "\nReal: " + known, 1670 size, values.size()); 1671 assertEquals("values should be empty if HashMap is" + 1672 "\nTest: " + test + "\nReal: " + known, 1673 empty, values.isEmpty()); 1674 assertTrue("values should contain all HashMap's elements" + 1675 "\nTest: " + test + "\nReal: " + known, 1676 test.containsAll(known)); 1677 assertTrue("values should contain all HashMap's elements" + 1678 "\nTest: " + test + "\nReal: " + known, 1679 known.containsAll(test)); 1680 // originally coded to use a HashBag, but now separate jar so... 1681 for (Iterator it = known.iterator(); it.hasNext();) { 1682 boolean removed = test.remove(it.next()); 1683 assertTrue("Map's values should still equal HashMap's", removed); 1684 } 1685 assertTrue("Map's values should still equal HashMap's", test.isEmpty()); 1686 } 1687 1688 1689 /** 1690 * Erases any leftover instance variables by setting them to null. 1691 */ tearDown()1692 public void tearDown() throws Exception { 1693 map = null; 1694 keySet = null; 1695 entrySet = null; 1696 values = null; 1697 confirmed = null; 1698 } 1699 1700 } 1701