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.Sets.newHashSet;
21 import static com.google.common.collect.testing.Helpers.nefariousMapEntry;
22 import static com.google.common.collect.testing.IteratorFeature.MODIFIABLE;
23 import static com.google.common.truth.Truth.assertThat;
24 import static java.util.Arrays.asList;
25
26 import com.google.common.annotations.GwtCompatible;
27 import com.google.common.base.Function;
28 import com.google.common.base.Functions;
29 import com.google.common.base.Predicates;
30 import com.google.common.base.Supplier;
31 import com.google.common.collect.Maps.EntryTransformer;
32 import com.google.common.collect.testing.IteratorTester;
33 import com.google.common.collect.testing.google.UnmodifiableCollectionTests;
34
35 import junit.framework.TestCase;
36
37 import java.io.Serializable;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.LinkedList;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Map.Entry;
49 import java.util.Queue;
50 import java.util.RandomAccess;
51 import java.util.Set;
52 import java.util.SortedMap;
53 import java.util.SortedSet;
54 import java.util.TreeSet;
55
56 import javax.annotation.Nullable;
57
58
59
60
61
62
63 @GwtCompatible(emulated = true)
64 public class MultimapsTest extends TestCase {
65
66 private static final Comparator<Integer> INT_COMPARATOR =
67 Ordering.<Integer>natural().reverse().nullsFirst();
68
69 private static final EntryTransformer<Object, Object, Object> ALWAYS_NULL =
70 new EntryTransformer<Object, Object, Object>() {
71 @Override
72 public Object transformEntry(Object k, Object v1) {
73 return null;
74 }
75 };
76
77 @SuppressWarnings("deprecation")
78 public void testUnmodifiableListMultimapShortCircuit() {
79 ListMultimap<String, Integer> mod = ArrayListMultimap.create();
80 ListMultimap<String, Integer> unmod = Multimaps.unmodifiableListMultimap(mod);
81 assertNotSame(mod, unmod);
82 assertSame(unmod, Multimaps.unmodifiableListMultimap(unmod));
83 ImmutableListMultimap<String, Integer> immutable =
84 ImmutableListMultimap.of("a", 1, "b", 2, "a", 3);
85 assertSame(immutable, Multimaps.unmodifiableListMultimap(immutable));
86 assertSame(
87 immutable, Multimaps.unmodifiableListMultimap((ListMultimap<String, Integer>) immutable));
88 }
89
90 @SuppressWarnings("deprecation")
91 public void testUnmodifiableSetMultimapShortCircuit() {
92 SetMultimap<String, Integer> mod = HashMultimap.create();
93 SetMultimap<String, Integer> unmod = Multimaps.unmodifiableSetMultimap(mod);
94 assertNotSame(mod, unmod);
95 assertSame(unmod, Multimaps.unmodifiableSetMultimap(unmod));
96 ImmutableSetMultimap<String, Integer> immutable =
97 ImmutableSetMultimap.of("a", 1, "b", 2, "a", 3);
98 assertSame(immutable, Multimaps.unmodifiableSetMultimap(immutable));
99 assertSame(
100 immutable, Multimaps.unmodifiableSetMultimap((SetMultimap<String, Integer>) immutable));
101 }
102
103 @SuppressWarnings("deprecation")
104 public void testUnmodifiableMultimapShortCircuit() {
105 Multimap<String, Integer> mod = HashMultimap.create();
106 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
107 assertNotSame(mod, unmod);
108 assertSame(unmod, Multimaps.unmodifiableMultimap(unmod));
109 ImmutableMultimap<String, Integer> immutable = ImmutableMultimap.of("a", 1, "b", 2, "a", 3);
110 assertSame(immutable, Multimaps.unmodifiableMultimap(immutable));
111 assertSame(immutable, Multimaps.unmodifiableMultimap((Multimap<String, Integer>) immutable));
112 }
113
114 public void testUnmodifiableArrayListMultimapRandomAccess() {
115 ListMultimap<String, Integer> delegate = ArrayListMultimap.create();
116 delegate.put("foo", 1);
117 delegate.put("foo", 3);
118 ListMultimap<String, Integer> multimap
119 = Multimaps.unmodifiableListMultimap(delegate);
120 assertTrue(multimap.get("foo") instanceof RandomAccess);
121 assertTrue(multimap.get("bar") instanceof RandomAccess);
122 }
123
124 public void testUnmodifiableLinkedListMultimapRandomAccess() {
125 ListMultimap<String, Integer> delegate = LinkedListMultimap.create();
126 delegate.put("foo", 1);
127 delegate.put("foo", 3);
128 ListMultimap<String, Integer> multimap
129 = Multimaps.unmodifiableListMultimap(delegate);
130 assertFalse(multimap.get("foo") instanceof RandomAccess);
131 assertFalse(multimap.get("bar") instanceof RandomAccess);
132 }
133
134 public void testUnmodifiableMultimapIsView() {
135 Multimap<String, Integer> mod = HashMultimap.create();
136 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
137 assertEquals(mod, unmod);
138 mod.put("foo", 1);
139 assertTrue(unmod.containsEntry("foo", 1));
140 assertEquals(mod, unmod);
141 }
142
143 @SuppressWarnings("unchecked")
144 public void testUnmodifiableMultimapEntries() {
145 Multimap<String, Integer> mod = HashMultimap.create();
146 Multimap<String, Integer> unmod = Multimaps.unmodifiableMultimap(mod);
147 mod.put("foo", 1);
148 Entry<String, Integer> entry = unmod.entries().iterator().next();
149 try {
150 entry.setValue(2);
151 fail("UnsupportedOperationException expected");
152 } catch (UnsupportedOperationException expected) {}
153 entry = (Entry<String, Integer>) unmod.entries().toArray()[0];
154 try {
155 entry.setValue(2);
156 fail("UnsupportedOperationException expected");
157 } catch (UnsupportedOperationException expected) {}
158 Entry<String, Integer>[] array
159 = (Entry<String, Integer>[]) new Entry<?, ?>[2];
160 assertSame(array, unmod.entries().toArray(array));
161 try {
162 array[0].setValue(2);
163 fail("UnsupportedOperationException expected");
164 } catch (UnsupportedOperationException expected) {}
165 assertFalse(unmod.entries().contains(nefariousMapEntry("pwnd", 2)));
166 assertFalse(unmod.keys().contains("pwnd"));
167 }
168
169
170
171
172
173 private static void checkUnmodifiableMultimap(
174 Multimap<String, Integer> multimap, boolean permitsDuplicates) {
175 checkUnmodifiableMultimap(multimap, permitsDuplicates, null, null);
176 }
177
178
179
180
181
182
183 private static void checkUnmodifiableMultimap(
184 Multimap<String, Integer> multimap, boolean permitsDuplicates,
185 @Nullable String nullKey, @Nullable Integer nullValue) {
186 Multimap<String, Integer> unmodifiable =
187 prepareUnmodifiableTests(multimap, permitsDuplicates, nullKey, nullValue);
188
189 UnmodifiableCollectionTests.assertMultimapIsUnmodifiable(
190 unmodifiable, "test", 123);
191
192 assertUnmodifiableIterableInTandem(
193 unmodifiable.keys(), multimap.keys());
194
195 assertUnmodifiableIterableInTandem(
196 unmodifiable.keySet(), multimap.keySet());
197
198 assertUnmodifiableIterableInTandem(
199 unmodifiable.entries(), multimap.entries());
200
201 assertUnmodifiableIterableInTandem(
202 unmodifiable.asMap().entrySet(), multimap.asMap().entrySet());
203
204 assertEquals(multimap.toString(), unmodifiable.toString());
205 assertEquals(multimap.hashCode(), unmodifiable.hashCode());
206 assertEquals(multimap, unmodifiable);
207
208 assertThat(unmodifiable.asMap().get("bar")).has().exactly(5, -1);
209 assertNull(unmodifiable.asMap().get("missing"));
210
211 assertFalse(unmodifiable.entries() instanceof Serializable);
212 }
213
214
215
216
217
218 private static Multimap<String, Integer> prepareUnmodifiableTests(
219 Multimap<String, Integer> multimap, boolean permitsDuplicates,
220 @Nullable String nullKey, @Nullable Integer nullValue) {
221 multimap.clear();
222 multimap.put("foo", 1);
223 multimap.put("foo", 2);
224 multimap.put("foo", 3);
225 multimap.put("bar", 5);
226 multimap.put("bar", -1);
227 multimap.put(nullKey, nullValue);
228 multimap.put("foo", nullValue);
229 multimap.put(nullKey, 5);
230 multimap.put("foo", 2);
231
232 if (permitsDuplicates) {
233 assertEquals(9, multimap.size());
234 } else {
235 assertEquals(8, multimap.size());
236 }
237
238 Multimap<String, Integer> unmodifiable;
239 if (multimap instanceof SortedSetMultimap) {
240 unmodifiable = Multimaps.unmodifiableSortedSetMultimap(
241 (SortedSetMultimap<String, Integer>) multimap);
242 } else if (multimap instanceof SetMultimap) {
243 unmodifiable = Multimaps.unmodifiableSetMultimap(
244 (SetMultimap<String, Integer>) multimap);
245 } else if (multimap instanceof ListMultimap) {
246 unmodifiable = Multimaps.unmodifiableListMultimap(
247 (ListMultimap<String, Integer>) multimap);
248 } else {
249 unmodifiable = Multimaps.unmodifiableMultimap(multimap);
250 }
251 return unmodifiable;
252 }
253
254 private static <T> void assertUnmodifiableIterableInTandem(
255 Iterable<T> unmodifiable, Iterable<T> modifiable) {
256 UnmodifiableCollectionTests.assertIteratorIsUnmodifiable(
257 unmodifiable.iterator());
258 UnmodifiableCollectionTests.assertIteratorsInOrder(
259 unmodifiable.iterator(), modifiable.iterator());
260 }
261
262 public void testInvertFrom() {
263 ImmutableMultimap<Integer, String> empty = ImmutableMultimap.of();
264
265
266 Multimap<String, Integer> multimap = Multimaps.invertFrom(empty,
267 ArrayListMultimap.<String, Integer>create());
268 assertTrue(multimap.isEmpty());
269
270 ImmutableMultimap<Integer, String> single
271 = new ImmutableMultimap.Builder<Integer, String>()
272 .put(1, "one")
273 .put(2, "two")
274 .build();
275
276
277 assertSame(multimap, Multimaps.invertFrom(single, multimap));
278
279 ImmutableMultimap<String, Integer> expected
280 = new ImmutableMultimap.Builder<String, Integer>()
281 .put("one", 1)
282 .put("two", 2)
283 .build();
284
285 assertEquals(expected, multimap);
286 }
287
288 public void testAsMap_multimap() {
289 Multimap<String, Integer> multimap = Multimaps.newMultimap(
290 new HashMap<String, Collection<Integer>>(), new QueueSupplier());
291 Map<String, Collection<Integer>> map = Multimaps.asMap(multimap);
292 assertSame(multimap.asMap(), map);
293 }
294
295 public void testAsMap_listMultimap() {
296 ListMultimap<String, Integer> listMultimap = ArrayListMultimap.create();
297 Map<String, List<Integer>> map = Multimaps.asMap(listMultimap);
298 assertSame(listMultimap.asMap(), map);
299 }
300
301 public void testAsMap_setMultimap() {
302 SetMultimap<String, Integer> setMultimap = LinkedHashMultimap.create();
303 Map<String, Set<Integer>> map = Multimaps.asMap(setMultimap);
304 assertSame(setMultimap.asMap(), map);
305 }
306
307 public void testAsMap_sortedSetMultimap() {
308 SortedSetMultimap<String, Integer> sortedSetMultimap =
309 TreeMultimap.create();
310 Map<String, SortedSet<Integer>> map = Multimaps.asMap(sortedSetMultimap);
311 assertSame(sortedSetMultimap.asMap(), map);
312 }
313
314 public void testForMap() {
315 Map<String, Integer> map = Maps.newHashMap();
316 map.put("foo", 1);
317 map.put("bar", 2);
318 Multimap<String, Integer> multimap = HashMultimap.create();
319 multimap.put("foo", 1);
320 multimap.put("bar", 2);
321 Multimap<String, Integer> multimapView = Multimaps.forMap(map);
322 assertTrue(multimap.equals(multimapView));
323 assertTrue(multimapView.equals(multimap));
324 assertTrue(multimapView.equals(multimapView));
325 assertFalse(multimapView.equals(map));
326 Multimap<String, Integer> multimap2 = HashMultimap.create();
327 multimap2.put("foo", 1);
328 assertFalse(multimapView.equals(multimap2));
329 multimap2.put("bar", 1);
330 assertFalse(multimapView.equals(multimap2));
331 ListMultimap<String, Integer> listMultimap
332 = new ImmutableListMultimap.Builder<String, Integer>()
333 .put("foo", 1).put("bar", 2).build();
334 assertFalse("SetMultimap equals ListMultimap",
335 multimapView.equals(listMultimap));
336 assertEquals(multimap.toString(), multimapView.toString());
337 assertEquals(multimap.hashCode(), multimapView.hashCode());
338 assertEquals(multimap.size(), multimapView.size());
339 assertTrue(multimapView.containsKey("foo"));
340 assertTrue(multimapView.containsValue(1));
341 assertTrue(multimapView.containsEntry("bar", 2));
342 assertEquals(Collections.singleton(1), multimapView.get("foo"));
343 assertEquals(Collections.singleton(2), multimapView.get("bar"));
344 try {
345 multimapView.put("baz", 3);
346 fail("UnsupportedOperationException expected");
347 } catch (UnsupportedOperationException expected) {}
348 try {
349 multimapView.putAll("baz", Collections.singleton(3));
350 fail("UnsupportedOperationException expected");
351 } catch (UnsupportedOperationException expected) {}
352 try {
353 multimapView.putAll(multimap);
354 fail("UnsupportedOperationException expected");
355 } catch (UnsupportedOperationException expected) {}
356 try {
357 multimapView.replaceValues("foo", Collections.<Integer>emptySet());
358 fail("UnsupportedOperationException expected");
359 } catch (UnsupportedOperationException expected) {}
360 multimapView.remove("bar", 2);
361 assertFalse(multimapView.containsKey("bar"));
362 assertFalse(map.containsKey("bar"));
363 assertEquals(map.keySet(), multimapView.keySet());
364 assertEquals(map.keySet(), multimapView.keys().elementSet());
365 assertThat(multimapView.keys()).has().item("foo");
366 assertThat(multimapView.values()).has().item(1);
367 assertThat(multimapView.entries()).has().item(
368 Maps.immutableEntry("foo", 1));
369 assertThat(multimapView.asMap().entrySet()).has().item(
370 Maps.immutableEntry(
371 "foo", (Collection<Integer>) Collections.singleton(1)));
372 multimapView.clear();
373 assertFalse(multimapView.containsKey("foo"));
374 assertFalse(map.containsKey("foo"));
375 assertTrue(map.isEmpty());
376 assertTrue(multimapView.isEmpty());
377 multimap.clear();
378 assertEquals(multimap.toString(), multimapView.toString());
379 assertEquals(multimap.hashCode(), multimapView.hashCode());
380 assertEquals(multimap.size(), multimapView.size());
381 assertEquals(multimapView, ArrayListMultimap.create());
382 }
383
384 public void testForMapRemoveAll() {
385 Map<String, Integer> map = Maps.newHashMap();
386 map.put("foo", 1);
387 map.put("bar", 2);
388 map.put("cow", 3);
389 Multimap<String, Integer> multimap = Multimaps.forMap(map);
390 assertEquals(3, multimap.size());
391 assertEquals(Collections.emptySet(), multimap.removeAll("dog"));
392 assertEquals(3, multimap.size());
393 assertTrue(multimap.containsKey("bar"));
394 assertEquals(Collections.singleton(2), multimap.removeAll("bar"));
395 assertEquals(2, multimap.size());
396 assertFalse(multimap.containsKey("bar"));
397 }
398
399 public void testForMapAsMap() {
400 Map<String, Integer> map = Maps.newHashMap();
401 map.put("foo", 1);
402 map.put("bar", 2);
403 Map<String, Collection<Integer>> asMap = Multimaps.forMap(map).asMap();
404 assertEquals(Collections.singleton(1), asMap.get("foo"));
405 assertNull(asMap.get("cow"));
406 assertTrue(asMap.containsKey("foo"));
407 assertFalse(asMap.containsKey("cow"));
408
409 Set<Entry<String, Collection<Integer>>> entries = asMap.entrySet();
410 assertFalse(entries.contains(4.5));
411 assertFalse(entries.remove(4.5));
412 assertFalse(entries.contains(Maps.immutableEntry("foo",
413 Collections.singletonList(1))));
414 assertFalse(entries.remove(Maps.immutableEntry("foo",
415 Collections.singletonList(1))));
416 assertFalse(entries.contains(Maps.immutableEntry("foo",
417 Sets.newLinkedHashSet(asList(1, 2)))));
418 assertFalse(entries.remove(Maps.immutableEntry("foo",
419 Sets.newLinkedHashSet(asList(1, 2)))));
420 assertFalse(entries.contains(Maps.immutableEntry("foo",
421 Collections.singleton(2))));
422 assertFalse(entries.remove(Maps.immutableEntry("foo",
423 Collections.singleton(2))));
424 assertTrue(map.containsKey("foo"));
425 assertTrue(entries.contains(Maps.immutableEntry("foo",
426 Collections.singleton(1))));
427 assertTrue(entries.remove(Maps.immutableEntry("foo",
428 Collections.singleton(1))));
429 assertFalse(map.containsKey("foo"));
430 }
431
432 public void testForMapGetIteration() {
433 IteratorTester<Integer> tester =
434 new IteratorTester<Integer>(4, MODIFIABLE, newHashSet(1),
435 IteratorTester.KnownOrder.KNOWN_ORDER) {
436 private Multimap<String, Integer> multimap;
437
438 @Override protected Iterator<Integer> newTargetIterator() {
439 Map<String, Integer> map = Maps.newHashMap();
440 map.put("foo", 1);
441 map.put("bar", 2);
442 multimap = Multimaps.forMap(map);
443 return multimap.get("foo").iterator();
444 }
445
446 @Override protected void verify(List<Integer> elements) {
447 assertEquals(newHashSet(elements), multimap.get("foo"));
448 }
449 };
450
451 tester.test();
452 }
453
454 private enum Color {BLUE, RED, YELLOW, GREEN}
455
456 private abstract static class CountingSupplier<E>
457 implements Supplier<E>, Serializable {
458 int count;
459
460 abstract E getImpl();
461
462 @Override
463 public E get() {
464 count++;
465 return getImpl();
466 }
467 }
468
469 private static class QueueSupplier extends CountingSupplier<Queue<Integer>> {
470 @Override public Queue<Integer> getImpl() {
471 return new LinkedList<Integer>();
472 }
473 private static final long serialVersionUID = 0;
474 }
475
476 public void testNewMultimapWithCollectionRejectingNegativeElements() {
477 CountingSupplier<Set<Integer>> factory = new SetSupplier() {
478 @Override
479 public Set<Integer> getImpl() {
480 final Set<Integer> backing = super.getImpl();
481 return new ForwardingSet<Integer>() {
482 @Override
483 protected Set<Integer> delegate() {
484 return backing;
485 }
486
487 @Override
488 public boolean add(Integer element) {
489 checkArgument(element >= 0);
490 return super.add(element);
491 }
492
493 @Override
494 public boolean addAll(Collection<? extends Integer> collection) {
495 return standardAddAll(collection);
496 }
497 };
498 }
499 };
500
501 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
502 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory);
503 try {
504 multimap.put(Color.BLUE, -1);
505 fail("Expected IllegalArgumentException");
506 } catch (IllegalArgumentException expected) {
507
508 }
509 multimap.put(Color.RED, 1);
510 multimap.put(Color.BLUE, 2);
511 try {
512 multimap.put(Color.GREEN, -1);
513 fail("Expected IllegalArgumentException");
514 } catch (IllegalArgumentException expected) {
515
516 }
517 assertThat(multimap.entries()).has().exactly(
518 Maps.immutableEntry(Color.RED, 1),
519 Maps.immutableEntry(Color.BLUE, 2));
520 }
521
522 public void testNewMultimap() {
523
524 CountingSupplier<Queue<Integer>> factory = new QueueSupplier();
525
526 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
527 Multimap<Color, Integer> multimap = Multimaps.newMultimap(map, factory);
528 assertEquals(0, factory.count);
529 multimap.putAll(Color.BLUE, asList(3, 1, 4));
530 assertEquals(1, factory.count);
531 multimap.putAll(Color.RED, asList(2, 7, 1, 8));
532 assertEquals(2, factory.count);
533 assertEquals("[3, 1, 4]", multimap.get(Color.BLUE).toString());
534
535 Multimap<Color, Integer> ummodifiable =
536 Multimaps.unmodifiableMultimap(multimap);
537 assertEquals("[3, 1, 4]", ummodifiable.get(Color.BLUE).toString());
538
539 Collection<Integer> collection = multimap.get(Color.BLUE);
540 assertEquals(collection, collection);
541
542 assertFalse(multimap.keySet() instanceof SortedSet);
543 assertFalse(multimap.asMap() instanceof SortedMap);
544 }
545
546 private static class ListSupplier extends
547 CountingSupplier<LinkedList<Integer>> {
548 @Override public LinkedList<Integer> getImpl() {
549 return new LinkedList<Integer>();
550 }
551 private static final long serialVersionUID = 0;
552 }
553
554 public void testNewListMultimap() {
555 CountingSupplier<LinkedList<Integer>> factory = new ListSupplier();
556 Map<Color, Collection<Integer>> map = Maps.newTreeMap();
557 ListMultimap<Color, Integer> multimap =
558 Multimaps.newListMultimap(map, factory);
559 assertEquals(0, factory.count);
560 multimap.putAll(Color.BLUE, asList(3, 1, 4, 1));
561 assertEquals(1, factory.count);
562 multimap.putAll(Color.RED, asList(2, 7, 1, 8));
563 assertEquals(2, factory.count);
564 assertEquals("{BLUE=[3, 1, 4, 1], RED=[2, 7, 1, 8]}", multimap.toString());
565 assertFalse(multimap.get(Color.BLUE) instanceof RandomAccess);
566
567 assertTrue(multimap.keySet() instanceof SortedSet);
568 assertTrue(multimap.asMap() instanceof SortedMap);
569 }
570
571 private static class SetSupplier extends CountingSupplier<Set<Integer>> {
572 @Override public Set<Integer> getImpl() {
573 return new HashSet<Integer>(4);
574 }
575 private static final long serialVersionUID = 0;
576 }
577
578 public void testNewSetMultimap() {
579 CountingSupplier<Set<Integer>> factory = new SetSupplier();
580 Map<Color, Collection<Integer>> map = Maps.newHashMap();
581 SetMultimap<Color, Integer> multimap =
582 Multimaps.newSetMultimap(map, factory);
583 assertEquals(0, factory.count);
584 multimap.putAll(Color.BLUE, asList(3, 1, 4));
585 assertEquals(1, factory.count);
586 multimap.putAll(Color.RED, asList(2, 7, 1, 8));
587 assertEquals(2, factory.count);
588 assertEquals(Sets.newHashSet(4, 3, 1), multimap.get(Color.BLUE));
589 }
590
591 private static class SortedSetSupplier extends
592 CountingSupplier<TreeSet<Integer>> {
593 @Override public TreeSet<Integer> getImpl() {
594 return Sets.newTreeSet(INT_COMPARATOR);
595 }
596 private static final long serialVersionUID = 0;
597 }
598
599 public void testNewSortedSetMultimap() {
600 CountingSupplier<TreeSet<Integer>> factory = new SortedSetSupplier();
601 Map<Color, Collection<Integer>> map = Maps.newEnumMap(Color.class);
602 SortedSetMultimap<Color, Integer> multimap =
603 Multimaps.newSortedSetMultimap(map, factory);
604
605 assertEquals(1, factory.count);
606 multimap.putAll(Color.BLUE, asList(3, 1, 4));
607 assertEquals(2, factory.count);
608 multimap.putAll(Color.RED, asList(2, 7, 1, 8));
609 assertEquals(3, factory.count);
610 assertEquals("[4, 3, 1]", multimap.get(Color.BLUE).toString());
611 assertEquals(INT_COMPARATOR, multimap.valueComparator());
612 }
613
614 public void testIndex() {
615 final Multimap<String, Object> stringToObject =
616 new ImmutableMultimap.Builder<String, Object>()
617 .put("1", 1)
618 .put("1", 1L)
619 .put("1", "1")
620 .put("2", 2)
621 .put("2", 2L)
622 .build();
623
624 ImmutableMultimap<String, Object> outputMap =
625 Multimaps.index(stringToObject.values(),
626 Functions.toStringFunction());
627 assertEquals(stringToObject, outputMap);
628 }
629
630 public void testIndexIterator() {
631 final Multimap<String, Object> stringToObject =
632 new ImmutableMultimap.Builder<String, Object>()
633 .put("1", 1)
634 .put("1", 1L)
635 .put("1", "1")
636 .put("2", 2)
637 .put("2", 2L)
638 .build();
639
640 ImmutableMultimap<String, Object> outputMap =
641 Multimaps.index(stringToObject.values().iterator(),
642 Functions.toStringFunction());
643 assertEquals(stringToObject, outputMap);
644 }
645
646 public void testIndex_ordering() {
647 final Multimap<Integer, String> expectedIndex =
648 new ImmutableListMultimap.Builder<Integer, String>()
649 .put(4, "Inky")
650 .put(6, "Blinky")
651 .put(5, "Pinky")
652 .put(5, "Pinky")
653 .put(5, "Clyde")
654 .build();
655
656 final List<String> badGuys =
657 Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
658 final Function<String, Integer> stringLengthFunction =
659 new Function<String, Integer>() {
660 @Override
661 public Integer apply(String input) {
662 return input.length();
663 }
664 };
665
666 Multimap<Integer, String> index =
667 Multimaps.index(badGuys, stringLengthFunction);
668
669 assertEquals(expectedIndex, index);
670 }
671
672 public void testIndex_nullValue() {
673 List<Integer> values = Arrays.asList(1, null);
674 try {
675 Multimaps.index(values, Functions.identity());
676 fail();
677 } catch (NullPointerException e) {}
678 }
679
680 public void testIndex_nullKey() {
681 List<Integer> values = Arrays.asList(1, 2);
682 try {
683 Multimaps.index(values, Functions.constant(null));
684 fail();
685 } catch (NullPointerException e) {}
686 }
687
688 public <K, V> void testSynchronizedMultimapSampleCodeCompilation() {
689 K key = null;
690
691 Multimap<K, V> multimap = Multimaps.synchronizedMultimap(
692 HashMultimap.<K, V>create());
693 Collection<V> values = multimap.get(key);
694 synchronized (multimap) {
695 Iterator<V> i = values.iterator();
696 while (i.hasNext()) {
697 foo(i.next());
698 }
699 }
700 }
701
702 private static void foo(Object o) {}
703
704 public void testFilteredKeysSetMultimapReplaceValues() {
705 SetMultimap<String, Integer> multimap = LinkedHashMultimap.create();
706 multimap.put("foo", 1);
707 multimap.put("bar", 2);
708 multimap.put("baz", 3);
709 multimap.put("bar", 4);
710
711 SetMultimap<String, Integer> filtered = Multimaps.filterKeys(
712 multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
713
714 assertEquals(
715 ImmutableSet.of(),
716 filtered.replaceValues("baz", ImmutableSet.<Integer>of()));
717
718 try {
719 filtered.replaceValues("baz", ImmutableSet.of(5));
720 fail("Expected IllegalArgumentException");
721 } catch (IllegalArgumentException expected) {
722 }
723 }
724
725 public void testFilteredKeysSetMultimapGetBadValue() {
726 SetMultimap<String, Integer> multimap = LinkedHashMultimap.create();
727 multimap.put("foo", 1);
728 multimap.put("bar", 2);
729 multimap.put("baz", 3);
730 multimap.put("bar", 4);
731
732 SetMultimap<String, Integer> filtered = Multimaps.filterKeys(
733 multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
734 Set<Integer> bazSet = filtered.get("baz");
735 assertThat(bazSet).isEmpty();
736 try {
737 bazSet.add(5);
738 fail("Expected IllegalArgumentException");
739 } catch (IllegalArgumentException expected) {
740 }
741 try {
742 bazSet.addAll(ImmutableSet.of(6, 7));
743 fail("Expected IllegalArgumentException");
744 } catch (IllegalArgumentException expected) {
745 }
746 }
747
748 public void testFilteredKeysListMultimapGetBadValue() {
749 ListMultimap<String, Integer> multimap = ArrayListMultimap.create();
750 multimap.put("foo", 1);
751 multimap.put("bar", 2);
752 multimap.put("baz", 3);
753 multimap.put("bar", 4);
754
755 ListMultimap<String, Integer> filtered = Multimaps.filterKeys(
756 multimap, Predicates.in(ImmutableSet.of("foo", "bar")));
757 List<Integer> bazList = filtered.get("baz");
758 assertThat(bazList).isEmpty();
759 try {
760 bazList.add(5);
761 fail("Expected IllegalArgumentException");
762 } catch (IllegalArgumentException expected) {
763 }
764 try {
765 bazList.add(0, 6);
766 fail("Expected IllegalArgumentException");
767 } catch (IllegalArgumentException expected) {
768 }
769 try {
770 bazList.addAll(ImmutableList.of(7, 8));
771 fail("Expected IllegalArgumentException");
772 } catch (IllegalArgumentException expected) {
773 }
774 try {
775 bazList.addAll(0, ImmutableList.of(9, 10));
776 fail("Expected IllegalArgumentException");
777 } catch (IllegalArgumentException expected) {
778 }
779 }
780 }
781