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