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