001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing;
018
019import static java.util.Collections.singleton;
020
021import com.google.common.annotations.GwtCompatible;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.Collections;
025import java.util.HashSet;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Map.Entry;
029import java.util.Set;
030import junit.framework.TestCase;
031
032/**
033 * Tests representing the contract of {@link Map}. Concrete subclasses of this base class test
034 * conformance of concrete {@link Map} subclasses to that contract.
035 *
036 * @param <K> the type of keys used by the maps under test
037 * @param <V> the type of mapped values used the maps under test
038 * @author George van den Driessche
039 */
040// TODO: Descriptive assertion messages, with hints as to probable fixes.
041// TODO: Add another constructor parameter indicating whether the class under test is ordered, and
042// check the order if so.
043// TODO: Refactor to share code with SetTestBuilder etc.
044@GwtCompatible
045public abstract class MapInterfaceTest<K, V> extends TestCase {
046
047  /** A key type that is not assignable to any classes but Object. */
048  private static final class IncompatibleKeyType {
049    @Override
050    public String toString() {
051      return "IncompatibleKeyType";
052    }
053  }
054
055  protected final boolean supportsPut;
056  protected final boolean supportsRemove;
057  protected final boolean supportsClear;
058  protected final boolean allowsNullKeys;
059  protected final boolean allowsNullValues;
060  protected final boolean supportsIteratorRemove;
061
062  /**
063   * Creates a new, empty instance of the class under test.
064   *
065   * @return a new, empty map instance.
066   * @throws UnsupportedOperationException if it's not possible to make an empty instance of the
067   *     class under test.
068   */
069  protected abstract Map<K, V> makeEmptyMap() throws UnsupportedOperationException;
070
071  /**
072   * Creates a new, non-empty instance of the class under test.
073   *
074   * @return a new, non-empty map instance.
075   * @throws UnsupportedOperationException if it's not possible to make a non-empty instance of the
076   *     class under test.
077   */
078  protected abstract Map<K, V> makePopulatedMap() throws UnsupportedOperationException;
079
080  /**
081   * Creates a new key that is not expected to be found in {@link #makePopulatedMap()}.
082   *
083   * @return a key.
084   * @throws UnsupportedOperationException if it's not possible to make a key that will not be found
085   *     in the map.
086   */
087  protected abstract K getKeyNotInPopulatedMap() throws UnsupportedOperationException;
088
089  /**
090   * Creates a new value that is not expected to be found in {@link #makePopulatedMap()}.
091   *
092   * @return a value.
093   * @throws UnsupportedOperationException if it's not possible to make a value that will not be
094   *     found in the map.
095   */
096  protected abstract V getValueNotInPopulatedMap() throws UnsupportedOperationException;
097
098  /**
099   * Constructor that assigns {@code supportsIteratorRemove} the same value as {@code
100   * supportsRemove}.
101   */
102  protected MapInterfaceTest(
103      boolean allowsNullKeys,
104      boolean allowsNullValues,
105      boolean supportsPut,
106      boolean supportsRemove,
107      boolean supportsClear) {
108    this(
109        allowsNullKeys,
110        allowsNullValues,
111        supportsPut,
112        supportsRemove,
113        supportsClear,
114        supportsRemove);
115  }
116
117  /** Constructor with an explicit {@code supportsIteratorRemove} parameter. */
118  protected MapInterfaceTest(
119      boolean allowsNullKeys,
120      boolean allowsNullValues,
121      boolean supportsPut,
122      boolean supportsRemove,
123      boolean supportsClear,
124      boolean supportsIteratorRemove) {
125    this.supportsPut = supportsPut;
126    this.supportsRemove = supportsRemove;
127    this.supportsClear = supportsClear;
128    this.allowsNullKeys = allowsNullKeys;
129    this.allowsNullValues = allowsNullValues;
130    this.supportsIteratorRemove = supportsIteratorRemove;
131  }
132
133  /**
134   * Used by tests that require a map, but don't care whether it's populated or not.
135   *
136   * @return a new map instance.
137   */
138  protected Map<K, V> makeEitherMap() {
139    try {
140      return makePopulatedMap();
141    } catch (UnsupportedOperationException e) {
142      return makeEmptyMap();
143    }
144  }
145
146  protected final boolean supportsValuesHashCode(Map<K, V> map) {
147    // get the first non-null value
148    Collection<V> values = map.values();
149    for (V value : values) {
150      if (value != null) {
151        try {
152          int unused = value.hashCode();
153        } catch (Exception e) {
154          return false;
155        }
156        return true;
157      }
158    }
159    return true;
160  }
161
162  /**
163   * Checks all the properties that should always hold of a map. Also calls {@link
164   * #assertMoreInvariants} to check invariants that are peculiar to specific implementations.
165   *
166   * @see #assertMoreInvariants
167   * @param map the map to check.
168   */
169  protected final void assertInvariants(Map<K, V> map) {
170    Set<K> keySet = map.keySet();
171    Collection<V> valueCollection = map.values();
172    Set<Entry<K, V>> entrySet = map.entrySet();
173
174    assertEquals(map.size() == 0, map.isEmpty());
175    assertEquals(map.size(), keySet.size());
176    assertEquals(keySet.size() == 0, keySet.isEmpty());
177    assertEquals(!keySet.isEmpty(), keySet.iterator().hasNext());
178
179    int expectedKeySetHash = 0;
180    for (K key : keySet) {
181      V value = map.get(key);
182      expectedKeySetHash += key != null ? key.hashCode() : 0;
183      assertTrue(map.containsKey(key));
184      assertTrue(map.containsValue(value));
185      assertTrue(valueCollection.contains(value));
186      assertTrue(valueCollection.containsAll(Collections.singleton(value)));
187      assertTrue(entrySet.contains(mapEntry(key, value)));
188      assertTrue(allowsNullKeys || (key != null));
189    }
190    assertEquals(expectedKeySetHash, keySet.hashCode());
191
192    assertEquals(map.size(), valueCollection.size());
193    assertEquals(valueCollection.size() == 0, valueCollection.isEmpty());
194    assertEquals(!valueCollection.isEmpty(), valueCollection.iterator().hasNext());
195    for (V value : valueCollection) {
196      assertTrue(map.containsValue(value));
197      assertTrue(allowsNullValues || (value != null));
198    }
199
200    assertEquals(map.size(), entrySet.size());
201    assertEquals(entrySet.size() == 0, entrySet.isEmpty());
202    assertEquals(!entrySet.isEmpty(), entrySet.iterator().hasNext());
203    assertEntrySetNotContainsString(entrySet);
204
205    boolean supportsValuesHashCode = supportsValuesHashCode(map);
206    if (supportsValuesHashCode) {
207      int expectedEntrySetHash = 0;
208      for (Entry<K, V> entry : entrySet) {
209        assertTrue(map.containsKey(entry.getKey()));
210        assertTrue(map.containsValue(entry.getValue()));
211        int expectedHash =
212            (entry.getKey() == null ? 0 : entry.getKey().hashCode())
213                ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode());
214        assertEquals(expectedHash, entry.hashCode());
215        expectedEntrySetHash += expectedHash;
216      }
217      assertEquals(expectedEntrySetHash, entrySet.hashCode());
218      assertTrue(entrySet.containsAll(new HashSet<Entry<K, V>>(entrySet)));
219      assertTrue(entrySet.equals(new HashSet<Entry<K, V>>(entrySet)));
220    }
221
222    Object[] entrySetToArray1 = entrySet.toArray();
223    assertEquals(map.size(), entrySetToArray1.length);
224    assertTrue(Arrays.asList(entrySetToArray1).containsAll(entrySet));
225
226    Entry<?, ?>[] entrySetToArray2 = new Entry<?, ?>[map.size() + 2];
227    entrySetToArray2[map.size()] = mapEntry("foo", 1);
228    assertSame(entrySetToArray2, entrySet.toArray(entrySetToArray2));
229    assertNull(entrySetToArray2[map.size()]);
230    assertTrue(Arrays.asList(entrySetToArray2).containsAll(entrySet));
231
232    Object[] valuesToArray1 = valueCollection.toArray();
233    assertEquals(map.size(), valuesToArray1.length);
234    assertTrue(Arrays.asList(valuesToArray1).containsAll(valueCollection));
235
236    Object[] valuesToArray2 = new Object[map.size() + 2];
237    valuesToArray2[map.size()] = "foo";
238    assertSame(valuesToArray2, valueCollection.toArray(valuesToArray2));
239    assertNull(valuesToArray2[map.size()]);
240    assertTrue(Arrays.asList(valuesToArray2).containsAll(valueCollection));
241
242    if (supportsValuesHashCode) {
243      int expectedHash = 0;
244      for (Entry<K, V> entry : entrySet) {
245        expectedHash += entry.hashCode();
246      }
247      assertEquals(expectedHash, map.hashCode());
248    }
249
250    assertMoreInvariants(map);
251  }
252
253  @SuppressWarnings("CollectionIncompatibleType")
254  private void assertEntrySetNotContainsString(Set<Entry<K, V>> entrySet) {
255    // Very unlikely that a buggy collection would ever return true. It might accidentally throw.
256    assertFalse(entrySet.contains("foo"));
257  }
258
259  /**
260   * Override this to check invariants which should hold true for a particular implementation, but
261   * which are not generally applicable to every instance of Map.
262   *
263   * @param map the map whose additional invariants to check.
264   */
265  protected void assertMoreInvariants(Map<K, V> map) {}
266
267  public void testClear() {
268    Map<K, V> map;
269    try {
270      map = makePopulatedMap();
271    } catch (UnsupportedOperationException e) {
272      return;
273    }
274
275    if (supportsClear) {
276      map.clear();
277      assertTrue(map.isEmpty());
278    } else {
279      try {
280        map.clear();
281        fail("Expected UnsupportedOperationException.");
282      } catch (UnsupportedOperationException expected) {
283      }
284    }
285    assertInvariants(map);
286  }
287
288  public void testContainsKey() {
289    Map<K, V> map;
290    K unmappedKey;
291    try {
292      map = makePopulatedMap();
293      unmappedKey = getKeyNotInPopulatedMap();
294    } catch (UnsupportedOperationException e) {
295      return;
296    }
297    assertFalse(map.containsKey(unmappedKey));
298    try {
299      assertFalse(map.containsKey(new IncompatibleKeyType()));
300    } catch (ClassCastException tolerated) {
301    }
302    assertTrue(map.containsKey(map.keySet().iterator().next()));
303    if (allowsNullKeys) {
304      boolean unused = map.containsKey(null);
305    } else {
306      try {
307        boolean unused2 = map.containsKey(null);
308      } catch (NullPointerException optional) {
309      }
310    }
311    assertInvariants(map);
312  }
313
314  public void testContainsValue() {
315    Map<K, V> map;
316    V unmappedValue;
317    try {
318      map = makePopulatedMap();
319      unmappedValue = getValueNotInPopulatedMap();
320    } catch (UnsupportedOperationException e) {
321      return;
322    }
323    assertFalse(map.containsValue(unmappedValue));
324    assertTrue(map.containsValue(map.values().iterator().next()));
325    if (allowsNullValues) {
326      boolean unused = map.containsValue(null);
327    } else {
328      try {
329        boolean unused2 = map.containsKey(null);
330      } catch (NullPointerException optional) {
331      }
332    }
333    assertInvariants(map);
334  }
335
336  public void testEntrySet() {
337    Map<K, V> map;
338    Set<Entry<K, V>> entrySet;
339    try {
340      map = makePopulatedMap();
341    } catch (UnsupportedOperationException e) {
342      return;
343    }
344    assertInvariants(map);
345
346    entrySet = map.entrySet();
347    K unmappedKey;
348    V unmappedValue;
349    try {
350      unmappedKey = getKeyNotInPopulatedMap();
351      unmappedValue = getValueNotInPopulatedMap();
352    } catch (UnsupportedOperationException e) {
353      return;
354    }
355    for (Entry<K, V> entry : entrySet) {
356      assertFalse(unmappedKey.equals(entry.getKey()));
357      assertFalse(unmappedValue.equals(entry.getValue()));
358    }
359  }
360
361  public void testEntrySetForEmptyMap() {
362    Map<K, V> map;
363    try {
364      map = makeEmptyMap();
365    } catch (UnsupportedOperationException e) {
366      return;
367    }
368    assertInvariants(map);
369  }
370
371  public void testEntrySetContainsEntryIncompatibleKey() {
372    Map<K, V> map;
373    Set<Entry<K, V>> entrySet;
374    try {
375      map = makeEitherMap();
376    } catch (UnsupportedOperationException e) {
377      return;
378    }
379    assertInvariants(map);
380
381    entrySet = map.entrySet();
382    V unmappedValue;
383    try {
384      unmappedValue = getValueNotInPopulatedMap();
385    } catch (UnsupportedOperationException e) {
386      return;
387    }
388    Entry<IncompatibleKeyType, V> entry = mapEntry(new IncompatibleKeyType(), unmappedValue);
389    try {
390      assertFalse(entrySet.contains(entry));
391    } catch (ClassCastException tolerated) {
392    }
393  }
394
395  public void testEntrySetContainsEntryNullKeyPresent() {
396    if (!allowsNullKeys || !supportsPut) {
397      return;
398    }
399    Map<K, V> map;
400    Set<Entry<K, V>> entrySet;
401    try {
402      map = makeEitherMap();
403    } catch (UnsupportedOperationException e) {
404      return;
405    }
406    assertInvariants(map);
407
408    entrySet = map.entrySet();
409    V unmappedValue;
410    try {
411      unmappedValue = getValueNotInPopulatedMap();
412    } catch (UnsupportedOperationException e) {
413      return;
414    }
415
416    map.put(null, unmappedValue);
417    Entry<K, V> entry = mapEntry(null, unmappedValue);
418    assertTrue(entrySet.contains(entry));
419    assertFalse(entrySet.contains(mapEntry(null, null)));
420  }
421
422  public void testEntrySetContainsEntryNullKeyMissing() {
423    Map<K, V> map;
424    Set<Entry<K, V>> entrySet;
425    try {
426      map = makeEitherMap();
427    } catch (UnsupportedOperationException e) {
428      return;
429    }
430    assertInvariants(map);
431
432    entrySet = map.entrySet();
433    V unmappedValue;
434    try {
435      unmappedValue = getValueNotInPopulatedMap();
436    } catch (UnsupportedOperationException e) {
437      return;
438    }
439    Entry<K, V> entry = mapEntry(null, unmappedValue);
440    try {
441      assertFalse(entrySet.contains(entry));
442    } catch (NullPointerException e) {
443      assertFalse(allowsNullKeys);
444    }
445    try {
446      assertFalse(entrySet.contains(mapEntry(null, null)));
447    } catch (NullPointerException e) {
448      assertFalse(allowsNullKeys && allowsNullValues);
449    }
450  }
451
452  public void testEntrySetIteratorRemove() {
453    Map<K, V> map;
454    try {
455      map = makePopulatedMap();
456    } catch (UnsupportedOperationException e) {
457      return;
458    }
459
460    Set<Entry<K, V>> entrySet = map.entrySet();
461    Iterator<Entry<K, V>> iterator = entrySet.iterator();
462    if (supportsIteratorRemove) {
463      int initialSize = map.size();
464      Entry<K, V> entry = iterator.next();
465      Entry<K, V> entryCopy = Helpers.mapEntry(entry.getKey(), entry.getValue());
466
467      iterator.remove();
468      assertEquals(initialSize - 1, map.size());
469
470      // Use "entryCopy" instead of "entry" because "entry" might be invalidated after
471      // iterator.remove().
472      assertFalse(entrySet.contains(entryCopy));
473      assertInvariants(map);
474      try {
475        iterator.remove();
476        fail("Expected IllegalStateException.");
477      } catch (IllegalStateException expected) {
478      }
479    } else {
480      try {
481        iterator.next();
482        iterator.remove();
483        fail("Expected UnsupportedOperationException.");
484      } catch (UnsupportedOperationException expected) {
485      }
486    }
487    assertInvariants(map);
488  }
489
490  public void testEntrySetRemove() {
491    Map<K, V> map;
492    try {
493      map = makePopulatedMap();
494    } catch (UnsupportedOperationException e) {
495      return;
496    }
497
498    Set<Entry<K, V>> entrySet = map.entrySet();
499    if (supportsRemove) {
500      int initialSize = map.size();
501      boolean didRemove = entrySet.remove(entrySet.iterator().next());
502      assertTrue(didRemove);
503      assertEquals(initialSize - 1, map.size());
504    } else {
505      try {
506        entrySet.remove(entrySet.iterator().next());
507        fail("Expected UnsupportedOperationException.");
508      } catch (UnsupportedOperationException expected) {
509      }
510    }
511    assertInvariants(map);
512  }
513
514  public void testEntrySetRemoveMissingKey() {
515    Map<K, V> map;
516    K key;
517    try {
518      map = makeEitherMap();
519      key = getKeyNotInPopulatedMap();
520    } catch (UnsupportedOperationException e) {
521      return;
522    }
523
524    Set<Entry<K, V>> entrySet = map.entrySet();
525    Entry<K, V> entry = mapEntry(key, getValueNotInPopulatedMap());
526    int initialSize = map.size();
527    if (supportsRemove) {
528      boolean didRemove = entrySet.remove(entry);
529      assertFalse(didRemove);
530    } else {
531      try {
532        boolean didRemove = entrySet.remove(entry);
533        assertFalse(didRemove);
534      } catch (UnsupportedOperationException optional) {
535      }
536    }
537    assertEquals(initialSize, map.size());
538    assertFalse(map.containsKey(key));
539    assertInvariants(map);
540  }
541
542  public void testEntrySetRemoveDifferentValue() {
543    Map<K, V> map;
544    try {
545      map = makePopulatedMap();
546    } catch (UnsupportedOperationException e) {
547      return;
548    }
549
550    Set<Entry<K, V>> entrySet = map.entrySet();
551    K key = map.keySet().iterator().next();
552    Entry<K, V> entry = mapEntry(key, getValueNotInPopulatedMap());
553    int initialSize = map.size();
554    if (supportsRemove) {
555      boolean didRemove = entrySet.remove(entry);
556      assertFalse(didRemove);
557    } else {
558      try {
559        boolean didRemove = entrySet.remove(entry);
560        assertFalse(didRemove);
561      } catch (UnsupportedOperationException optional) {
562      }
563    }
564    assertEquals(initialSize, map.size());
565    assertTrue(map.containsKey(key));
566    assertInvariants(map);
567  }
568
569  public void testEntrySetRemoveNullKeyPresent() {
570    if (!allowsNullKeys || !supportsPut || !supportsRemove) {
571      return;
572    }
573    Map<K, V> map;
574    Set<Entry<K, V>> entrySet;
575    try {
576      map = makeEitherMap();
577    } catch (UnsupportedOperationException e) {
578      return;
579    }
580    assertInvariants(map);
581
582    entrySet = map.entrySet();
583    V unmappedValue;
584    try {
585      unmappedValue = getValueNotInPopulatedMap();
586    } catch (UnsupportedOperationException e) {
587      return;
588    }
589
590    map.put(null, unmappedValue);
591    assertEquals(unmappedValue, map.get(null));
592    assertTrue(map.containsKey(null));
593    Entry<K, V> entry = mapEntry(null, unmappedValue);
594    assertTrue(entrySet.remove(entry));
595    assertNull(map.get(null));
596    assertFalse(map.containsKey(null));
597  }
598
599  public void testEntrySetRemoveNullKeyMissing() {
600    Map<K, V> map;
601    try {
602      map = makeEitherMap();
603    } catch (UnsupportedOperationException e) {
604      return;
605    }
606
607    Set<Entry<K, V>> entrySet = map.entrySet();
608    Entry<K, V> entry = mapEntry(null, getValueNotInPopulatedMap());
609    int initialSize = map.size();
610    if (supportsRemove) {
611      try {
612        boolean didRemove = entrySet.remove(entry);
613        assertFalse(didRemove);
614      } catch (NullPointerException e) {
615        assertFalse(allowsNullKeys);
616      }
617    } else {
618      try {
619        boolean didRemove = entrySet.remove(entry);
620        assertFalse(didRemove);
621      } catch (UnsupportedOperationException optional) {
622      }
623    }
624    assertEquals(initialSize, map.size());
625    assertInvariants(map);
626  }
627
628  public void testEntrySetRemoveAll() {
629    Map<K, V> map;
630    try {
631      map = makePopulatedMap();
632    } catch (UnsupportedOperationException e) {
633      return;
634    }
635
636    Set<Entry<K, V>> entrySet = map.entrySet();
637
638    Entry<K, V> entryToRemove = entrySet.iterator().next();
639    Set<Entry<K, V>> entriesToRemove = singleton(entryToRemove);
640    if (supportsRemove) {
641      // We use a copy of "entryToRemove" in the assertion because "entryToRemove" might be
642      // invalidated and have undefined behavior after entrySet.removeAll(entriesToRemove),
643      // for example entryToRemove.getValue() might be null.
644      Entry<K, V> entryToRemoveCopy =
645          Helpers.mapEntry(entryToRemove.getKey(), entryToRemove.getValue());
646
647      int initialSize = map.size();
648      boolean didRemove = entrySet.removeAll(entriesToRemove);
649      assertTrue(didRemove);
650      assertEquals(initialSize - entriesToRemove.size(), map.size());
651
652      // Use "entryToRemoveCopy" instead of "entryToRemove" because it might be invalidated and
653      // have undefined behavior after entrySet.removeAll(entriesToRemove),
654      assertFalse(entrySet.contains(entryToRemoveCopy));
655    } else {
656      try {
657        entrySet.removeAll(entriesToRemove);
658        fail("Expected UnsupportedOperationException.");
659      } catch (UnsupportedOperationException expected) {
660      }
661    }
662    assertInvariants(map);
663  }
664
665  public void testEntrySetRemoveAllNullFromEmpty() {
666    Map<K, V> map;
667    try {
668      map = makeEmptyMap();
669    } catch (UnsupportedOperationException e) {
670      return;
671    }
672
673    Set<Entry<K, V>> entrySet = map.entrySet();
674    if (supportsRemove) {
675      try {
676        entrySet.removeAll(null);
677        fail("Expected NullPointerException.");
678      } catch (NullPointerException expected) {
679      }
680    } else {
681      try {
682        entrySet.removeAll(null);
683        fail("Expected UnsupportedOperationException or NullPointerException.");
684      } catch (UnsupportedOperationException | NullPointerException e) {
685        // Expected.
686      }
687    }
688    assertInvariants(map);
689  }
690
691  public void testEntrySetRetainAll() {
692    Map<K, V> map;
693    try {
694      map = makePopulatedMap();
695    } catch (UnsupportedOperationException e) {
696      return;
697    }
698
699    Set<Entry<K, V>> entrySet = map.entrySet();
700    Set<Entry<K, V>> entriesToRetain = singleton(entrySet.iterator().next());
701    if (supportsRemove) {
702      boolean shouldRemove = (entrySet.size() > entriesToRetain.size());
703      boolean didRemove = entrySet.retainAll(entriesToRetain);
704      assertEquals(shouldRemove, didRemove);
705      assertEquals(entriesToRetain.size(), map.size());
706      for (Entry<K, V> entry : entriesToRetain) {
707        assertTrue(entrySet.contains(entry));
708      }
709    } else {
710      try {
711        entrySet.retainAll(entriesToRetain);
712        fail("Expected UnsupportedOperationException.");
713      } catch (UnsupportedOperationException expected) {
714      }
715    }
716    assertInvariants(map);
717  }
718
719  public void testEntrySetRetainAllNullFromEmpty() {
720    Map<K, V> map;
721    try {
722      map = makeEmptyMap();
723    } catch (UnsupportedOperationException e) {
724      return;
725    }
726
727    Set<Entry<K, V>> entrySet = map.entrySet();
728    if (supportsRemove) {
729      try {
730        entrySet.retainAll(null);
731        // Returning successfully is not ideal, but tolerated.
732      } catch (NullPointerException expected) {
733      }
734    } else {
735      try {
736        entrySet.retainAll(null);
737        // We have to tolerate a successful return (Sun bug 4802647)
738      } catch (UnsupportedOperationException | NullPointerException e) {
739        // Expected.
740      }
741    }
742    assertInvariants(map);
743  }
744
745  public void testEntrySetClear() {
746    Map<K, V> map;
747    try {
748      map = makePopulatedMap();
749    } catch (UnsupportedOperationException e) {
750      return;
751    }
752
753    Set<Entry<K, V>> entrySet = map.entrySet();
754    if (supportsClear) {
755      entrySet.clear();
756      assertTrue(entrySet.isEmpty());
757    } else {
758      try {
759        entrySet.clear();
760        fail("Expected UnsupportedOperationException.");
761      } catch (UnsupportedOperationException expected) {
762      }
763    }
764    assertInvariants(map);
765  }
766
767  public void testEntrySetAddAndAddAll() {
768    Map<K, V> map = makeEitherMap();
769
770    Set<Entry<K, V>> entrySet = map.entrySet();
771    Entry<K, V> entryToAdd = mapEntry(null, null);
772    try {
773      entrySet.add(entryToAdd);
774      fail("Expected UnsupportedOperationException or NullPointerException.");
775    } catch (UnsupportedOperationException | NullPointerException e) {
776      // Expected.
777    }
778    assertInvariants(map);
779
780    try {
781      entrySet.addAll(singleton(entryToAdd));
782      fail("Expected UnsupportedOperationException or NullPointerException.");
783    } catch (UnsupportedOperationException | NullPointerException e) {
784      // Expected.
785    }
786    assertInvariants(map);
787  }
788
789  public void testEntrySetSetValue() {
790    // TODO: Investigate the extent to which, in practice, maps that support
791    // put() also support Entry.setValue().
792    if (!supportsPut) {
793      return;
794    }
795
796    Map<K, V> map;
797    V valueToSet;
798    try {
799      map = makePopulatedMap();
800      valueToSet = getValueNotInPopulatedMap();
801    } catch (UnsupportedOperationException e) {
802      return;
803    }
804
805    Set<Entry<K, V>> entrySet = map.entrySet();
806    Entry<K, V> entry = entrySet.iterator().next();
807    V oldValue = entry.getValue();
808    V returnedValue = entry.setValue(valueToSet);
809    assertEquals(oldValue, returnedValue);
810    assertTrue(entrySet.contains(mapEntry(entry.getKey(), valueToSet)));
811    assertEquals(valueToSet, map.get(entry.getKey()));
812    assertInvariants(map);
813  }
814
815  public void testEntrySetSetValueSameValue() {
816    // TODO: Investigate the extent to which, in practice, maps that support
817    // put() also support Entry.setValue().
818    if (!supportsPut) {
819      return;
820    }
821
822    Map<K, V> map;
823    try {
824      map = makePopulatedMap();
825    } catch (UnsupportedOperationException e) {
826      return;
827    }
828
829    Set<Entry<K, V>> entrySet = map.entrySet();
830    Entry<K, V> entry = entrySet.iterator().next();
831    V oldValue = entry.getValue();
832    V returnedValue = entry.setValue(oldValue);
833    assertEquals(oldValue, returnedValue);
834    assertTrue(entrySet.contains(mapEntry(entry.getKey(), oldValue)));
835    assertEquals(oldValue, map.get(entry.getKey()));
836    assertInvariants(map);
837  }
838
839  public void testEqualsForEqualMap() {
840    Map<K, V> map;
841    try {
842      map = makePopulatedMap();
843    } catch (UnsupportedOperationException e) {
844      return;
845    }
846
847    // Explicitly call `equals`; `assertEquals` might return fast
848    assertTrue(map.equals(map));
849    assertTrue(makePopulatedMap().equals(map));
850    assertFalse(map.equals(Collections.emptyMap()));
851    // no-inspection ObjectEqualsNull
852    assertFalse(map.equals(null));
853  }
854
855  public void testEqualsForLargerMap() {
856    if (!supportsPut) {
857      return;
858    }
859
860    Map<K, V> map;
861    Map<K, V> largerMap;
862    try {
863      map = makePopulatedMap();
864      largerMap = makePopulatedMap();
865      largerMap.put(getKeyNotInPopulatedMap(), getValueNotInPopulatedMap());
866    } catch (UnsupportedOperationException e) {
867      return;
868    }
869
870    assertFalse(map.equals(largerMap));
871  }
872
873  public void testEqualsForSmallerMap() {
874    if (!supportsRemove) {
875      return;
876    }
877
878    Map<K, V> map;
879    Map<K, V> smallerMap;
880    try {
881      map = makePopulatedMap();
882      smallerMap = makePopulatedMap();
883      smallerMap.remove(smallerMap.keySet().iterator().next());
884    } catch (UnsupportedOperationException e) {
885      return;
886    }
887
888    assertFalse(map.equals(smallerMap));
889  }
890
891  public void testEqualsForEmptyMap() {
892    Map<K, V> map;
893    try {
894      map = makeEmptyMap();
895    } catch (UnsupportedOperationException e) {
896      return;
897    }
898
899    // Explicitly call `equals`; `assertEquals` might return fast
900    assertTrue(map.equals(map));
901    assertTrue(makeEmptyMap().equals(map));
902    assertEquals(Collections.emptyMap(), map);
903    assertFalse(map.equals(Collections.emptySet()));
904    // noinspection ObjectEqualsNull
905    assertFalse(map.equals(null));
906  }
907
908  public void testGet() {
909    Map<K, V> map;
910    try {
911      map = makePopulatedMap();
912    } catch (UnsupportedOperationException e) {
913      return;
914    }
915
916    for (Entry<K, V> entry : map.entrySet()) {
917      assertEquals(entry.getValue(), map.get(entry.getKey()));
918    }
919
920    K unmappedKey = null;
921    try {
922      unmappedKey = getKeyNotInPopulatedMap();
923    } catch (UnsupportedOperationException e) {
924      return;
925    }
926    assertNull(map.get(unmappedKey));
927  }
928
929  public void testGetForEmptyMap() {
930    Map<K, V> map;
931    K unmappedKey = null;
932    try {
933      map = makeEmptyMap();
934      unmappedKey = getKeyNotInPopulatedMap();
935    } catch (UnsupportedOperationException e) {
936      return;
937    }
938    assertNull(map.get(unmappedKey));
939  }
940
941  public void testGetNull() {
942    Map<K, V> map = makeEitherMap();
943    if (allowsNullKeys) {
944      if (allowsNullValues) {
945        // TODO: decide what to test here.
946      } else {
947        assertEquals(map.containsKey(null), map.get(null) != null);
948      }
949    } else {
950      try {
951        map.get(null);
952      } catch (NullPointerException optional) {
953      }
954    }
955    assertInvariants(map);
956  }
957
958  public void testHashCode() {
959    Map<K, V> map;
960    try {
961      map = makePopulatedMap();
962    } catch (UnsupportedOperationException e) {
963      return;
964    }
965    assertInvariants(map);
966  }
967
968  public void testHashCodeForEmptyMap() {
969    Map<K, V> map;
970    try {
971      map = makeEmptyMap();
972    } catch (UnsupportedOperationException e) {
973      return;
974    }
975    assertInvariants(map);
976  }
977
978  public void testPutNewKey() {
979    Map<K, V> map = makeEitherMap();
980    K keyToPut;
981    V valueToPut;
982    try {
983      keyToPut = getKeyNotInPopulatedMap();
984      valueToPut = getValueNotInPopulatedMap();
985    } catch (UnsupportedOperationException e) {
986      return;
987    }
988    if (supportsPut) {
989      int initialSize = map.size();
990      V oldValue = map.put(keyToPut, valueToPut);
991      assertEquals(valueToPut, map.get(keyToPut));
992      assertTrue(map.containsKey(keyToPut));
993      assertTrue(map.containsValue(valueToPut));
994      assertEquals(initialSize + 1, map.size());
995      assertNull(oldValue);
996    } else {
997      try {
998        map.put(keyToPut, valueToPut);
999        fail("Expected UnsupportedOperationException.");
1000      } catch (UnsupportedOperationException expected) {
1001      }
1002    }
1003    assertInvariants(map);
1004  }
1005
1006  public void testPutExistingKey() {
1007    Map<K, V> map;
1008    K keyToPut;
1009    V valueToPut;
1010    try {
1011      map = makePopulatedMap();
1012      valueToPut = getValueNotInPopulatedMap();
1013    } catch (UnsupportedOperationException e) {
1014      return;
1015    }
1016    keyToPut = map.keySet().iterator().next();
1017    if (supportsPut) {
1018      int initialSize = map.size();
1019      map.put(keyToPut, valueToPut);
1020      assertEquals(valueToPut, map.get(keyToPut));
1021      assertTrue(map.containsKey(keyToPut));
1022      assertTrue(map.containsValue(valueToPut));
1023      assertEquals(initialSize, map.size());
1024    } else {
1025      try {
1026        map.put(keyToPut, valueToPut);
1027        fail("Expected UnsupportedOperationException.");
1028      } catch (UnsupportedOperationException expected) {
1029      }
1030    }
1031    assertInvariants(map);
1032  }
1033
1034  public void testPutNullKey() {
1035    if (!supportsPut) {
1036      return;
1037    }
1038    Map<K, V> map = makeEitherMap();
1039    V valueToPut;
1040    try {
1041      valueToPut = getValueNotInPopulatedMap();
1042    } catch (UnsupportedOperationException e) {
1043      return;
1044    }
1045    if (allowsNullKeys) {
1046      V oldValue = map.get(null);
1047      V returnedValue = map.put(null, valueToPut);
1048      assertEquals(oldValue, returnedValue);
1049      assertEquals(valueToPut, map.get(null));
1050      assertTrue(map.containsKey(null));
1051      assertTrue(map.containsValue(valueToPut));
1052    } else {
1053      try {
1054        map.put(null, valueToPut);
1055        fail("Expected RuntimeException");
1056      } catch (RuntimeException expected) {
1057      }
1058    }
1059    assertInvariants(map);
1060  }
1061
1062  public void testPutNullValue() {
1063    if (!supportsPut) {
1064      return;
1065    }
1066    Map<K, V> map = makeEitherMap();
1067    K keyToPut;
1068    try {
1069      keyToPut = getKeyNotInPopulatedMap();
1070    } catch (UnsupportedOperationException e) {
1071      return;
1072    }
1073    if (allowsNullValues) {
1074      int initialSize = map.size();
1075      V oldValue = map.get(keyToPut);
1076      V returnedValue = map.put(keyToPut, null);
1077      assertEquals(oldValue, returnedValue);
1078      assertNull(map.get(keyToPut));
1079      assertTrue(map.containsKey(keyToPut));
1080      assertTrue(map.containsValue(null));
1081      assertEquals(initialSize + 1, map.size());
1082    } else {
1083      try {
1084        map.put(keyToPut, null);
1085        fail("Expected RuntimeException");
1086      } catch (RuntimeException expected) {
1087      }
1088    }
1089    assertInvariants(map);
1090  }
1091
1092  public void testPutNullValueForExistingKey() {
1093    if (!supportsPut) {
1094      return;
1095    }
1096    Map<K, V> map;
1097    K keyToPut;
1098    try {
1099      map = makePopulatedMap();
1100      keyToPut = map.keySet().iterator().next();
1101    } catch (UnsupportedOperationException e) {
1102      return;
1103    }
1104    if (allowsNullValues) {
1105      int initialSize = map.size();
1106      V oldValue = map.get(keyToPut);
1107      V returnedValue = map.put(keyToPut, null);
1108      assertEquals(oldValue, returnedValue);
1109      assertNull(map.get(keyToPut));
1110      assertTrue(map.containsKey(keyToPut));
1111      assertTrue(map.containsValue(null));
1112      assertEquals(initialSize, map.size());
1113    } else {
1114      try {
1115        map.put(keyToPut, null);
1116        fail("Expected RuntimeException");
1117      } catch (RuntimeException expected) {
1118      }
1119    }
1120    assertInvariants(map);
1121  }
1122
1123  public void testPutAllNewKey() {
1124    Map<K, V> map = makeEitherMap();
1125    K keyToPut;
1126    V valueToPut;
1127    try {
1128      keyToPut = getKeyNotInPopulatedMap();
1129      valueToPut = getValueNotInPopulatedMap();
1130    } catch (UnsupportedOperationException e) {
1131      return;
1132    }
1133    Map<K, V> mapToPut = Collections.singletonMap(keyToPut, valueToPut);
1134    if (supportsPut) {
1135      int initialSize = map.size();
1136      map.putAll(mapToPut);
1137      assertEquals(valueToPut, map.get(keyToPut));
1138      assertTrue(map.containsKey(keyToPut));
1139      assertTrue(map.containsValue(valueToPut));
1140      assertEquals(initialSize + 1, map.size());
1141    } else {
1142      try {
1143        map.putAll(mapToPut);
1144        fail("Expected UnsupportedOperationException.");
1145      } catch (UnsupportedOperationException expected) {
1146      }
1147    }
1148    assertInvariants(map);
1149  }
1150
1151  public void testPutAllExistingKey() {
1152    Map<K, V> map;
1153    K keyToPut;
1154    V valueToPut;
1155    try {
1156      map = makePopulatedMap();
1157      valueToPut = getValueNotInPopulatedMap();
1158    } catch (UnsupportedOperationException e) {
1159      return;
1160    }
1161    keyToPut = map.keySet().iterator().next();
1162    Map<K, V> mapToPut = Collections.singletonMap(keyToPut, valueToPut);
1163    int initialSize = map.size();
1164    if (supportsPut) {
1165      map.putAll(mapToPut);
1166      assertEquals(valueToPut, map.get(keyToPut));
1167      assertTrue(map.containsKey(keyToPut));
1168      assertTrue(map.containsValue(valueToPut));
1169    } else {
1170      try {
1171        map.putAll(mapToPut);
1172        fail("Expected UnsupportedOperationException.");
1173      } catch (UnsupportedOperationException expected) {
1174      }
1175    }
1176    assertEquals(initialSize, map.size());
1177    assertInvariants(map);
1178  }
1179
1180  public void testRemove() {
1181    Map<K, V> map;
1182    K keyToRemove;
1183    try {
1184      map = makePopulatedMap();
1185    } catch (UnsupportedOperationException e) {
1186      return;
1187    }
1188    keyToRemove = map.keySet().iterator().next();
1189    if (supportsRemove) {
1190      int initialSize = map.size();
1191      V expectedValue = map.get(keyToRemove);
1192      V oldValue = map.remove(keyToRemove);
1193      assertEquals(expectedValue, oldValue);
1194      assertFalse(map.containsKey(keyToRemove));
1195      assertEquals(initialSize - 1, map.size());
1196    } else {
1197      try {
1198        map.remove(keyToRemove);
1199        fail("Expected UnsupportedOperationException.");
1200      } catch (UnsupportedOperationException expected) {
1201      }
1202    }
1203    assertInvariants(map);
1204  }
1205
1206  public void testRemoveMissingKey() {
1207    Map<K, V> map;
1208    K keyToRemove;
1209    try {
1210      map = makePopulatedMap();
1211      keyToRemove = getKeyNotInPopulatedMap();
1212    } catch (UnsupportedOperationException e) {
1213      return;
1214    }
1215    if (supportsRemove) {
1216      int initialSize = map.size();
1217      assertNull(map.remove(keyToRemove));
1218      assertEquals(initialSize, map.size());
1219    } else {
1220      try {
1221        map.remove(keyToRemove);
1222        fail("Expected UnsupportedOperationException.");
1223      } catch (UnsupportedOperationException expected) {
1224      }
1225    }
1226    assertInvariants(map);
1227  }
1228
1229  public void testSize() {
1230    assertInvariants(makeEitherMap());
1231  }
1232
1233  public void testKeySetRemove() {
1234    Map<K, V> map;
1235    try {
1236      map = makePopulatedMap();
1237    } catch (UnsupportedOperationException e) {
1238      return;
1239    }
1240
1241    Set<K> keys = map.keySet();
1242    K key = keys.iterator().next();
1243    if (supportsRemove) {
1244      int initialSize = map.size();
1245      keys.remove(key);
1246      assertEquals(initialSize - 1, map.size());
1247      assertFalse(map.containsKey(key));
1248    } else {
1249      try {
1250        keys.remove(key);
1251        fail("Expected UnsupportedOperationException.");
1252      } catch (UnsupportedOperationException expected) {
1253      }
1254    }
1255    assertInvariants(map);
1256  }
1257
1258  public void testKeySetRemoveAll() {
1259    Map<K, V> map;
1260    try {
1261      map = makePopulatedMap();
1262    } catch (UnsupportedOperationException e) {
1263      return;
1264    }
1265
1266    Set<K> keys = map.keySet();
1267    K key = keys.iterator().next();
1268    if (supportsRemove) {
1269      int initialSize = map.size();
1270      assertTrue(keys.removeAll(Collections.singleton(key)));
1271      assertEquals(initialSize - 1, map.size());
1272      assertFalse(map.containsKey(key));
1273    } else {
1274      try {
1275        keys.removeAll(Collections.singleton(key));
1276        fail("Expected UnsupportedOperationException.");
1277      } catch (UnsupportedOperationException expected) {
1278      }
1279    }
1280    assertInvariants(map);
1281  }
1282
1283  public void testKeySetRetainAll() {
1284    Map<K, V> map;
1285    try {
1286      map = makePopulatedMap();
1287    } catch (UnsupportedOperationException e) {
1288      return;
1289    }
1290
1291    Set<K> keys = map.keySet();
1292    K key = keys.iterator().next();
1293    if (supportsRemove) {
1294      keys.retainAll(Collections.singleton(key));
1295      assertEquals(1, map.size());
1296      assertTrue(map.containsKey(key));
1297    } else {
1298      try {
1299        keys.retainAll(Collections.singleton(key));
1300        fail("Expected UnsupportedOperationException.");
1301      } catch (UnsupportedOperationException expected) {
1302      }
1303    }
1304    assertInvariants(map);
1305  }
1306
1307  public void testKeySetClear() {
1308    Map<K, V> map;
1309    try {
1310      map = makeEitherMap();
1311    } catch (UnsupportedOperationException e) {
1312      return;
1313    }
1314
1315    Set<K> keySet = map.keySet();
1316    if (supportsClear) {
1317      keySet.clear();
1318      assertTrue(keySet.isEmpty());
1319    } else {
1320      try {
1321        keySet.clear();
1322        fail("Expected UnsupportedOperationException.");
1323      } catch (UnsupportedOperationException expected) {
1324      }
1325    }
1326    assertInvariants(map);
1327  }
1328
1329  public void testKeySetRemoveAllNullFromEmpty() {
1330    Map<K, V> map;
1331    try {
1332      map = makeEmptyMap();
1333    } catch (UnsupportedOperationException e) {
1334      return;
1335    }
1336
1337    Set<K> keySet = map.keySet();
1338    if (supportsRemove) {
1339      try {
1340        keySet.removeAll(null);
1341        fail("Expected NullPointerException.");
1342      } catch (NullPointerException expected) {
1343      }
1344    } else {
1345      try {
1346        keySet.removeAll(null);
1347        fail("Expected UnsupportedOperationException or NullPointerException.");
1348      } catch (UnsupportedOperationException | NullPointerException e) {
1349        // Expected.
1350      }
1351    }
1352    assertInvariants(map);
1353  }
1354
1355  public void testKeySetRetainAllNullFromEmpty() {
1356    Map<K, V> map;
1357    try {
1358      map = makeEmptyMap();
1359    } catch (UnsupportedOperationException e) {
1360      return;
1361    }
1362
1363    Set<K> keySet = map.keySet();
1364    if (supportsRemove) {
1365      try {
1366        keySet.retainAll(null);
1367        // Returning successfully is not ideal, but tolerated.
1368      } catch (NullPointerException expected) {
1369      }
1370    } else {
1371      try {
1372        keySet.retainAll(null);
1373        // We have to tolerate a successful return (Sun bug 4802647)
1374      } catch (UnsupportedOperationException | NullPointerException e) {
1375        // Expected.
1376      }
1377    }
1378    assertInvariants(map);
1379  }
1380
1381  public void testValues() {
1382    Map<K, V> map;
1383    Collection<V> valueCollection;
1384    try {
1385      map = makePopulatedMap();
1386    } catch (UnsupportedOperationException e) {
1387      return;
1388    }
1389    assertInvariants(map);
1390
1391    valueCollection = map.values();
1392    V unmappedValue;
1393    try {
1394      unmappedValue = getValueNotInPopulatedMap();
1395    } catch (UnsupportedOperationException e) {
1396      return;
1397    }
1398    for (V value : valueCollection) {
1399      assertFalse(unmappedValue.equals(value));
1400    }
1401  }
1402
1403  public void testValuesIteratorRemove() {
1404    Map<K, V> map;
1405    try {
1406      map = makePopulatedMap();
1407    } catch (UnsupportedOperationException e) {
1408      return;
1409    }
1410
1411    Collection<V> valueCollection = map.values();
1412    Iterator<V> iterator = valueCollection.iterator();
1413    if (supportsIteratorRemove) {
1414      int initialSize = map.size();
1415      iterator.next();
1416      iterator.remove();
1417      assertEquals(initialSize - 1, map.size());
1418      // (We can't assert that the values collection no longer contains the
1419      // removed value, because the underlying map can have multiple mappings
1420      // to the same value.)
1421      assertInvariants(map);
1422      try {
1423        iterator.remove();
1424        fail("Expected IllegalStateException.");
1425      } catch (IllegalStateException expected) {
1426      }
1427    } else {
1428      try {
1429        iterator.next();
1430        iterator.remove();
1431        fail("Expected UnsupportedOperationException.");
1432      } catch (UnsupportedOperationException expected) {
1433      }
1434    }
1435    assertInvariants(map);
1436  }
1437
1438  public void testValuesRemove() {
1439    Map<K, V> map;
1440    try {
1441      map = makePopulatedMap();
1442    } catch (UnsupportedOperationException e) {
1443      return;
1444    }
1445
1446    Collection<V> valueCollection = map.values();
1447    if (supportsRemove) {
1448      int initialSize = map.size();
1449      valueCollection.remove(valueCollection.iterator().next());
1450      assertEquals(initialSize - 1, map.size());
1451      // (We can't assert that the values collection no longer contains the
1452      // removed value, because the underlying map can have multiple mappings
1453      // to the same value.)
1454    } else {
1455      try {
1456        valueCollection.remove(valueCollection.iterator().next());
1457        fail("Expected UnsupportedOperationException.");
1458      } catch (UnsupportedOperationException expected) {
1459      }
1460    }
1461    assertInvariants(map);
1462  }
1463
1464  public void testValuesRemoveMissing() {
1465    Map<K, V> map;
1466    V valueToRemove;
1467    try {
1468      map = makeEitherMap();
1469      valueToRemove = getValueNotInPopulatedMap();
1470    } catch (UnsupportedOperationException e) {
1471      return;
1472    }
1473
1474    Collection<V> valueCollection = map.values();
1475    int initialSize = map.size();
1476    if (supportsRemove) {
1477      assertFalse(valueCollection.remove(valueToRemove));
1478    } else {
1479      try {
1480        assertFalse(valueCollection.remove(valueToRemove));
1481      } catch (UnsupportedOperationException e) {
1482        // Tolerated.
1483      }
1484    }
1485    assertEquals(initialSize, map.size());
1486    assertInvariants(map);
1487  }
1488
1489  public void testValuesRemoveAll() {
1490    Map<K, V> map;
1491    try {
1492      map = makePopulatedMap();
1493    } catch (UnsupportedOperationException e) {
1494      return;
1495    }
1496
1497    Collection<V> valueCollection = map.values();
1498    Set<V> valuesToRemove = singleton(valueCollection.iterator().next());
1499    if (supportsRemove) {
1500      valueCollection.removeAll(valuesToRemove);
1501      for (V value : valuesToRemove) {
1502        assertFalse(valueCollection.contains(value));
1503      }
1504      for (V value : valueCollection) {
1505        assertFalse(valuesToRemove.contains(value));
1506      }
1507    } else {
1508      try {
1509        valueCollection.removeAll(valuesToRemove);
1510        fail("Expected UnsupportedOperationException.");
1511      } catch (UnsupportedOperationException expected) {
1512      }
1513    }
1514    assertInvariants(map);
1515  }
1516
1517  public void testValuesRemoveAllNullFromEmpty() {
1518    Map<K, V> map;
1519    try {
1520      map = makeEmptyMap();
1521    } catch (UnsupportedOperationException e) {
1522      return;
1523    }
1524
1525    Collection<V> values = map.values();
1526    if (supportsRemove) {
1527      try {
1528        values.removeAll(null);
1529        // Returning successfully is not ideal, but tolerated.
1530      } catch (NullPointerException expected) {
1531      }
1532    } else {
1533      try {
1534        values.removeAll(null);
1535        // We have to tolerate a successful return (Sun bug 4802647)
1536      } catch (UnsupportedOperationException | NullPointerException e) {
1537        // Expected.
1538      }
1539    }
1540    assertInvariants(map);
1541  }
1542
1543  public void testValuesRetainAll() {
1544    Map<K, V> map;
1545    try {
1546      map = makePopulatedMap();
1547    } catch (UnsupportedOperationException e) {
1548      return;
1549    }
1550
1551    Collection<V> valueCollection = map.values();
1552    Set<V> valuesToRetain = singleton(valueCollection.iterator().next());
1553    if (supportsRemove) {
1554      valueCollection.retainAll(valuesToRetain);
1555      for (V value : valuesToRetain) {
1556        assertTrue(valueCollection.contains(value));
1557      }
1558      for (V value : valueCollection) {
1559        assertTrue(valuesToRetain.contains(value));
1560      }
1561    } else {
1562      try {
1563        valueCollection.retainAll(valuesToRetain);
1564        fail("Expected UnsupportedOperationException.");
1565      } catch (UnsupportedOperationException expected) {
1566      }
1567    }
1568    assertInvariants(map);
1569  }
1570
1571  public void testValuesRetainAllNullFromEmpty() {
1572    Map<K, V> map;
1573    try {
1574      map = makeEmptyMap();
1575    } catch (UnsupportedOperationException e) {
1576      return;
1577    }
1578
1579    Collection<V> values = map.values();
1580    if (supportsRemove) {
1581      try {
1582        values.retainAll(null);
1583        // Returning successfully is not ideal, but tolerated.
1584      } catch (NullPointerException expected) {
1585      }
1586    } else {
1587      try {
1588        values.retainAll(null);
1589        // We have to tolerate a successful return (Sun bug 4802647)
1590      } catch (UnsupportedOperationException | NullPointerException e) {
1591        // Expected.
1592      }
1593    }
1594    assertInvariants(map);
1595  }
1596
1597  public void testValuesClear() {
1598    Map<K, V> map;
1599    try {
1600      map = makePopulatedMap();
1601    } catch (UnsupportedOperationException e) {
1602      return;
1603    }
1604
1605    Collection<V> valueCollection = map.values();
1606    if (supportsClear) {
1607      valueCollection.clear();
1608      assertTrue(valueCollection.isEmpty());
1609    } else {
1610      try {
1611        valueCollection.clear();
1612        fail("Expected UnsupportedOperationException.");
1613      } catch (UnsupportedOperationException expected) {
1614      }
1615    }
1616    assertInvariants(map);
1617  }
1618
1619  static <K, V> Entry<K, V> mapEntry(K key, V value) {
1620    return Collections.singletonMap(key, value).entrySet().iterator().next();
1621  }
1622}