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