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