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