• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.collect.Maps.newHashMap;
20 import static com.google.common.collect.testing.Helpers.mapEntry;
21 import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
22 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
23 import static com.google.common.collect.testing.google.AbstractMultisetSetCountTester.getSetCountDuplicateInitializingMethods;
24 import static com.google.common.collect.testing.google.MultisetCountTester.getCountDuplicateInitializingMethods;
25 import static com.google.common.collect.testing.google.MultisetElementSetTester.getElementSetDuplicateInitializingMethods;
26 import static com.google.common.collect.testing.google.MultisetIteratorTester.getIteratorDuplicateInitializingMethods;
27 import static com.google.common.collect.testing.google.MultisetRemoveTester.getRemoveDuplicateInitializingMethods;
28 import static java.lang.reflect.Proxy.newProxyInstance;
29 
30 import com.google.common.annotations.GwtIncompatible;
31 import com.google.common.base.Ascii;
32 import com.google.common.base.Function;
33 import com.google.common.base.Predicate;
34 import com.google.common.base.Predicates;
35 import com.google.common.base.Supplier;
36 import com.google.common.collect.Maps.EntryTransformer;
37 import com.google.common.collect.testing.SampleElements;
38 import com.google.common.collect.testing.SetTestSuiteBuilder;
39 import com.google.common.collect.testing.TestCollectionGenerator;
40 import com.google.common.collect.testing.TestListGenerator;
41 import com.google.common.collect.testing.TestStringSetGenerator;
42 import com.google.common.collect.testing.features.CollectionFeature;
43 import com.google.common.collect.testing.features.CollectionSize;
44 import com.google.common.collect.testing.features.Feature;
45 import com.google.common.collect.testing.features.MapFeature;
46 import com.google.common.collect.testing.google.ListMultimapTestSuiteBuilder;
47 import com.google.common.collect.testing.google.MultimapFeature;
48 import com.google.common.collect.testing.google.MultimapTestSuiteBuilder;
49 import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
50 import com.google.common.collect.testing.google.SetMultimapTestSuiteBuilder;
51 import com.google.common.collect.testing.google.TestListMultimapGenerator;
52 import com.google.common.collect.testing.google.TestMultimapGenerator;
53 import com.google.common.collect.testing.google.TestSetMultimapGenerator;
54 import com.google.common.collect.testing.google.TestStringListMultimapGenerator;
55 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
56 import java.lang.reflect.InvocationHandler;
57 import java.lang.reflect.Method;
58 import java.util.Collection;
59 import java.util.List;
60 import java.util.Map;
61 import java.util.Map.Entry;
62 import java.util.Set;
63 import java.util.TreeSet;
64 import junit.framework.Test;
65 import junit.framework.TestCase;
66 import junit.framework.TestSuite;
67 
68 /**
69  * Run collection tests on wrappers from {@link Multimaps}.
70  *
71  * @author Jared Levy
72  */
73 @GwtIncompatible // suite // TODO(cpovirk): set up collect/gwt/suites version
74 public class MultimapsCollectionTest extends TestCase {
75 
76   private static final Feature<?>[] FOR_MAP_FEATURES_ONE = {
77     CollectionSize.ONE,
78     ALLOWS_NULL_VALUES,
79     SUPPORTS_REMOVE,
80     CollectionFeature.SUPPORTS_ITERATOR_REMOVE
81   };
82 
83   private static final Feature<?>[] FOR_MAP_FEATURES_ANY = {
84     CollectionSize.ANY,
85     ALLOWS_NULL_VALUES,
86     SUPPORTS_REMOVE,
87     CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
88     MultisetTestSuiteBuilder.NoRecurse.NO_ENTRY_SET, // Cannot create entries with count > 1
89   };
90 
91   static final Supplier<TreeSet<String>> STRING_TREESET_FACTORY =
92       new Supplier<TreeSet<String>>() {
93         @Override
94         public TreeSet<String> get() {
95           return new TreeSet<>(Ordering.natural().nullsLast());
96         }
97       };
98 
populateMultimapForGet(Multimap<Integer, String> multimap, String[] elements)99   static void populateMultimapForGet(Multimap<Integer, String> multimap, String[] elements) {
100     multimap.put(2, "foo");
101     for (String element : elements) {
102       multimap.put(3, element);
103     }
104   }
105 
populateMultimapForKeySet(Multimap<String, Integer> multimap, String[] elements)106   static void populateMultimapForKeySet(Multimap<String, Integer> multimap, String[] elements) {
107     for (String element : elements) {
108       multimap.put(element, 2);
109       multimap.put(element, 3);
110     }
111   }
112 
populateMultimapForValues(Multimap<Integer, String> multimap, String[] elements)113   static void populateMultimapForValues(Multimap<Integer, String> multimap, String[] elements) {
114     for (int i = 0; i < elements.length; i++) {
115       multimap.put(i % 2, elements[i]);
116     }
117   }
118 
populateMultimapForKeys(Multimap<String, Integer> multimap, String[] elements)119   static void populateMultimapForKeys(Multimap<String, Integer> multimap, String[] elements) {
120     for (int i = 0; i < elements.length; i++) {
121       multimap.put(elements[i], i);
122     }
123   }
124 
125   /**
126    * Implements {@code Multimap.put()} -- and no other methods -- for a {@code Map} by ignoring all
127    * but the latest value for each key. This class exists only so that we can use {@link
128    * MultimapsCollectionTest#populateMultimapForGet(Multimap, String[])} and similar methods to
129    * populate a map to be passed to {@link Multimaps#forMap(Map)}. All tests should run against the
130    * result of {@link #build()}.
131    */
132   private static final class PopulatableMapAsMultimap<K, V> extends ForwardingMultimap<K, V> {
133     final Map<K, V> map;
134     final SetMultimap<K, V> unusableDelegate;
135 
create()136     static <K, V> PopulatableMapAsMultimap<K, V> create() {
137       return new PopulatableMapAsMultimap<>();
138     }
139 
140     @SuppressWarnings("unchecked") // all methods throw immediately
PopulatableMapAsMultimap()141     PopulatableMapAsMultimap() {
142       this.map = newHashMap();
143       this.unusableDelegate =
144           (SetMultimap<K, V>)
145               newProxyInstance(
146                   SetMultimap.class.getClassLoader(),
147                   new Class<?>[] {SetMultimap.class},
148                   new InvocationHandler() {
149                     @Override
150                     public Object invoke(Object proxy, Method method, Object[] args)
151                         throws Throwable {
152                       throw new UnsupportedOperationException();
153                     }
154                   });
155     }
156 
157     @Override
delegate()158     protected Multimap<K, V> delegate() {
159       return unusableDelegate;
160     }
161 
162     @Override
put(K key, V value)163     public boolean put(K key, V value) {
164       map.put(key, value);
165       return true;
166     }
167 
build()168     SetMultimap<K, V> build() {
169       return Multimaps.forMap(map);
170     }
171   }
172 
173   abstract static class TestEntriesGenerator
174       implements TestCollectionGenerator<Entry<String, Integer>> {
175     @Override
samples()176     public SampleElements<Entry<String, Integer>> samples() {
177       return new SampleElements<>(
178           Maps.immutableEntry("bar", 1),
179           Maps.immutableEntry("bar", 2),
180           Maps.immutableEntry("foo", 3),
181           Maps.immutableEntry("bar", 3),
182           Maps.immutableEntry("cat", 2));
183     }
184 
185     @Override
create(Object... elements)186     public Collection<Entry<String, Integer>> create(Object... elements) {
187       Multimap<String, Integer> multimap = createMultimap();
188       for (Object element : elements) {
189         @SuppressWarnings("unchecked")
190         Entry<String, Integer> entry = (Entry<String, Integer>) element;
191         multimap.put(entry.getKey(), entry.getValue());
192       }
193       return multimap.entries();
194     }
195 
createMultimap()196     abstract Multimap<String, Integer> createMultimap();
197 
198     @Override
199     @SuppressWarnings("unchecked")
createArray(int length)200     public Entry<String, Integer>[] createArray(int length) {
201       return (Entry<String, Integer>[]) new Entry<?, ?>[length];
202     }
203 
204     @Override
order(List<Entry<String, Integer>> insertionOrder)205     public List<Entry<String, Integer>> order(List<Entry<String, Integer>> insertionOrder) {
206       return insertionOrder;
207     }
208   }
209 
210   public abstract static class TestEntriesListGenerator extends TestEntriesGenerator
211       implements TestListGenerator<Entry<String, Integer>> {
212     @Override
create(Object... elements)213     public List<Entry<String, Integer>> create(Object... elements) {
214       return (List<Entry<String, Integer>>) super.create(elements);
215     }
216   }
217 
218   private static final Predicate<Entry<Integer, String>> FILTER_GET_PREDICATE =
219       new Predicate<Entry<Integer, String>>() {
220         @Override
221         public boolean apply(Entry<Integer, String> entry) {
222           return !"badvalue".equals(entry.getValue()) && 55556 != entry.getKey();
223         }
224       };
225 
226   private static final Predicate<Entry<String, Integer>> FILTER_KEYSET_PREDICATE =
227       new Predicate<Entry<String, Integer>>() {
228         @Override
229         public boolean apply(Entry<String, Integer> entry) {
230           return !"badkey".equals(entry.getKey()) && 55556 != entry.getValue();
231         }
232       };
233 
suite()234   public static Test suite() {
235     TestSuite suite = new TestSuite();
236 
237     suite.addTest(transformSuite());
238     suite.addTest(filterSuite());
239 
240     suite.addTest(
241         ListMultimapTestSuiteBuilder.using(
242                 new TestStringListMultimapGenerator() {
243                   @Override
244                   protected ListMultimap<String, String> create(Entry<String, String>[] entries) {
245                     ListMultimap<String, String> multimap =
246                         Multimaps.synchronizedListMultimap(
247                             ArrayListMultimap.<String, String>create());
248                     for (Entry<String, String> entry : entries) {
249                       multimap.put(entry.getKey(), entry.getValue());
250                     }
251                     return multimap;
252                   }
253                 })
254             .named("synchronized ArrayListMultimap")
255             .withFeatures(
256                 MapFeature.ALLOWS_NULL_KEYS,
257                 MapFeature.ALLOWS_NULL_VALUES,
258                 MapFeature.ALLOWS_ANY_NULL_QUERIES,
259                 MapFeature.GENERAL_PURPOSE,
260                 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
261                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
262                 CollectionSize.ANY)
263             .createTestSuite());
264 
265     suite.addTest(
266         SetTestSuiteBuilder.using(
267                 new TestStringSetGenerator() {
268                   @Override
269                   protected Set<String> create(String[] elements) {
270                     PopulatableMapAsMultimap<Integer, String> multimap =
271                         PopulatableMapAsMultimap.create();
272                     populateMultimapForGet(multimap, elements);
273                     return multimap.build().get(3);
274                   }
275                 })
276             .named("Multimaps.forMap.get")
277             .withFeatures(FOR_MAP_FEATURES_ONE)
278             .createTestSuite());
279 
280     suite.addTest(
281         SetTestSuiteBuilder.using(
282                 new TestStringSetGenerator() {
283                   @Override
284                   protected Set<String> create(String[] elements) {
285                     PopulatableMapAsMultimap<String, Integer> multimap =
286                         PopulatableMapAsMultimap.create();
287                     populateMultimapForKeySet(multimap, elements);
288                     return multimap.build().keySet();
289                   }
290                 })
291             .named("Multimaps.forMap.keySet")
292             .withFeatures(FOR_MAP_FEATURES_ANY)
293             .createTestSuite());
294 
295     // TODO: use collection testers on Multimaps.forMap.values
296 
297     suite.addTest(
298         MultisetTestSuiteBuilder.using(
299                 new TestStringMultisetGenerator() {
300                   @Override
301                   protected Multiset<String> create(String[] elements) {
302                     PopulatableMapAsMultimap<String, Integer> multimap =
303                         PopulatableMapAsMultimap.create();
304                     populateMultimapForKeys(multimap, elements);
305                     return multimap.build().keys();
306                   }
307                 })
308             .named("Multimaps.forMap.keys")
309             .withFeatures(FOR_MAP_FEATURES_ANY)
310             .suppressing(getCountDuplicateInitializingMethods())
311             .suppressing(getSetCountDuplicateInitializingMethods())
312             .suppressing(getIteratorDuplicateInitializingMethods())
313             .suppressing(getRemoveDuplicateInitializingMethods())
314             .suppressing(getElementSetDuplicateInitializingMethods())
315             .createTestSuite());
316 
317     // TODO: use collection testers on Multimaps.forMap.entries
318 
319     return suite;
320   }
321 
322   abstract static class TransformedMultimapGenerator<M extends Multimap<String, String>>
323       implements TestMultimapGenerator<String, String, M> {
324 
325     @Override
createKeyArray(int length)326     public String[] createKeyArray(int length) {
327       return new String[length];
328     }
329 
330     @Override
createValueArray(int length)331     public String[] createValueArray(int length) {
332       return new String[length];
333     }
334 
335     @Override
sampleKeys()336     public SampleElements<String> sampleKeys() {
337       return new SampleElements<>("one", "two", "three", "four", "five");
338     }
339 
340     @Override
sampleValues()341     public SampleElements<String> sampleValues() {
342       return new SampleElements<>("january", "february", "march", "april", "may");
343     }
344 
345     @Override
createCollection(Iterable<? extends String> values)346     public Collection<String> createCollection(Iterable<? extends String> values) {
347       return Lists.newArrayList(values);
348     }
349 
350     @Override
samples()351     public SampleElements<Entry<String, String>> samples() {
352       return new SampleElements<>(
353           mapEntry("one", "january"),
354           mapEntry("two", "february"),
355           mapEntry("three", "march"),
356           mapEntry("four", "april"),
357           mapEntry("five", "may"));
358     }
359 
360     @Override
create(Object... elements)361     public M create(Object... elements) {
362       Multimap<String, String> multimap = ArrayListMultimap.create();
363       for (Object o : elements) {
364         @SuppressWarnings("unchecked")
365         Entry<String, String> entry = (Entry<String, String>) o;
366         multimap.put(entry.getKey(), Ascii.toUpperCase(entry.getValue()));
367       }
368       return transform(multimap);
369     }
370 
transform(Multimap<String, String> multimap)371     abstract M transform(Multimap<String, String> multimap);
372 
373     @SuppressWarnings("unchecked")
374     @Override
createArray(int length)375     public Entry<String, String>[] createArray(int length) {
376       return new Entry[length];
377     }
378 
379     @Override
order(List<Entry<String, String>> insertionOrder)380     public Iterable<Entry<String, String>> order(List<Entry<String, String>> insertionOrder) {
381       return insertionOrder;
382     }
383 
384     static final Function<String, String> FUNCTION =
385         new Function<String, String>() {
386           @Override
387           public String apply(String value) {
388             return Ascii.toLowerCase(value);
389           }
390         };
391 
392     static final EntryTransformer<String, String, String> ENTRY_TRANSFORMER =
393         new EntryTransformer<String, String, String>() {
394           @Override
395           public String transformEntry(String key, String value) {
396             return Ascii.toLowerCase(value);
397           }
398         };
399   }
400 
401   abstract static class TransformedListMultimapGenerator
402       extends TransformedMultimapGenerator<ListMultimap<String, String>>
403       implements TestListMultimapGenerator<String, String> {}
404 
transformSuite()405   private static Test transformSuite() {
406     TestSuite suite = new TestSuite("Multimaps.transform*");
407     suite.addTest(
408         MultimapTestSuiteBuilder.using(
409                 new TransformedMultimapGenerator<Multimap<String, String>>() {
410                   @Override
411                   Multimap<String, String> transform(Multimap<String, String> multimap) {
412                     return Multimaps.transformValues(multimap, FUNCTION);
413                   }
414                 })
415             .named("Multimaps.transformValues[Multimap]")
416             .withFeatures(
417                 CollectionSize.ANY,
418                 MapFeature.SUPPORTS_REMOVE,
419                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
420                 MapFeature.ALLOWS_NULL_KEYS,
421                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
422             .createTestSuite());
423     suite.addTest(
424         MultimapTestSuiteBuilder.using(
425                 new TransformedMultimapGenerator<Multimap<String, String>>() {
426                   @Override
427                   Multimap<String, String> transform(Multimap<String, String> multimap) {
428                     return Multimaps.transformEntries(multimap, ENTRY_TRANSFORMER);
429                   }
430                 })
431             .named("Multimaps.transformEntries[Multimap]")
432             .withFeatures(
433                 CollectionSize.ANY,
434                 MapFeature.SUPPORTS_REMOVE,
435                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
436                 MapFeature.ALLOWS_NULL_KEYS,
437                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
438             .createTestSuite());
439     suite.addTest(
440         ListMultimapTestSuiteBuilder.using(
441                 new TransformedListMultimapGenerator() {
442                   @Override
443                   ListMultimap<String, String> transform(Multimap<String, String> multimap) {
444                     return Multimaps.transformValues(
445                         (ListMultimap<String, String>) multimap, FUNCTION);
446                   }
447                 })
448             .named("Multimaps.transformValues[ListMultimap]")
449             .withFeatures(
450                 CollectionSize.ANY,
451                 MapFeature.SUPPORTS_REMOVE,
452                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
453                 MapFeature.ALLOWS_NULL_KEYS,
454                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
455             .createTestSuite());
456     suite.addTest(
457         ListMultimapTestSuiteBuilder.using(
458                 new TransformedListMultimapGenerator() {
459                   @Override
460                   ListMultimap<String, String> transform(Multimap<String, String> multimap) {
461                     return Multimaps.transformEntries(
462                         (ListMultimap<String, String>) multimap, ENTRY_TRANSFORMER);
463                   }
464                 })
465             .named("Multimaps.transformEntries[ListMultimap]")
466             .withFeatures(
467                 CollectionSize.ANY,
468                 MapFeature.SUPPORTS_REMOVE,
469                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
470                 MapFeature.ALLOWS_NULL_KEYS,
471                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
472             .createTestSuite());
473 
474     // TODO: use collection testers on Multimaps.forMap.entries
475 
476     return suite;
477   }
478 
479   abstract static class TestFilteredMultimapGenerator<M extends Multimap<String, Integer>>
480       implements TestMultimapGenerator<String, Integer, M> {
481 
482     @Override
samples()483     public SampleElements<Entry<String, Integer>> samples() {
484       return new SampleElements<>(
485           mapEntry("one", 114),
486           mapEntry("two", 37),
487           mapEntry("three", 42),
488           mapEntry("four", 19),
489           mapEntry("five", 82));
490     }
491 
492     @SuppressWarnings("unchecked")
493     @Override
createArray(int length)494     public Entry<String, Integer>[] createArray(int length) {
495       return new Entry[length];
496     }
497 
498     @Override
order(List<Entry<String, Integer>> insertionOrder)499     public Iterable<Entry<String, Integer>> order(List<Entry<String, Integer>> insertionOrder) {
500       return insertionOrder;
501     }
502 
503     @Override
createKeyArray(int length)504     public String[] createKeyArray(int length) {
505       return new String[length];
506     }
507 
508     @Override
createValueArray(int length)509     public Integer[] createValueArray(int length) {
510       return new Integer[length];
511     }
512 
513     @Override
sampleKeys()514     public SampleElements<String> sampleKeys() {
515       return new SampleElements<>("one", "two", "three", "four", "five");
516     }
517 
518     @Override
sampleValues()519     public SampleElements<Integer> sampleValues() {
520       return new SampleElements<>(114, 37, 42, 19, 82);
521     }
522   }
523 
524   abstract static class FilteredSetMultimapGenerator
525       extends TestFilteredMultimapGenerator<SetMultimap<String, Integer>>
526       implements TestSetMultimapGenerator<String, Integer> {
527 
filter(SetMultimap<String, Integer> multimap)528     abstract SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap);
529 
530     @Override
create(Object... elements)531     public SetMultimap<String, Integer> create(Object... elements) {
532       SetMultimap<String, Integer> multimap = LinkedHashMultimap.create();
533       for (Object o : elements) {
534         @SuppressWarnings("unchecked")
535         Entry<String, Integer> entry = (Entry<String, Integer>) o;
536         multimap.put(entry.getKey(), entry.getValue());
537       }
538       return filter(multimap);
539     }
540 
541     @Override
createCollection(Iterable<? extends Integer> values)542     public Collection<Integer> createCollection(Iterable<? extends Integer> values) {
543       return Sets.newLinkedHashSet(values);
544     }
545   }
546 
547   abstract static class FilteredListMultimapGenerator
548       extends TestFilteredMultimapGenerator<ListMultimap<String, Integer>>
549       implements TestListMultimapGenerator<String, Integer> {
550 
551     @Override
create(Object... elements)552     public ListMultimap<String, Integer> create(Object... elements) {
553       ListMultimap<String, Integer> multimap = LinkedListMultimap.create();
554       for (Object o : elements) {
555         @SuppressWarnings("unchecked")
556         Entry<String, Integer> entry = (Entry<String, Integer>) o;
557         multimap.put(entry.getKey(), entry.getValue());
558       }
559       return filter(multimap);
560     }
561 
filter(ListMultimap<String, Integer> multimap)562     abstract ListMultimap<String, Integer> filter(ListMultimap<String, Integer> multimap);
563 
564     @Override
createCollection(Iterable<? extends Integer> values)565     public Collection<Integer> createCollection(Iterable<? extends Integer> values) {
566       return Lists.newArrayList(values);
567     }
568   }
569 
filterSuite()570   private static Test filterSuite() {
571     TestSuite suite = new TestSuite("Multimaps.filter*");
572     suite.addTest(
573         SetMultimapTestSuiteBuilder.using(
574                 new FilteredSetMultimapGenerator() {
575                   @Override
576                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
577                     multimap.put("foo", 17);
578                     multimap.put("bar", 32);
579                     multimap.put("foo", 16);
580                     return Multimaps.filterKeys(
581                         multimap, Predicates.not(Predicates.in(ImmutableSet.of("foo", "bar"))));
582                   }
583                 })
584             .named("Multimaps.filterKeys[SetMultimap, Predicate]")
585             .withFeatures(
586                 CollectionSize.ANY,
587                 MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE,
588                 MapFeature.GENERAL_PURPOSE,
589                 MapFeature.ALLOWS_NULL_KEYS,
590                 MapFeature.ALLOWS_NULL_VALUES,
591                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
592             .createTestSuite());
593 
594     suite.addTest(
595         ListMultimapTestSuiteBuilder.using(
596                 new FilteredListMultimapGenerator() {
597                   @Override
598                   ListMultimap<String, Integer> filter(ListMultimap<String, Integer> multimap) {
599                     multimap.put("foo", 17);
600                     multimap.put("bar", 32);
601                     multimap.put("foo", 16);
602                     return Multimaps.filterKeys(
603                         multimap, Predicates.not(Predicates.in(ImmutableSet.of("foo", "bar"))));
604                   }
605                 })
606             .named("Multimaps.filterKeys[ListMultimap, Predicate]")
607             .withFeatures(
608                 CollectionSize.ANY,
609                 MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE,
610                 MapFeature.GENERAL_PURPOSE,
611                 MapFeature.ALLOWS_NULL_KEYS,
612                 MapFeature.ALLOWS_NULL_VALUES,
613                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
614             .createTestSuite());
615     suite.addTest(
616         ListMultimapTestSuiteBuilder.using(
617                 new FilteredListMultimapGenerator() {
618                   @Override
619                   ListMultimap<String, Integer> filter(ListMultimap<String, Integer> multimap) {
620                     multimap.put("foo", 17);
621                     multimap.put("bar", 32);
622                     multimap.put("foo", 16);
623                     multimap =
624                         Multimaps.filterKeys(multimap, Predicates.not(Predicates.equalTo("foo")));
625                     return Multimaps.filterKeys(
626                         multimap, Predicates.not(Predicates.equalTo("bar")));
627                   }
628                 })
629             .named("Multimaps.filterKeys[Multimaps.filterKeys[ListMultimap], Predicate]")
630             .withFeatures(
631                 CollectionSize.ANY,
632                 MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE,
633                 MapFeature.GENERAL_PURPOSE,
634                 MapFeature.ALLOWS_NULL_KEYS,
635                 MapFeature.ALLOWS_NULL_VALUES,
636                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
637             .createTestSuite());
638     suite.addTest(
639         SetMultimapTestSuiteBuilder.using(
640                 new FilteredSetMultimapGenerator() {
641                   @Override
642                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
643                     multimap.put("one", 314);
644                     multimap.put("two", 159);
645                     multimap.put("one", 265);
646                     return Multimaps.filterValues(
647                         multimap, Predicates.not(Predicates.in(ImmutableSet.of(314, 159, 265))));
648                   }
649                 })
650             .named("Multimaps.filterValues[SetMultimap, Predicate]")
651             .withFeatures(
652                 CollectionSize.ANY,
653                 MapFeature.GENERAL_PURPOSE,
654                 MapFeature.ALLOWS_NULL_KEYS,
655                 MapFeature.ALLOWS_NULL_VALUES,
656                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
657             .createTestSuite());
658     suite.addTest(
659         SetMultimapTestSuiteBuilder.using(
660                 new FilteredSetMultimapGenerator() {
661                   @Override
662                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
663                     ImmutableSetMultimap<String, Integer> badEntries =
664                         ImmutableSetMultimap.of("foo", 314, "one", 159, "two", 265, "bar", 358);
665                     multimap.putAll(badEntries);
666                     return Multimaps.filterEntries(
667                         multimap, Predicates.not(Predicates.in(badEntries.entries())));
668                   }
669                 })
670             .named("Multimaps.filterEntries[SetMultimap, Predicate]")
671             .withFeatures(
672                 CollectionSize.ANY,
673                 MapFeature.GENERAL_PURPOSE,
674                 MapFeature.ALLOWS_NULL_KEYS,
675                 MapFeature.ALLOWS_NULL_VALUES,
676                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
677             .createTestSuite());
678     suite.addTest(
679         SetMultimapTestSuiteBuilder.using(
680                 new FilteredSetMultimapGenerator() {
681                   @Override
682                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
683                     ImmutableSetMultimap<String, Integer> badEntries =
684                         ImmutableSetMultimap.of("foo", 314, "one", 159, "two", 265, "bar", 358);
685                     multimap.putAll(badEntries);
686                     multimap =
687                         Multimaps.filterKeys(
688                             multimap, Predicates.not(Predicates.in(ImmutableSet.of("foo", "bar"))));
689                     return Multimaps.filterEntries(
690                         multimap, Predicates.not(Predicates.in(badEntries.entries())));
691                   }
692                 })
693             .named("Multimaps.filterEntries[Multimaps.filterKeys[SetMultimap]]")
694             .withFeatures(
695                 CollectionSize.ANY,
696                 MapFeature.GENERAL_PURPOSE,
697                 MapFeature.ALLOWS_NULL_KEYS,
698                 MapFeature.ALLOWS_NULL_VALUES,
699                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
700             .createTestSuite());
701     suite.addTest(
702         SetMultimapTestSuiteBuilder.using(
703                 new FilteredSetMultimapGenerator() {
704                   @Override
705                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
706                     ImmutableSetMultimap<String, Integer> badEntries =
707                         ImmutableSetMultimap.of("foo", 314, "one", 159, "two", 265, "bar", 358);
708                     multimap.putAll(badEntries);
709                     multimap =
710                         Multimaps.filterEntries(
711                             multimap,
712                             Predicates.not(
713                                 Predicates.in(ImmutableMap.of("one", 159, "two", 265).entrySet())));
714                     return Multimaps.filterKeys(
715                         multimap, Predicates.not(Predicates.in(ImmutableSet.of("foo", "bar"))));
716                   }
717                 })
718             .named("Multimaps.filterKeys[Multimaps.filterEntries[SetMultimap]]")
719             .withFeatures(
720                 CollectionSize.ANY,
721                 MapFeature.GENERAL_PURPOSE,
722                 MapFeature.ALLOWS_NULL_KEYS,
723                 MapFeature.ALLOWS_NULL_VALUES,
724                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
725             .createTestSuite());
726     suite.addTest(
727         SetMultimapTestSuiteBuilder.using(
728                 new FilteredSetMultimapGenerator() {
729                   @Override
730                   SetMultimap<String, Integer> filter(SetMultimap<String, Integer> multimap) {
731                     ImmutableSetMultimap<String, Integer> badEntries =
732                         ImmutableSetMultimap.of("foo", 314, "bar", 358);
733                     multimap.putAll(badEntries);
734                     multimap =
735                         Multimaps.filterKeys(multimap, Predicates.not(Predicates.equalTo("foo")));
736                     multimap =
737                         Multimaps.filterKeys(multimap, Predicates.not(Predicates.equalTo("bar")));
738                     return multimap;
739                   }
740                 })
741             .named("Multimaps.filterKeys[Multimaps.filterKeys[SetMultimap]]")
742             .withFeatures(
743                 CollectionSize.ANY,
744                 MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE,
745                 MapFeature.GENERAL_PURPOSE,
746                 MapFeature.ALLOWS_NULL_KEYS,
747                 MapFeature.ALLOWS_NULL_VALUES,
748                 MapFeature.ALLOWS_ANY_NULL_QUERIES)
749             .createTestSuite());
750     return suite;
751   }
752 }
753