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