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