1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.collect.Maps.immutableEntry; 21 import static com.google.common.collect.Sets.newHashSet; 22 import static com.google.common.collect.testing.Helpers.mapEntry; 23 import static com.google.common.collect.testing.Helpers.nefariousMapEntry; 24 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE; 25 import static com.google.common.truth.Truth.assertThat; 26 import static java.util.Arrays.asList; 27 28 import com.google.common.annotations.GwtCompatible; 29 import com.google.common.annotations.GwtIncompatible; 30 import com.google.common.base.Equivalence; 31 import com.google.common.base.Function; 32 import com.google.common.base.Functions; 33 import com.google.common.base.Predicates; 34 import com.google.common.base.Supplier; 35 import com.google.common.collect.Maps.EntryTransformer; 36 import com.google.common.collect.testing.IteratorTester; 37 import com.google.common.collect.testing.google.UnmodifiableCollectionTests; 38 import com.google.common.primitives.Chars; 39 import com.google.common.testing.CollectorTester; 40 import com.google.common.testing.EqualsTester; 41 import com.google.common.testing.NullPointerTester; 42 import com.google.common.testing.SerializableTester; 43 import java.io.Serializable; 44 import java.util.Arrays; 45 import java.util.Collection; 46 import java.util.Collections; 47 import java.util.Comparator; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import java.util.Iterator; 51 import java.util.LinkedList; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.Map.Entry; 55 import java.util.NavigableSet; 56 import java.util.Queue; 57 import java.util.RandomAccess; 58 import java.util.Set; 59 import java.util.SortedMap; 60 import java.util.SortedSet; 61 import java.util.TreeSet; 62 import java.util.function.BiPredicate; 63 import java.util.stream.Collector; 64 import java.util.stream.Stream; 65 import junit.framework.TestCase; 66 import org.checkerframework.checker.nullness.qual.Nullable; 67 68 /** 69 * Unit test for {@code Multimaps}. 70 * 71 * @author Jared Levy 72 */ 73 @GwtCompatible(emulated = true) 74 public class MultimapsTest extends TestCase { 75 76 private static final Comparator<Integer> INT_COMPARATOR = 77 Ordering.<Integer>natural().reverse().nullsFirst(); 78 testMultimapCollectorGenerics()79 public void testMultimapCollectorGenerics() { 80 ListMultimap<Integer, String> unused = 81 Stream.of("foo", "bar", "quux") 82 .collect( 83 Multimaps.toMultimap( 84 String::length, s -> s, MultimapBuilder.treeKeys().arrayListValues()::build)); 85 } 86 testToMultimap()87 public void testToMultimap() { 88 Collector<Entry<String, Integer>, ?, TreeMultimap<String, Integer>> collector = 89 Multimaps.toMultimap(Entry::getKey, Entry::getValue, TreeMultimap::create); 90 BiPredicate<Multimap<?, ?>, Multimap<?, ?>> equivalence = 91 Equivalence.equals() 92 .onResultOf((Multimap<?, ?> mm) -> ImmutableList.copyOf(mm.asMap().entrySet())) 93 .and(Equivalence.equals()); 94 TreeMultimap<String, Integer> empty = TreeMultimap.create(); 95 TreeMultimap<String, Integer> filled = TreeMultimap.create(); 96 filled.put("a", 1); 97 filled.put("a", 2); 98 filled.put("b", 2); 99 filled.put("c", 3); 100 CollectorTester.of(collector, equivalence) 101 .expectCollects(empty) 102 .expectCollects( 103 filled, mapEntry("a", 1), mapEntry("a", 2), mapEntry("b", 2), mapEntry("c", 3)); 104 } 105 testFlatteningToMultimap()106 public void testFlatteningToMultimap() { 107 Collector<String, ?, ListMultimap<Character, Character>> collector = 108 Multimaps.flatteningToMultimap( 109 str -> str.charAt(0), 110 str -> Chars.asList(str.substring(1).toCharArray()).stream(), 111 MultimapBuilder.linkedHashKeys().arrayListValues()::build); 112 BiPredicate<Multimap<?, ?>, Multimap<?, ?>> equivalence = 113 Equivalence.equals() 114 .onResultOf((Multimap<?, ?> mm) -> ImmutableList.copyOf(mm.asMap().entrySet())) 115 .and(Equivalence.equals()); 116 ListMultimap<Character, Character> empty = 117 MultimapBuilder.linkedHashKeys().arrayListValues().build(); 118 ListMultimap<Character, Character> filled = 119 MultimapBuilder.linkedHashKeys().arrayListValues().build(); 120 filled.putAll('b', Arrays.asList('a', 'n', 'a', 'n', 'a')); 121 filled.putAll('a', Arrays.asList('p', 'p', 'l', 'e')); 122 filled.putAll('c', Arrays.asList('a', 'r', 'r', 'o', 't')); 123 filled.putAll('a', Arrays.asList('s', 'p', 'a', 'r', 'a', 'g', 'u', 's')); 124 filled.putAll('c', Arrays.asList('h', 'e', 'r', 'r', 'y')); 125 CollectorTester.of(collector, equivalence) 126 .expectCollects(empty) 127 .expectCollects(filled, "banana", "apple", "carrot", "asparagus", "cherry"); 128 } 129 130 @SuppressWarnings("deprecation") testUnmodifiableListMultimapShortCircuit()131 public void testUnmodifiableListMultimapShortCircuit() { 132 ListMultimap<String, Integer> mod = ArrayListMultimap.create(); 133 ListMultimap<String, Integer> unmod = Multimaps.unmodifiableListMultimap(mod); 134 assertNotSame(mod, unmod); 135 assertSame(unmod, Multimaps.unmodifiableListMultimap(unmod)); 136 ImmutableListMultimap<String, Integer> immutable = 137 ImmutableListMultimap.of("a", 1, "b", 2, "a", 3); 138 assertSame(immutable, Multimaps.unmodifiableListMultimap(immutable)); 139 assertSame( 140 immutable, Multimaps.unmodifiableListMultimap((ListMultimap<String, Integer>) immutable)); 141 } 142 143 @SuppressWarnings("deprecation") testUnmodifiableSetMultimapShortCircuit()144 public void testUnmodifiableSetMultimapShortCircuit() { 145 SetMultimap<String, Integer> mod = HashMultimap.create(); 146 SetMultimap<String, Integer> unmod = Multimaps.unmodifiableSetMultimap(mod); 147 assertNotSame(mod, unmod); 148 assertSame(unmod, Multimaps.unmodifiableSetMultimap(unmod)); 149 ImmutableSetMultimap<String, Integer> immutable = 150 ImmutableSetMultimap.of("a", 1, "b", 2, "a", 3); 151 assertSame(immutable, Multimaps.unmodifiableSetMultimap(immutable)); 152 assertSame( 153 immutable, Multimaps.unmodifiableSetMultimap((SetMultimap<String, Integer>) immutable)); 154 } 155 156 @SuppressWarnings("deprecation") testUnmodifiableMultimapShortCircuit()157 public void testUnmodifiableMultimapShortCircuit() { 158 Multimap<String, Integer> mod = HashMultimap.create(); 159 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod); 160 assertNotSame(mod, unmod); 161 assertSame(unmod, Multimaps.unmodifiableMultimap(unmod)); 162 ImmutableMultimap<String, Integer> immutable = ImmutableMultimap.of("a", 1, "b", 2, "a", 3); 163 assertSame(immutable, Multimaps.unmodifiableMultimap(immutable)); 164 assertSame(immutable, Multimaps.unmodifiableMultimap((Multimap<String, Integer>) immutable)); 165 } 166 167 @GwtIncompatible // slow (~10s) testUnmodifiableArrayListMultimap()168 public void testUnmodifiableArrayListMultimap() { 169 checkUnmodifiableMultimap(ArrayListMultimap.<String, Integer>create(), true); 170 } 171 172 @GwtIncompatible // SerializableTester testSerializingUnmodifiableArrayListMultimap()173 public void testSerializingUnmodifiableArrayListMultimap() { 174 Multimap<String, Integer> unmodifiable = 175 prepareUnmodifiableTests(ArrayListMultimap.<String, Integer>create(), true, null, null); 176 SerializableTester.reserializeAndAssert(unmodifiable); 177 } 178 testUnmodifiableArrayListMultimapRandomAccess()179 public void testUnmodifiableArrayListMultimapRandomAccess() { 180 ListMultimap<String, Integer> delegate = ArrayListMultimap.create(); 181 delegate.put("foo", 1); 182 delegate.put("foo", 3); 183 ListMultimap<String, Integer> multimap = Multimaps.unmodifiableListMultimap(delegate); 184 assertTrue(multimap.get("foo") instanceof RandomAccess); 185 assertTrue(multimap.get("bar") instanceof RandomAccess); 186 } 187 testUnmodifiableLinkedListMultimapRandomAccess()188 public void testUnmodifiableLinkedListMultimapRandomAccess() { 189 ListMultimap<String, Integer> delegate = LinkedListMultimap.create(); 190 delegate.put("foo", 1); 191 delegate.put("foo", 3); 192 ListMultimap<String, Integer> multimap = Multimaps.unmodifiableListMultimap(delegate); 193 assertFalse(multimap.get("foo") instanceof RandomAccess); 194 assertFalse(multimap.get("bar") instanceof RandomAccess); 195 } 196 197 @GwtIncompatible // slow (~10s) testUnmodifiableHashMultimap()198 public void testUnmodifiableHashMultimap() { 199 checkUnmodifiableMultimap(HashMultimap.<String, Integer>create(), false); 200 } 201 202 @GwtIncompatible // SerializableTester testSerializingUnmodifiableHashMultimap()203 public void testSerializingUnmodifiableHashMultimap() { 204 Multimap<String, Integer> unmodifiable = 205 prepareUnmodifiableTests(HashMultimap.<String, Integer>create(), false, null, null); 206 SerializableTester.reserializeAndAssert(unmodifiable); 207 } 208 209 @GwtIncompatible // slow (~10s) testUnmodifiableTreeMultimap()210 public void testUnmodifiableTreeMultimap() { 211 checkUnmodifiableMultimap(TreeMultimap.<String, Integer>create(), false, "null", 42); 212 } 213 214 @GwtIncompatible // SerializableTester testSerializingUnmodifiableTreeMultimap()215 public void testSerializingUnmodifiableTreeMultimap() { 216 Multimap<String, Integer> unmodifiable = 217 prepareUnmodifiableTests(TreeMultimap.<String, Integer>create(), false, "null", 42); 218 SerializableTester.reserializeAndAssert(unmodifiable); 219 } 220 221 @GwtIncompatible // slow (~10s) testUnmodifiableSynchronizedArrayListMultimap()222 public void testUnmodifiableSynchronizedArrayListMultimap() { 223 checkUnmodifiableMultimap( 224 Multimaps.synchronizedListMultimap(ArrayListMultimap.<String, Integer>create()), true); 225 } 226 227 @GwtIncompatible // SerializableTester testSerializingUnmodifiableSynchronizedArrayListMultimap()228 public void testSerializingUnmodifiableSynchronizedArrayListMultimap() { 229 Multimap<String, Integer> unmodifiable = 230 prepareUnmodifiableTests( 231 Multimaps.synchronizedListMultimap(ArrayListMultimap.<String, Integer>create()), 232 true, 233 null, 234 null); 235 SerializableTester.reserializeAndAssert(unmodifiable); 236 } 237 238 @GwtIncompatible // slow (~10s) testUnmodifiableSynchronizedHashMultimap()239 public void testUnmodifiableSynchronizedHashMultimap() { 240 checkUnmodifiableMultimap( 241 Multimaps.synchronizedSetMultimap(HashMultimap.<String, Integer>create()), false); 242 } 243 244 @GwtIncompatible // SerializableTester testSerializingUnmodifiableSynchronizedHashMultimap()245 public void testSerializingUnmodifiableSynchronizedHashMultimap() { 246 Multimap<String, Integer> unmodifiable = 247 prepareUnmodifiableTests( 248 Multimaps.synchronizedSetMultimap(HashMultimap.<String, Integer>create()), 249 false, 250 null, 251 null); 252 SerializableTester.reserializeAndAssert(unmodifiable); 253 } 254 255 @GwtIncompatible // slow (~10s) testUnmodifiableSynchronizedTreeMultimap()256 public void testUnmodifiableSynchronizedTreeMultimap() { 257 TreeMultimap<String, Integer> delegate = 258 TreeMultimap.create(Ordering.<String>natural(), INT_COMPARATOR); 259 SortedSetMultimap<String, Integer> multimap = Multimaps.synchronizedSortedSetMultimap(delegate); 260 checkUnmodifiableMultimap(multimap, false, "null", 42); 261 assertSame(INT_COMPARATOR, multimap.valueComparator()); 262 } 263 264 @GwtIncompatible // SerializableTester testSerializingUnmodifiableSynchronizedTreeMultimap()265 public void testSerializingUnmodifiableSynchronizedTreeMultimap() { 266 TreeMultimap<String, Integer> delegate = 267 TreeMultimap.create(Ordering.<String>natural(), INT_COMPARATOR); 268 SortedSetMultimap<String, Integer> multimap = Multimaps.synchronizedSortedSetMultimap(delegate); 269 Multimap<String, Integer> unmodifiable = prepareUnmodifiableTests(multimap, false, "null", 42); 270 SerializableTester.reserializeAndAssert(unmodifiable); 271 assertSame(INT_COMPARATOR, multimap.valueComparator()); 272 } 273 testUnmodifiableMultimapIsView()274 public void testUnmodifiableMultimapIsView() { 275 Multimap<String, Integer> mod = HashMultimap.create(); 276 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod); 277 assertEquals(mod, unmod); 278 mod.put("foo", 1); 279 assertTrue(unmod.containsEntry("foo", 1)); 280 assertEquals(mod, unmod); 281 } 282 283 @SuppressWarnings("unchecked") testUnmodifiableMultimapEntries()284 public void testUnmodifiableMultimapEntries() { 285 Multimap<String, Integer> mod = HashMultimap.create(); 286 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod); 287 mod.put("foo", 1); 288 Entry<String, Integer> entry = unmod.entries().iterator().next(); 289 try { 290 entry.setValue(2); 291 fail("UnsupportedOperationException expected"); 292 } catch (UnsupportedOperationException expected) { 293 } 294 entry = (Entry<String, Integer>) unmod.entries().toArray()[0]; 295 try { 296 entry.setValue(2); 297 fail("UnsupportedOperationException expected"); 298 } catch (UnsupportedOperationException expected) { 299 } 300 Entry<String, Integer>[] array = (Entry<String, Integer>[]) new Entry<?, ?>[2]; 301 assertSame(array, unmod.entries().toArray(array)); 302 try { 303 array[0].setValue(2); 304 fail("UnsupportedOperationException expected"); 305 } catch (UnsupportedOperationException expected) { 306 } 307 assertFalse(unmod.entries().contains(nefariousMapEntry("pwnd", 2))); 308 assertFalse(unmod.keys().contains("pwnd")); 309 } 310 311 /** 312 * The supplied multimap will be mutated and an unmodifiable instance used in its stead. The 313 * multimap must support null keys and values. 314 */ checkUnmodifiableMultimap( Multimap<String, Integer> multimap, boolean permitsDuplicates)315 private static void checkUnmodifiableMultimap( 316 Multimap<String, Integer> multimap, boolean permitsDuplicates) { 317 checkUnmodifiableMultimap(multimap, permitsDuplicates, null, null); 318 } 319 320 /** 321 * The supplied multimap will be mutated and an unmodifiable instance used in its stead. If the 322 * multimap does not support null keys or values, alternatives may be specified for tests 323 * involving nulls. 324 */ checkUnmodifiableMultimap( Multimap<String, Integer> multimap, boolean permitsDuplicates, @Nullable String nullKey, @Nullable Integer nullValue)325 private static void checkUnmodifiableMultimap( 326 Multimap<String, Integer> multimap, 327 boolean permitsDuplicates, 328 @Nullable String nullKey, 329 @Nullable Integer nullValue) { 330 Multimap<String, Integer> unmodifiable = 331 prepareUnmodifiableTests(multimap, permitsDuplicates, nullKey, nullValue); 332 333 UnmodifiableCollectionTests.assertMultimapIsUnmodifiable(unmodifiable, "test", 123); 334 335 assertUnmodifiableIterableInTandem(unmodifiable.keys(), multimap.keys()); 336 337 assertUnmodifiableIterableInTandem(unmodifiable.keySet(), multimap.keySet()); 338 339 assertUnmodifiableIterableInTandem(unmodifiable.entries(), multimap.entries()); 340 341 assertUnmodifiableIterableInTandem( 342 unmodifiable.asMap().entrySet(), multimap.asMap().entrySet()); 343 344 assertEquals(multimap.toString(), unmodifiable.toString()); 345 assertEquals(multimap.hashCode(), unmodifiable.hashCode()); 346 assertEquals(multimap, unmodifiable); 347 348 assertThat(unmodifiable.asMap().get("bar")).containsExactly(5, -1); 349 assertNull(unmodifiable.asMap().get("missing")); 350 351 assertFalse(unmodifiable.entries() instanceof Serializable); 352 } 353 354 /** Prepares the multimap for unmodifiable tests, returning an unmodifiable view of the map. */ prepareUnmodifiableTests( Multimap<String, Integer> multimap, boolean permitsDuplicates, @Nullable String nullKey, @Nullable Integer nullValue)355 private static Multimap<String, Integer> prepareUnmodifiableTests( 356 Multimap<String, Integer> multimap, 357 boolean permitsDuplicates, 358 @Nullable String nullKey, 359 @Nullable Integer nullValue) { 360 multimap.clear(); 361 multimap.put("foo", 1); 362 multimap.put("foo", 2); 363 multimap.put("foo", 3); 364 multimap.put("bar", 5); 365 multimap.put("bar", -1); 366 multimap.put(nullKey, nullValue); 367 multimap.put("foo", nullValue); 368 multimap.put(nullKey, 5); 369 multimap.put("foo", 2); 370 371 if (permitsDuplicates) { 372 assertEquals(9, multimap.size()); 373 } else { 374 assertEquals(8, multimap.size()); 375 } 376 377 Multimap<String, Integer> unmodifiable; 378 if (multimap instanceof SortedSetMultimap) { 379 unmodifiable = 380 Multimaps.unmodifiableSortedSetMultimap((SortedSetMultimap<String, Integer>) multimap); 381 } else if (multimap instanceof SetMultimap) { 382 unmodifiable = Multimaps.unmodifiableSetMultimap((SetMultimap<String, Integer>) multimap); 383 } else if (multimap instanceof ListMultimap) { 384 unmodifiable = Multimaps.unmodifiableListMultimap((ListMultimap<String, Integer>) multimap); 385 } else { 386 unmodifiable = Multimaps.unmodifiableMultimap(multimap); 387 } 388 return unmodifiable; 389 } 390 assertUnmodifiableIterableInTandem( Iterable<T> unmodifiable, Iterable<T> modifiable)391 private static <T> void assertUnmodifiableIterableInTandem( 392 Iterable<T> unmodifiable, Iterable<T> modifiable) { 393 UnmodifiableCollectionTests.assertIteratorIsUnmodifiable(unmodifiable.iterator()); 394 UnmodifiableCollectionTests.assertIteratorsInOrder( 395 unmodifiable.iterator(), modifiable.iterator()); 396 } 397 testInvertFrom()398 public void testInvertFrom() { 399 ImmutableMultimap<Integer, String> empty = ImmutableMultimap.of(); 400 401 // typical usage example - sad that ArrayListMultimap.create() won't work 402 Multimap<String, Integer> multimap = 403 Multimaps.invertFrom(empty, ArrayListMultimap.<String, Integer>create()); 404 assertTrue(multimap.isEmpty()); 405 406 ImmutableMultimap<Integer, String> single = 407 new ImmutableMultimap.Builder<Integer, String>().put(1, "one").put(2, "two").build(); 408 409 // copy into existing multimap 410 assertSame(multimap, Multimaps.invertFrom(single, multimap)); 411 412 ImmutableMultimap<String, Integer> expected = 413 new ImmutableMultimap.Builder<String, Integer>().put("one", 1).put("two", 2).build(); 414 415 assertEquals(expected, multimap); 416 } 417 testAsMap_multimap()418 public void testAsMap_multimap() { 419 Multimap<String, Integer> multimap = 420 Multimaps.newMultimap(new HashMap<String, Collection<Integer>>(), new QueueSupplier()); 421 Map<String, Collection<Integer>> map = Multimaps.asMap(multimap); 422 assertSame(multimap.asMap(), map); 423 } 424 testAsMap_listMultimap()425 public void testAsMap_listMultimap() { 426 ListMultimap<String, Integer> listMultimap = ArrayListMultimap.create(); 427 Map<String, List<Integer>> map = Multimaps.asMap(listMultimap); 428 assertSame(listMultimap.asMap(), map); 429 } 430 testAsMap_setMultimap()431 public void testAsMap_setMultimap() { 432 SetMultimap<String, Integer> setMultimap = LinkedHashMultimap.create(); 433 Map<String, Set<Integer>> map = Multimaps.asMap(setMultimap); 434 assertSame(setMultimap.asMap(), map); 435 } 436 testAsMap_sortedSetMultimap()437 public void testAsMap_sortedSetMultimap() { 438 SortedSetMultimap<String, Integer> sortedSetMultimap = TreeMultimap.create(); 439 Map<String, SortedSet<Integer>> map = Multimaps.asMap(sortedSetMultimap); 440 assertSame(sortedSetMultimap.asMap(), map); 441 } 442 testForMap()443 public void testForMap() { 444 Map<String, Integer> map = Maps.newHashMap(); 445 map.put("foo", 1); 446 map.put("bar", 2); 447 Multimap<String, Integer> multimap = HashMultimap.create(); 448 multimap.put("foo", 1); 449 multimap.put("bar", 2); 450 Multimap<String, Integer> multimapView = Multimaps.forMap(map); 451 new EqualsTester().addEqualityGroup(multimap, multimapView).addEqualityGroup(map).testEquals(); 452 Multimap<String, Integer> multimap2 = HashMultimap.create(); 453 multimap2.put("foo", 1); 454 assertFalse(multimapView.equals(multimap2)); 455 multimap2.put("bar", 1); 456 assertFalse(multimapView.equals(multimap2)); 457 ListMultimap<String, Integer> listMultimap = 458 new ImmutableListMultimap.Builder<String, Integer>().put("foo", 1).put("bar", 2).build(); 459 assertFalse("SetMultimap equals ListMultimap", multimapView.equals(listMultimap)); 460 assertEquals(multimap.hashCode(), multimapView.hashCode()); 461 assertEquals(multimap.size(), multimapView.size()); 462 assertTrue(multimapView.containsKey("foo")); 463 assertTrue(multimapView.containsValue(1)); 464 assertTrue(multimapView.containsEntry("bar", 2)); 465 assertEquals(Collections.singleton(1), multimapView.get("foo")); 466 assertEquals(Collections.singleton(2), multimapView.get("bar")); 467 try { 468 multimapView.put("baz", 3); 469 fail("UnsupportedOperationException expected"); 470 } catch (UnsupportedOperationException expected) { 471 } 472 try { 473 multimapView.putAll("baz", Collections.singleton(3)); 474 fail("UnsupportedOperationException expected"); 475 } catch (UnsupportedOperationException expected) { 476 } 477 try { 478 multimapView.putAll(multimap); 479 fail("UnsupportedOperationException expected"); 480 } catch (UnsupportedOperationException expected) { 481 } 482 try { 483 multimapView.replaceValues("foo", Collections.<Integer>emptySet()); 484 fail("UnsupportedOperationException expected"); 485 } catch (UnsupportedOperationException expected) { 486 } 487 multimapView.remove("bar", 2); 488 assertFalse(multimapView.containsKey("bar")); 489 assertFalse(map.containsKey("bar")); 490 assertEquals(map.keySet(), multimapView.keySet()); 491 assertEquals(map.keySet(), multimapView.keys().elementSet()); 492 assertThat(multimapView.keys()).contains("foo"); 493 assertThat(multimapView.values()).contains(1); 494 assertThat(multimapView.entries()).contains(Maps.immutableEntry("foo", 1)); 495 assertThat(multimapView.asMap().entrySet()) 496 .contains(Maps.immutableEntry("foo", (Collection<Integer>) Collections.singleton(1))); 497 multimapView.clear(); 498 assertFalse(multimapView.containsKey("foo")); 499 assertFalse(map.containsKey("foo")); 500 assertTrue(map.isEmpty()); 501 assertTrue(multimapView.isEmpty()); 502 multimap.clear(); 503 assertEquals(multimap.toString(), multimapView.toString()); 504 assertEquals(multimap.hashCode(), multimapView.hashCode()); 505 assertEquals(multimap.size(), multimapView.size()); 506 assertEquals(multimapView, ArrayListMultimap.create()); 507 } 508 509 @GwtIncompatible // SerializableTester testForMapSerialization()510 public void testForMapSerialization() { 511 Map<String, Integer> map = Maps.newHashMap(); 512 map.put("foo", 1); 513 map.put("bar", 2); 514 Multimap<String, Integer> multimapView = Multimaps.forMap(map); 515 SerializableTester.reserializeAndAssert(multimapView); 516 } 517 testForMapRemoveAll()518 public void testForMapRemoveAll() { 519 Map<String, Integer> map = Maps.newHashMap(); 520 map.put("foo", 1); 521 map.put("bar", 2); 522 map.put("cow", 3); 523 Multimap<String, Integer> multimap = Multimaps.forMap(map); 524 assertEquals(3, multimap.size()); 525 assertEquals(Collections.emptySet(), multimap.removeAll("dog")); 526 assertEquals(3, multimap.size()); 527 assertTrue(multimap.containsKey("bar")); 528 assertEquals(Collections.singleton(2), multimap.removeAll("bar")); 529 assertEquals(2, multimap.size()); 530 assertFalse(multimap.containsKey("bar")); 531 } 532 testForMapAsMap()533 public void testForMapAsMap() { 534 Map<String, Integer> map = Maps.newHashMap(); 535 map.put("foo", 1); 536 map.put("bar", 2); 537 Map<String, Collection<Integer>> asMap = Multimaps.forMap(map).asMap(); 538 assertEquals(Collections.singleton(1), asMap.get("foo")); 539 assertNull(asMap.get("cow")); 540 assertTrue(asMap.containsKey("foo")); 541 assertFalse(asMap.containsKey("cow")); 542 543 Set<Entry<String, Collection<Integer>>> entries = asMap.entrySet(); 544 assertFalse(entries.contains((Object) 4.5)); 545 assertFalse(entries.remove((Object) 4.5)); 546 assertFalse(entries.contains(Maps.immutableEntry("foo", Collections.singletonList(1)))); 547 assertFalse(entries.remove(Maps.immutableEntry("foo", Collections.singletonList(1)))); 548 assertFalse(entries.contains(Maps.immutableEntry("foo", Sets.newLinkedHashSet(asList(1, 2))))); 549 assertFalse(entries.remove(Maps.immutableEntry("foo", Sets.newLinkedHashSet(asList(1, 2))))); 550 assertFalse(entries.contains(Maps.immutableEntry("foo", Collections.singleton(2)))); 551 assertFalse(entries.remove(Maps.immutableEntry("foo", Collections.singleton(2)))); 552 assertTrue(map.containsKey("foo")); 553 assertTrue(entries.contains(Maps.immutableEntry("foo", Collections.singleton(1)))); 554 assertTrue(entries.remove(Maps.immutableEntry("foo", Collections.singleton(1)))); 555 assertFalse(map.containsKey("foo")); 556 } 557 testForMapGetIteration()558 public void testForMapGetIteration() { 559 IteratorTester<Integer> tester = 560 new IteratorTester<Integer>( 561 4, MODIFIABLE, newHashSet(1), IteratorTester.KnownOrder.KNOWN_ORDER) { 562 private Multimap<String, Integer> multimap; 563 564 @Override 565 protected Iterator<Integer> newTargetIterator() { 566 Map<String, Integer> map = Maps.newHashMap(); 567 map.put("foo", 1); 568 map.put("bar", 2); 569 multimap = Multimaps.forMap(map); 570 return multimap.get("foo").iterator(); 571 } 572 573 @Override 574 protected void verify(List<Integer> elements) { 575 assertEquals(newHashSet(elements), multimap.get("foo")); 576 } 577 }; 578 579 tester.test(); 580 } 581 582 private enum Color { 583 BLUE, 584 RED, 585 YELLOW, 586 GREEN 587 } 588 589 private abstract static class CountingSupplier<E> implements Supplier<E>, Serializable { 590 int count; 591 getImpl()592 abstract E getImpl(); 593 594 @Override get()595 public E get() { 596 count++; 597 return getImpl(); 598 } 599 } 600 601 private static class QueueSupplier extends CountingSupplier<Queue<Integer>> { 602 @Override getImpl()603 public Queue<Integer> getImpl() { 604 return new LinkedList<>(); 605 } 606 607 private static final long serialVersionUID = 0; 608 } 609 testNewMultimapWithCollectionRejectingNegativeElements()610 public void testNewMultimapWithCollectionRejectingNegativeElements() { 611 CountingSupplier<Set<Integer>> factory = 612 new SetSupplier() { 613 @Override 614 public Set<Integer> getImpl() { 615 final Set<Integer> backing = super.getImpl(); 616 return new ForwardingSet<Integer>() { 617 @Override 618 protected Set<Integer> delegate() { 619 return backing; 620 } 621 622 @Override 623 public boolean add(Integer element) { 624 checkArgument(element >= 0); 625 return super.add(element); 626 } 627 628 @Override 629 public boolean addAll(Collection<? extends Integer> collection) { 630 return standardAddAll(collection); 631 } 632 }; 633 } 634 }; 635 636 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 637 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory); 638 try { 639 multimap.put(Color.BLUE, -1); 640 fail("Expected IllegalArgumentException"); 641 } catch (IllegalArgumentException expected) { 642 } 643 multimap.put(Color.RED, 1); 644 multimap.put(Color.BLUE, 2); 645 try { 646 multimap.put(Color.GREEN, -1); 647 fail("Expected IllegalArgumentException"); 648 } catch (IllegalArgumentException expected) { 649 } 650 assertThat(multimap.entries()) 651 .containsExactly(Maps.immutableEntry(Color.RED, 1), Maps.immutableEntry(Color.BLUE, 2)); 652 } 653 testNewMultimap()654 public void testNewMultimap() { 655 // The ubiquitous EnumArrayBlockingQueueMultimap 656 CountingSupplier<Queue<Integer>> factory = new QueueSupplier(); 657 658 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 659 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory); 660 assertEquals(0, factory.count); 661 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 662 assertEquals(1, factory.count); 663 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 664 assertEquals(2, factory.count); 665 assertEquals("[3, 1, 4]", multimap.get(Color.BLUE).toString()); 666 667 Multimap<Color, Integer> ummodifiable = Multimaps.unmodifiableMultimap(multimap); 668 assertEquals("[3, 1, 4]", ummodifiable.get(Color.BLUE).toString()); 669 670 Collection<Integer> collection = multimap.get(Color.BLUE); 671 // Explicitly call `equals`; `assertEquals` might return fast 672 assertTrue(collection.equals(collection)); 673 674 assertFalse(multimap.keySet() instanceof SortedSet); 675 assertFalse(multimap.asMap() instanceof SortedMap); 676 } 677 testNewMultimapValueCollectionMatchesNavigableSet()678 public void testNewMultimapValueCollectionMatchesNavigableSet() { 679 Supplier<TreeSet<Integer>> factory = new SortedSetSupplier(); 680 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 681 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory); 682 assertTrue(multimap.get(Color.BLUE) instanceof NavigableSet); 683 } 684 testNewMultimapValueCollectionMatchesList()685 public void testNewMultimapValueCollectionMatchesList() { 686 Supplier<LinkedList<Integer>> factory = new ListSupplier(); 687 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 688 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory); 689 assertTrue(multimap.get(Color.BLUE) instanceof List); 690 } 691 692 @GwtIncompatible // SerializableTester testNewMultimapSerialization()693 public void testNewMultimapSerialization() { 694 CountingSupplier<Queue<Integer>> factory = new QueueSupplier(); 695 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 696 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory); 697 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 698 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 699 SerializableTester.reserializeAndAssert(multimap); 700 } 701 702 private static class ListSupplier extends CountingSupplier<LinkedList<Integer>> { 703 @Override getImpl()704 public LinkedList<Integer> getImpl() { 705 return new LinkedList<>(); 706 } 707 708 private static final long serialVersionUID = 0; 709 } 710 testNewListMultimap()711 public void testNewListMultimap() { 712 CountingSupplier<LinkedList<Integer>> factory = new ListSupplier(); 713 Map<Color, Collection<Integer>> map = Maps.newTreeMap(); 714 ListMultimap<Color, Integer> multimap = Multimaps.newListMultimap(map, factory); 715 assertEquals(0, factory.count); 716 multimap.putAll(Color.BLUE, asList(3, 1, 4, 1)); 717 assertEquals(1, factory.count); 718 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 719 assertEquals(2, factory.count); 720 assertEquals("{BLUE=[3, 1, 4, 1], RED=[2, 7, 1, 8]}", multimap.toString()); 721 assertFalse(multimap.get(Color.BLUE) instanceof RandomAccess); 722 723 assertTrue(multimap.keySet() instanceof SortedSet); 724 assertTrue(multimap.asMap() instanceof SortedMap); 725 } 726 727 @GwtIncompatible // SerializableTester testNewListMultimapSerialization()728 public void testNewListMultimapSerialization() { 729 CountingSupplier<LinkedList<Integer>> factory = new ListSupplier(); 730 Map<Color, Collection<Integer>> map = Maps.newTreeMap(); 731 ListMultimap<Color, Integer> multimap = Multimaps.newListMultimap(map, factory); 732 multimap.putAll(Color.BLUE, asList(3, 1, 4, 1)); 733 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 734 SerializableTester.reserializeAndAssert(multimap); 735 } 736 737 private static class SetSupplier extends CountingSupplier<Set<Integer>> { 738 @Override getImpl()739 public Set<Integer> getImpl() { 740 return new HashSet<>(4); 741 } 742 743 private static final long serialVersionUID = 0; 744 } 745 testNewSetMultimap()746 public void testNewSetMultimap() { 747 CountingSupplier<Set<Integer>> factory = new SetSupplier(); 748 Map<Color, Collection<Integer>> map = Maps.newHashMap(); 749 SetMultimap<Color, Integer> multimap = Multimaps.newSetMultimap(map, factory); 750 assertEquals(0, factory.count); 751 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 752 assertEquals(1, factory.count); 753 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 754 assertEquals(2, factory.count); 755 assertEquals(Sets.newHashSet(4, 3, 1), multimap.get(Color.BLUE)); 756 } 757 758 @GwtIncompatible // SerializableTester testNewSetMultimapSerialization()759 public void testNewSetMultimapSerialization() { 760 CountingSupplier<Set<Integer>> factory = new SetSupplier(); 761 Map<Color, Collection<Integer>> map = Maps.newHashMap(); 762 SetMultimap<Color, Integer> multimap = Multimaps.newSetMultimap(map, factory); 763 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 764 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 765 SerializableTester.reserializeAndAssert(multimap); 766 } 767 768 private static class SortedSetSupplier extends CountingSupplier<TreeSet<Integer>> { 769 @Override getImpl()770 public TreeSet<Integer> getImpl() { 771 return Sets.newTreeSet(INT_COMPARATOR); 772 } 773 774 private static final long serialVersionUID = 0; 775 } 776 testNewSortedSetMultimap()777 public void testNewSortedSetMultimap() { 778 CountingSupplier<TreeSet<Integer>> factory = new SortedSetSupplier(); 779 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 780 SortedSetMultimap<Color, Integer> multimap = Multimaps.newSortedSetMultimap(map, factory); 781 // newSortedSetMultimap calls the factory once to determine the comparator. 782 assertEquals(1, factory.count); 783 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 784 assertEquals(2, factory.count); 785 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 786 assertEquals(3, factory.count); 787 assertEquals("[4, 3, 1]", multimap.get(Color.BLUE).toString()); 788 assertEquals(INT_COMPARATOR, multimap.valueComparator()); 789 } 790 791 @GwtIncompatible // SerializableTester testNewSortedSetMultimapSerialization()792 public void testNewSortedSetMultimapSerialization() { 793 CountingSupplier<TreeSet<Integer>> factory = new SortedSetSupplier(); 794 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class); 795 SortedSetMultimap<Color, Integer> multimap = Multimaps.newSortedSetMultimap(map, factory); 796 multimap.putAll(Color.BLUE, asList(3, 1, 4)); 797 multimap.putAll(Color.RED, asList(2, 7, 1, 8)); 798 SerializableTester.reserializeAndAssert(multimap); 799 assertEquals(INT_COMPARATOR, multimap.valueComparator()); 800 } 801 testIndex()802 public void testIndex() { 803 final Multimap<String, Object> stringToObject = 804 new ImmutableMultimap.Builder<String, Object>() 805 .put("1", 1) 806 .put("1", 1L) 807 .put("1", "1") 808 .put("2", 2) 809 .put("2", 2L) 810 .build(); 811 812 ImmutableMultimap<String, Object> outputMap = 813 Multimaps.index(stringToObject.values(), Functions.toStringFunction()); 814 assertEquals(stringToObject, outputMap); 815 } 816 testIndexIterator()817 public void testIndexIterator() { 818 final Multimap<String, Object> stringToObject = 819 new ImmutableMultimap.Builder<String, Object>() 820 .put("1", 1) 821 .put("1", 1L) 822 .put("1", "1") 823 .put("2", 2) 824 .put("2", 2L) 825 .build(); 826 827 ImmutableMultimap<String, Object> outputMap = 828 Multimaps.index(stringToObject.values().iterator(), Functions.toStringFunction()); 829 assertEquals(stringToObject, outputMap); 830 } 831 testIndex_ordering()832 public void testIndex_ordering() { 833 final Multimap<Integer, String> expectedIndex = 834 new ImmutableListMultimap.Builder<Integer, String>() 835 .put(4, "Inky") 836 .put(6, "Blinky") 837 .put(5, "Pinky") 838 .put(5, "Pinky") 839 .put(5, "Clyde") 840 .build(); 841 842 final List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde"); 843 final Function<String, Integer> stringLengthFunction = 844 new Function<String, Integer>() { 845 @Override 846 public Integer apply(String input) { 847 return input.length(); 848 } 849 }; 850 851 Multimap<Integer, String> index = Multimaps.index(badGuys, stringLengthFunction); 852 853 assertEquals(expectedIndex, index); 854 } 855 testIndex_nullValue()856 public void testIndex_nullValue() { 857 List<Integer> values = Arrays.asList(1, null); 858 try { 859 Multimaps.index(values, Functions.identity()); 860 fail(); 861 } catch (NullPointerException expected) { 862 } 863 } 864 testIndex_nullKey()865 public void testIndex_nullKey() { 866 List<Integer> values = Arrays.asList(1, 2); 867 try { 868 Multimaps.index(values, Functions.constant(null)); 869 fail(); 870 } catch (NullPointerException expected) { 871 } 872 } 873 874 @GwtIncompatible(value = "untested") testTransformValues()875 public void testTransformValues() { 876 SetMultimap<String, Integer> multimap = 877 ImmutableSetMultimap.of("a", 2, "b", -3, "b", 3, "a", 4, "c", 6); 878 Function<Integer, Integer> square = 879 new Function<Integer, Integer>() { 880 @Override 881 public Integer apply(Integer in) { 882 return in * in; 883 } 884 }; 885 Multimap<String, Integer> transformed = Multimaps.transformValues(multimap, square); 886 assertThat(transformed.entries()) 887 .containsExactly( 888 immutableEntry("a", 4), 889 immutableEntry("a", 16), 890 immutableEntry("b", 9), 891 immutableEntry("b", 9), 892 immutableEntry("c", 36)) 893 .inOrder(); 894 } 895 896 @GwtIncompatible(value = "untested") testTransformValuesIsView()897 public void testTransformValuesIsView() { 898 Multimap<String, String> multimap = LinkedListMultimap.create(); 899 multimap.put("a", "a"); 900 Multimap<String, Integer> transformed = 901 Multimaps.transformValues( 902 multimap, 903 new Function<String, Integer>() { 904 905 @Override 906 public Integer apply(String str) { 907 return str.length(); 908 } 909 }); 910 Entry<String, String> entry = multimap.entries().iterator().next(); 911 entry.setValue("bbb"); 912 assertThat(transformed.entries()).containsExactly(immutableEntry("a", 3)); 913 } 914 915 @GwtIncompatible(value = "untested") testTransformListValues()916 public void testTransformListValues() { 917 ListMultimap<String, Integer> multimap = 918 ImmutableListMultimap.of("a", 2, "b", -3, "b", 3, "a", 4, "c", 6); 919 Function<Integer, Integer> square = 920 new Function<Integer, Integer>() { 921 @Override 922 public Integer apply(Integer in) { 923 return in * in; 924 } 925 }; 926 ListMultimap<String, Integer> transformed = Multimaps.transformValues(multimap, square); 927 assertThat(transformed.entries()) 928 .containsExactly( 929 immutableEntry("a", 4), 930 immutableEntry("a", 16), 931 immutableEntry("b", 9), 932 immutableEntry("b", 9), 933 immutableEntry("c", 36)) 934 .inOrder(); 935 } 936 937 @GwtIncompatible(value = "untested") testTransformEntries()938 public void testTransformEntries() { 939 SetMultimap<String, Integer> multimap = ImmutableSetMultimap.of("a", 1, "a", 4, "b", -6); 940 EntryTransformer<String, Integer, String> transformer = 941 new EntryTransformer<String, Integer, String>() { 942 @Override 943 public String transformEntry(String key, Integer value) { 944 return (value >= 0) ? key : "no" + key; 945 } 946 }; 947 Multimap<String, String> transformed = Multimaps.transformEntries(multimap, transformer); 948 assertThat(transformed.entries()) 949 .containsExactly( 950 immutableEntry("a", "a"), immutableEntry("a", "a"), immutableEntry("b", "nob")) 951 .inOrder(); 952 } 953 954 @GwtIncompatible(value = "untested") testTransformListEntries()955 public void testTransformListEntries() { 956 ListMultimap<String, Integer> multimap = 957 ImmutableListMultimap.of("a", 1, "a", 4, "b", 6, "a", 4); 958 EntryTransformer<String, Integer, String> transformer = 959 new EntryTransformer<String, Integer, String>() { 960 @Override 961 public String transformEntry(String key, Integer value) { 962 return key + value; 963 } 964 }; 965 ListMultimap<String, String> transformed = Multimaps.transformEntries(multimap, transformer); 966 assertEquals(ImmutableListMultimap.of("a", "a1", "a", "a4", "a", "a4", "b", "b6"), transformed); 967 assertEquals("{a=[a1, a4, a4], b=[b6]}", transformed.toString()); 968 } 969 testSynchronizedMultimapSampleCodeCompilation()970 public <K, V> void testSynchronizedMultimapSampleCodeCompilation() { 971 K key = null; 972 973 Multimap<K, V> multimap = Multimaps.synchronizedMultimap(HashMultimap.<K, V>create()); 974 Collection<V> values = multimap.get(key); // Needn't be in synchronized block 975 synchronized (multimap) { // Synchronizing on multimap, not values! 976 Iterator<V> i = values.iterator(); // Must be in synchronized block 977 while (i.hasNext()) { 978 foo(i.next()); 979 } 980 } 981 } 982 foo(Object o)983 private static void foo(Object o) {} 984 testFilteredKeysSetMultimapReplaceValues()985 public void testFilteredKeysSetMultimapReplaceValues() { 986 SetMultimap<String, Integer> multimap = LinkedHashMultimap.create(); 987 multimap.put("foo", 1); 988 multimap.put("bar", 2); 989 multimap.put("baz", 3); 990 multimap.put("bar", 4); 991 992 SetMultimap<String, Integer> filtered = 993 Multimaps.filterKeys(multimap, Predicates.in(ImmutableSet.of("foo", "bar"))); 994 995 assertEquals(ImmutableSet.of(), filtered.replaceValues("baz", ImmutableSet.<Integer>of())); 996 997 try { 998 filtered.replaceValues("baz", ImmutableSet.of(5)); 999 fail("Expected IllegalArgumentException"); 1000 } catch (IllegalArgumentException expected) { 1001 } 1002 } 1003 testFilteredKeysSetMultimapGetBadValue()1004 public void testFilteredKeysSetMultimapGetBadValue() { 1005 SetMultimap<String, Integer> multimap = LinkedHashMultimap.create(); 1006 multimap.put("foo", 1); 1007 multimap.put("bar", 2); 1008 multimap.put("baz", 3); 1009 multimap.put("bar", 4); 1010 1011 SetMultimap<String, Integer> filtered = 1012 Multimaps.filterKeys(multimap, Predicates.in(ImmutableSet.of("foo", "bar"))); 1013 Set<Integer> bazSet = filtered.get("baz"); 1014 assertThat(bazSet).isEmpty(); 1015 try { 1016 bazSet.add(5); 1017 fail("Expected IllegalArgumentException"); 1018 } catch (IllegalArgumentException expected) { 1019 } 1020 try { 1021 bazSet.addAll(ImmutableSet.of(6, 7)); 1022 fail("Expected IllegalArgumentException"); 1023 } catch (IllegalArgumentException expected) { 1024 } 1025 } 1026 testFilteredKeysListMultimapGetBadValue()1027 public void testFilteredKeysListMultimapGetBadValue() { 1028 ListMultimap<String, Integer> multimap = ArrayListMultimap.create(); 1029 multimap.put("foo", 1); 1030 multimap.put("bar", 2); 1031 multimap.put("baz", 3); 1032 multimap.put("bar", 4); 1033 1034 ListMultimap<String, Integer> filtered = 1035 Multimaps.filterKeys(multimap, Predicates.in(ImmutableSet.of("foo", "bar"))); 1036 List<Integer> bazList = filtered.get("baz"); 1037 assertThat(bazList).isEmpty(); 1038 try { 1039 bazList.add(5); 1040 fail("Expected IllegalArgumentException"); 1041 } catch (IllegalArgumentException expected) { 1042 } 1043 try { 1044 bazList.add(0, 6); 1045 fail("Expected IllegalArgumentException"); 1046 } catch (IllegalArgumentException expected) { 1047 } 1048 try { 1049 bazList.addAll(ImmutableList.of(7, 8)); 1050 fail("Expected IllegalArgumentException"); 1051 } catch (IllegalArgumentException expected) { 1052 } 1053 try { 1054 bazList.addAll(0, ImmutableList.of(9, 10)); 1055 fail("Expected IllegalArgumentException"); 1056 } catch (IllegalArgumentException expected) { 1057 } 1058 } 1059 1060 @GwtIncompatible // NullPointerTester 1061 @AndroidIncompatible // see ImmutableTableTest.testNullPointerInstance testNullPointers()1062 public void testNullPointers() { 1063 new NullPointerTester().testAllPublicStaticMethods(Multimaps.class); 1064 } 1065 } 1066