• 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.features.CollectionFeature.ALLOWS_NULL_VALUES;
21 import static com.google.common.collect.testing.features.CollectionFeature.REMOVE_OPERATIONS;
22 import static com.google.common.collect.testing.google.AbstractMultisetSetCountTester.getSetCountDuplicateInitializingMethods;
23 import static com.google.common.collect.testing.google.MultisetIteratorTester.getIteratorDuplicateInitializingMethods;
24 import static com.google.common.collect.testing.google.MultisetReadsTester.getReadsDuplicateInitializingMethods;
25 import static java.lang.reflect.Proxy.newProxyInstance;
26 
27 import com.google.common.annotations.GwtIncompatible;
28 import com.google.common.base.Functions;
29 import com.google.common.base.Predicate;
30 import com.google.common.base.Supplier;
31 import com.google.common.collect.testing.CollectionTestSuiteBuilder;
32 import com.google.common.collect.testing.ListTestSuiteBuilder;
33 import com.google.common.collect.testing.SampleElements;
34 import com.google.common.collect.testing.SetTestSuiteBuilder;
35 import com.google.common.collect.testing.TestCollectionGenerator;
36 import com.google.common.collect.testing.TestListGenerator;
37 import com.google.common.collect.testing.TestStringCollectionGenerator;
38 import com.google.common.collect.testing.TestStringListGenerator;
39 import com.google.common.collect.testing.TestStringSetGenerator;
40 import com.google.common.collect.testing.TestStringSortedSetGenerator;
41 import com.google.common.collect.testing.features.CollectionFeature;
42 import com.google.common.collect.testing.features.CollectionSize;
43 import com.google.common.collect.testing.features.Feature;
44 import com.google.common.collect.testing.features.ListFeature;
45 import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
46 import com.google.common.collect.testing.google.MultisetWritesTester;
47 import com.google.common.collect.testing.google.TestStringMultisetGenerator;
48 import com.google.common.collect.testing.testers.CollectionIteratorTester;
49 
50 import junit.framework.Test;
51 import junit.framework.TestCase;
52 import junit.framework.TestSuite;
53 
54 import java.lang.reflect.InvocationHandler;
55 import java.lang.reflect.Method;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.Map;
60 import java.util.Map.Entry;
61 import java.util.Set;
62 import java.util.SortedSet;
63 import java.util.TreeSet;
64 
65 /**
66  * Run collection tests on {@link Multimap} implementations.
67  *
68  * @author Jared Levy
69  */
70 @GwtIncompatible("suite") // TODO(cpovirk): set up collect/gwt/suites version
71 public class MultimapCollectionTest extends TestCase {
72 
73   private static final Feature<?>[] COLLECTION_FEATURES = {
74     CollectionSize.ANY,
75     CollectionFeature.ALLOWS_NULL_VALUES,
76     CollectionFeature.GENERAL_PURPOSE
77   };
78 
79   static final Feature<?>[] COLLECTION_FEATURES_ORDER = {
80     CollectionSize.ANY,
81     CollectionFeature.ALLOWS_NULL_VALUES,
82     CollectionFeature.KNOWN_ORDER,
83     CollectionFeature.GENERAL_PURPOSE
84   };
85   static final Feature<?>[] COLLECTION_FEATURES_REMOVE = {
86     CollectionSize.ANY,
87     CollectionFeature.ALLOWS_NULL_VALUES,
88     CollectionFeature.REMOVE_OPERATIONS
89   };
90 
91   static final Feature<?>[] COLLECTION_FEATURES_REMOVE_ORDER = {
92     CollectionSize.ANY,
93     CollectionFeature.ALLOWS_NULL_VALUES,
94     CollectionFeature.KNOWN_ORDER,
95     CollectionFeature.REMOVE_OPERATIONS
96   };
97 
98   private static final Feature<?>[] LIST_FEATURES = {
99     CollectionSize.ANY,
100     CollectionFeature.ALLOWS_NULL_VALUES,
101     ListFeature.GENERAL_PURPOSE
102   };
103 
104   private static final Feature<?>[] LIST_FEATURES_REMOVE_SET = {
105     CollectionSize.ANY,
106     CollectionFeature.ALLOWS_NULL_VALUES,
107     ListFeature.REMOVE_OPERATIONS,
108     ListFeature.SUPPORTS_SET
109   };
110 
111   private static final Feature<?>[] FOR_MAP_FEATURES_ONE = {
112     CollectionSize.ONE,
113     ALLOWS_NULL_VALUES,
114     REMOVE_OPERATIONS,
115   };
116 
117   private static final Feature<?>[] FOR_MAP_FEATURES_ANY = {
118     CollectionSize.ANY,
119     ALLOWS_NULL_VALUES,
120     REMOVE_OPERATIONS,
121   };
122 
123   static final Supplier<TreeSet<String>> STRING_TREESET_FACTORY
124       = new Supplier<TreeSet<String>>() {
125         @Override
126         public TreeSet<String> get() {
127           return new TreeSet<String>(Ordering.natural().nullsLast());
128         }
129       };
130 
populateMultimapForGet( Multimap<Integer, String> multimap, String[] elements)131   static void populateMultimapForGet(
132       Multimap<Integer, String> multimap, String[] elements) {
133     multimap.put(2, "foo");
134     for (String element : elements) {
135       multimap.put(3, element);
136     }
137   }
138 
populateMultimapForKeySet( Multimap<String, Integer> multimap, String[] elements)139   static void populateMultimapForKeySet(
140       Multimap<String, Integer> multimap, String[] elements) {
141     for (String element : elements) {
142       multimap.put(element, 2);
143       multimap.put(element, 3);
144     }
145   }
146 
populateMultimapForValues( Multimap<Integer, String> multimap, String[] elements)147   static void populateMultimapForValues(
148       Multimap<Integer, String> multimap, String[] elements) {
149     for (int i = 0; i < elements.length; i++) {
150       multimap.put(i % 2, elements[i]);
151     }
152   }
153 
populateMultimapForKeys( Multimap<String, Integer> multimap, String[] elements)154   static void populateMultimapForKeys(
155       Multimap<String, Integer> multimap, String[] elements) {
156     for (int i = 0; i < elements.length; i++) {
157       multimap.put(elements[i], i);
158     }
159   }
160 
161   /**
162    * Implements {@code Multimap.put()} -- and no other methods -- for a {@code
163    * Map} by ignoring all but the latest value for each key. This class exists
164    * only so that we can use
165    * {@link MultimapCollectionTest#populateMultimapForGet(Multimap, String[])}
166    * and similar methods to populate a map to be passed to
167    * {@link Multimaps#forMap(Map)}. All tests should run against the result of
168    * {@link #build()}.
169    */
170   private static final class PopulatableMapAsMultimap<K, V>
171       extends ForwardingMultimap<K, V> {
172     final Map<K, V> map;
173     final SetMultimap<K, V> unusableDelegate;
174 
create()175     static <K, V> PopulatableMapAsMultimap<K, V> create() {
176       return new PopulatableMapAsMultimap<K, V>();
177     }
178 
179     @SuppressWarnings("unchecked") // all methods throw immediately
PopulatableMapAsMultimap()180     PopulatableMapAsMultimap() {
181       this.map = newHashMap();
182       this.unusableDelegate = (SetMultimap<K, V>) newProxyInstance(
183           SetMultimap.class.getClassLoader(),
184           new Class<?>[] {SetMultimap.class},
185           new InvocationHandler() {
186             @Override
187             public Object invoke(Object proxy, Method method, Object[] args)
188                 throws Throwable {
189               throw new UnsupportedOperationException();
190             }
191           });
192     }
193 
delegate()194     @Override protected Multimap<K, V> delegate() {
195       return unusableDelegate;
196     }
197 
put(K key, V value)198     @Override public boolean put(K key, V value) {
199       map.put(key, value);
200       return true;
201     }
202 
build()203     SetMultimap<K, V> build() {
204       return Multimaps.forMap(map);
205     }
206   }
207 
208   static abstract class TestEntriesGenerator
209       implements TestCollectionGenerator<Entry<String, Integer>> {
210     @Override
samples()211     public SampleElements<Entry<String, Integer>> samples() {
212       return new SampleElements<Entry<String, Integer>>(
213           Maps.immutableEntry("bar", 1),
214           Maps.immutableEntry("bar", 2),
215           Maps.immutableEntry("foo", 3),
216           Maps.immutableEntry("bar", 3),
217           Maps.immutableEntry("cat", 2));
218     }
219 
220     @Override
create(Object... elements)221     public Collection<Entry<String, Integer>> create(Object... elements) {
222       Multimap<String, Integer> multimap = createMultimap();
223       for (Object element : elements) {
224         @SuppressWarnings("unchecked")
225         Entry<String, Integer> entry = (Entry<String, Integer>) element;
226         multimap.put(entry.getKey(), entry.getValue());
227       }
228       return multimap.entries();
229     }
230 
createMultimap()231     abstract Multimap<String, Integer> createMultimap();
232 
233     @Override
234     @SuppressWarnings("unchecked")
createArray(int length)235     public Entry<String, Integer>[] createArray(int length) {
236       return (Entry<String, Integer>[]) new Entry<?, ?>[length];
237     }
238 
239     @Override
order( List<Entry<String, Integer>> insertionOrder)240     public List<Entry<String, Integer>> order(
241         List<Entry<String, Integer>> insertionOrder) {
242       return insertionOrder;
243     }
244   }
245 
246   public static abstract class TestEntriesListGenerator
247       extends TestEntriesGenerator
248       implements TestListGenerator<Entry<String, Integer>> {
create(Object... elements)249     @Override public List<Entry<String, Integer>> create(Object... elements) {
250       return (List<Entry<String, Integer>>) super.create(elements);
251     }
252   }
253 
254   private static abstract class TestEntrySetGenerator
255       extends TestEntriesGenerator {
createMultimap()256     @Override abstract SetMultimap<String, Integer> createMultimap();
257 
create(Object... elements)258     @Override public Set<Entry<String, Integer>> create(Object... elements) {
259       return (Set<Entry<String, Integer>>) super.create(elements);
260     }
261   }
262 
263   private static final Predicate<Map.Entry<Integer, String>> FILTER_GET_PREDICATE
264       = new Predicate<Map.Entry<Integer, String>>() {
265         @Override public boolean apply(Entry<Integer, String> entry) {
266           return !"badvalue".equals(entry.getValue()) && 55556 != entry.getKey();
267         }
268     };
269 
270   private static final Predicate<Map.Entry<String, Integer>> FILTER_KEYSET_PREDICATE
271     = new Predicate<Map.Entry<String, Integer>>() {
272       @Override public boolean apply(Entry<String, Integer> entry) {
273         return !"badkey".equals(entry.getKey()) && 55556 != entry.getValue();
274       }
275   };
276 
suite()277   public static Test suite() {
278     TestSuite suite = new TestSuite();
279 
280     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
281           @Override protected Set<String> create(String[] elements) {
282             SetMultimap<Integer, String> multimap = HashMultimap.create();
283             populateMultimapForGet(multimap, elements);
284             return multimap.get(3);
285           }
286         })
287         .named("HashMultimap.get")
288         .withFeatures(COLLECTION_FEATURES)
289         .createTestSuite());
290 
291     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
292           @Override protected Set<String> create(String[] elements) {
293             SetMultimap<Integer, String> multimap
294                 = LinkedHashMultimap.create();
295             populateMultimapForGet(multimap, elements);
296             return multimap.get(3);
297           }
298         })
299         .named("LinkedHashMultimap.get")
300         .withFeatures(COLLECTION_FEATURES_ORDER)
301         .createTestSuite());
302 
303     suite.addTest(SetTestSuiteBuilder.using(
304         new TestStringSortedSetGenerator() {
305           @Override protected SortedSet<String> create(String[] elements) {
306             SortedSetMultimap<Integer, String> multimap =
307                 TreeMultimap.create(Ordering.natural().nullsFirst(),
308                     Ordering.natural().nullsLast());
309             populateMultimapForGet(multimap, elements);
310             return multimap.get(3);
311           }
312         })
313         .named("TreeMultimap.get")
314         .withFeatures(COLLECTION_FEATURES_ORDER)
315         .createTestSuite());
316 
317     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
318           @Override protected List<String> create(String[] elements) {
319             ListMultimap<Integer, String> multimap
320                 = ArrayListMultimap.create();
321             populateMultimapForGet(multimap, elements);
322             return multimap.get(3);
323           }
324         })
325         .named("ArrayListMultimap.get")
326         .withFeatures(LIST_FEATURES)
327         .createTestSuite());
328 
329     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
330           @Override protected List<String> create(String[] elements) {
331             ListMultimap<Integer, String> multimap
332                 = Multimaps.synchronizedListMultimap(
333                 ArrayListMultimap.<Integer, String>create());
334             populateMultimapForGet(multimap, elements);
335             return multimap.get(3);
336           }
337         })
338         .named("synchronized ArrayListMultimap.get")
339         .withFeatures(LIST_FEATURES)
340         .createTestSuite());
341 
342     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
343           @Override protected List<String> create(String[] elements) {
344             ListMultimap<Integer, String> multimap
345                 = LinkedListMultimap.create();
346             populateMultimapForGet(multimap, elements);
347             return multimap.get(3);
348           }
349         })
350         .named("LinkedListMultimap.get")
351         .withFeatures(LIST_FEATURES)
352         .createTestSuite());
353 
354     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
355           @Override protected List<String> create(String[] elements) {
356             ImmutableListMultimap.Builder<Integer, String> builder
357                 = ImmutableListMultimap.builder();
358             ListMultimap<Integer, String> multimap
359                 = builder.put(2, "foo")
360                 .putAll(3, elements)
361                 .build();
362             return multimap.get(3);
363           }
364         })
365         .named("ImmutableListMultimap.get")
366         .withFeatures(CollectionSize.ANY)
367         .createTestSuite());
368 
369     suite.addTest(SetTestSuiteBuilder.using(
370         new TestStringSetGenerator() {
371           @Override protected Set<String> create(String[] elements) {
372             PopulatableMapAsMultimap<Integer, String> multimap
373                 = PopulatableMapAsMultimap.create();
374             populateMultimapForGet(multimap, elements);
375             return multimap.build().get(3);
376           }
377         })
378         .named("Multimaps.forMap.get")
379         .withFeatures(FOR_MAP_FEATURES_ONE)
380         .createTestSuite());
381 
382     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
383           @Override protected Set<String> create(String[] elements) {
384             SetMultimap<Integer, String> multimap
385                 = LinkedHashMultimap.create();
386             populateMultimapForGet(multimap, elements);
387             multimap.put(3, "badvalue");
388             multimap.put(55556, "foo");
389             return (Set<String>) Multimaps.filterEntries(multimap, FILTER_GET_PREDICATE).get(3);
390           }
391         })
392         .named("Multimaps.filterEntries.get")
393         .withFeatures(COLLECTION_FEATURES_ORDER)
394         .suppressing(CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod())
395         .createTestSuite());
396 
397     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
398           @Override protected Set<String> create(String[] elements) {
399             Multimap<String, Integer> multimap = HashMultimap.create();
400             populateMultimapForKeySet(multimap, elements);
401             return multimap.keySet();
402           }
403         })
404         .named("HashMultimap.keySet")
405         .withFeatures(COLLECTION_FEATURES_REMOVE)
406         .createTestSuite());
407 
408     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
409           @Override protected Set<String> create(String[] elements) {
410             Multimap<String, Integer> multimap
411                 = LinkedHashMultimap.create();
412             populateMultimapForKeySet(multimap, elements);
413             return multimap.keySet();
414           }
415         })
416         .named("LinkedHashMultimap.keySet")
417         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
418         .createTestSuite());
419 
420     suite.addTest(SetTestSuiteBuilder.using(
421         new TestStringSortedSetGenerator() {
422           @Override protected SortedSet<String> create(String[] elements) {
423             TreeMultimap<String, Integer> multimap =
424                 TreeMultimap.create(Ordering.natural().nullsFirst(),
425                     Ordering.natural().nullsLast());
426             populateMultimapForKeySet(multimap, elements);
427             return multimap.keySet();
428           }
429         })
430         .named("TreeMultimap.keySet")
431         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
432         .createTestSuite());
433 
434     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
435           @Override protected Set<String> create(String[] elements) {
436             Multimap<String, Integer> multimap
437                 = ArrayListMultimap.create();
438             populateMultimapForKeySet(multimap, elements);
439             return multimap.keySet();
440           }
441         })
442         .named("ArrayListMultimap.keySet")
443         .withFeatures(COLLECTION_FEATURES_REMOVE)
444         .createTestSuite());
445 
446     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
447           @Override protected Set<String> create(String[] elements) {
448             Multimap<String, Integer> multimap
449                 = LinkedListMultimap.create();
450             populateMultimapForKeySet(multimap, elements);
451             return multimap.keySet();
452           }
453         })
454         .named("LinkedListMultimap.keySet")
455         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
456         .createTestSuite());
457 
458     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
459           @Override protected Set<String> create(String[] elements) {
460             ImmutableListMultimap.Builder<String, Integer> builder
461                 = ImmutableListMultimap.builder();
462             for (String element : elements) {
463               builder.put(element, 2);
464               builder.put(element, 3);
465             }
466             Multimap<String, Integer> multimap = builder.build();
467             return multimap.keySet();
468           }
469         })
470         .named("ImmutableListMultimap.keySet")
471         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER)
472         .createTestSuite());
473 
474     suite.addTest(SetTestSuiteBuilder.using(
475         new TestStringSetGenerator() {
476           @Override protected Set<String> create(String[] elements) {
477             PopulatableMapAsMultimap<String, Integer> multimap
478                 = PopulatableMapAsMultimap.create();
479             populateMultimapForKeySet(multimap, elements);
480             return multimap.build().keySet();
481           }
482         })
483         .named("Multimaps.forMap.keySet")
484         .withFeatures(FOR_MAP_FEATURES_ANY)
485         .createTestSuite());
486 
487     suite.addTest(SetTestSuiteBuilder.using(
488         new TestStringSetGenerator() {
489         @Override protected Set<String> create(String[] elements) {
490           SetMultimap<String, Integer> multimap = LinkedHashMultimap.create();
491           populateMultimapForKeySet(multimap, elements);
492           multimap.put("badkey", 3);
493           multimap.put("a", 55556);
494           return Multimaps.filterEntries(multimap, FILTER_KEYSET_PREDICATE).keySet();
495           }
496         })
497         .named("Multimaps.filterEntries.keySet")
498         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
499         .suppressing(CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod())
500         .createTestSuite());
501 
502     suite.addTest(CollectionTestSuiteBuilder.using(
503         new TestStringCollectionGenerator() {
504           @Override public Collection<String> create(String[] elements) {
505             Multimap<Integer, String> multimap = HashMultimap.create();
506             populateMultimapForValues(multimap, elements);
507             return multimap.values();
508           }
509         })
510         .named("HashMultimap.values")
511         .withFeatures(COLLECTION_FEATURES_REMOVE)
512         .createTestSuite());
513 
514     suite.addTest(CollectionTestSuiteBuilder.using(
515         new TestStringCollectionGenerator() {
516           @Override public Collection<String> create(String[] elements) {
517             Multimap<Integer, String> multimap
518                 = LinkedHashMultimap.create();
519             populateMultimapForValues(multimap, elements);
520             return multimap.values();
521           }
522         })
523         .named("LinkedHashMultimap.values")
524         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
525         .createTestSuite());
526 
527     suite.addTest(CollectionTestSuiteBuilder.using(
528         new TestStringCollectionGenerator() {
529           @Override public Collection<String> create(String[] elements) {
530             Multimap<Integer, String> multimap
531                 = TreeMultimap.create(Ordering.natural().nullsFirst(),
532                     Ordering.natural().nullsLast());
533             populateMultimapForValues(multimap, elements);
534             return multimap.values();
535           }
536         })
537         .named("TreeMultimap.values")
538         .withFeatures(COLLECTION_FEATURES_REMOVE)
539         .createTestSuite());
540 
541     suite.addTest(CollectionTestSuiteBuilder.using(
542         new TestStringCollectionGenerator() {
543           @Override public Collection<String> create(String[] elements) {
544             Multimap<Integer, String> multimap
545                 = ArrayListMultimap.create();
546             populateMultimapForValues(multimap, elements);
547             return multimap.values();
548           }
549         })
550         .named("ArrayListMultimap.values")
551         .withFeatures(COLLECTION_FEATURES_REMOVE)
552         .createTestSuite());
553 
554     suite.addTest(ListTestSuiteBuilder.using(
555         new TestStringListGenerator() {
556           @Override public List<String> create(String[] elements) {
557             LinkedListMultimap<Integer, String> multimap
558                 = LinkedListMultimap.create();
559             populateMultimapForValues(multimap, elements);
560             return multimap.values();
561           }
562         })
563         .named("LinkedListMultimap.values")
564         .withFeatures(LIST_FEATURES_REMOVE_SET)
565         .createTestSuite());
566 
567     suite.addTest(CollectionTestSuiteBuilder.using(
568         new TestStringCollectionGenerator() {
569           @Override public Collection<String> create(String[] elements) {
570             ImmutableListMultimap.Builder<Integer, String> builder
571                 = ImmutableListMultimap.builder();
572             for (int i = 0; i < elements.length; i++) {
573               builder.put(i % 2, elements[i]);
574             }
575             return builder.build().values();
576           }
577         })
578         .named("ImmutableListMultimap.values")
579         .withFeatures(CollectionSize.ANY)
580         .createTestSuite());
581 
582     suite.addTest(CollectionTestSuiteBuilder.using(
583         new TestStringCollectionGenerator() {
584           @Override public Collection<String> create(String[] elements) {
585             Multimap<Integer, String> multimap
586                 = LinkedHashMultimap.create();
587             populateMultimapForValues(multimap, elements);
588             multimap.put(3, "badvalue");
589             multimap.put(55556, "foo");
590             return Multimaps.filterEntries(multimap, FILTER_GET_PREDICATE).values();
591           }
592         })
593         .named("Multimaps.filterEntries.values")
594         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
595         .suppressing(CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod())
596         .createTestSuite());
597 
598     // TODO: use collection testers on Multimaps.forMap.values
599 
600     suite.addTest(MultisetTestSuiteBuilder.using(
601         new TestStringMultisetGenerator() {
602           @Override protected Multiset<String> create(String[] elements) {
603             Multimap<String, Integer> multimap = HashMultimap.create();
604             populateMultimapForKeys(multimap, elements);
605             return multimap.keys();
606           }
607         })
608         .named("HashMultimap.keys")
609         .withFeatures(COLLECTION_FEATURES_REMOVE)
610         .createTestSuite());
611 
612     suite.addTest(MultisetTestSuiteBuilder.using(
613         new TestStringMultisetGenerator() {
614           @Override protected Multiset<String> create(String[] elements) {
615             Multimap<String, Integer> multimap
616                 = LinkedHashMultimap.create();
617             populateMultimapForKeys(multimap, elements);
618             return multimap.keys();
619           }
620         })
621         .named("LinkedHashMultimap.keys")
622         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
623         .createTestSuite());
624 
625     suite.addTest(MultisetTestSuiteBuilder.using(
626         new TestStringMultisetGenerator() {
627           @Override protected Multiset<String> create(String[] elements) {
628             Multimap<String, Integer> multimap
629                 = TreeMultimap.create(Ordering.natural().nullsFirst(),
630                     Ordering.natural().nullsLast());
631             populateMultimapForKeys(multimap, elements);
632             return multimap.keys();
633           }
634 
635           @Override public List<String> order(List<String> insertionOrder) {
636             Collections.sort(insertionOrder, Ordering.natural().nullsFirst());
637             return insertionOrder;
638           }
639         })
640         .named("TreeMultimap.keys")
641         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
642         .createTestSuite());
643 
644     suite.addTest(MultisetTestSuiteBuilder.using(
645         new TestStringMultisetGenerator() {
646           @Override protected Multiset<String> create(String[] elements) {
647             Multimap<String, Integer> multimap
648                 = ArrayListMultimap.create();
649             populateMultimapForKeys(multimap, elements);
650             return multimap.keys();
651           }
652         })
653         .named("ArrayListMultimap.keys")
654         .withFeatures(COLLECTION_FEATURES_REMOVE)
655         .createTestSuite());
656 
657     suite.addTest(MultisetTestSuiteBuilder.using(
658         new TestStringMultisetGenerator() {
659           @Override protected Multiset<String> create(String[] elements) {
660             Multimap<String, Integer> multimap
661                 = Multimaps.synchronizedListMultimap(
662                     ArrayListMultimap.<String, Integer>create());
663             populateMultimapForKeys(multimap, elements);
664             return multimap.keys();
665           }
666         })
667         .named("synchronized ArrayListMultimap.keys")
668         .withFeatures(COLLECTION_FEATURES_REMOVE)
669         .createTestSuite());
670 
671     suite.addTest(MultisetTestSuiteBuilder.using(
672         new TestStringMultisetGenerator() {
673           @Override protected Multiset<String> create(String[] elements) {
674             Multimap<String, Integer> multimap
675                 = LinkedListMultimap.create();
676             populateMultimapForKeys(multimap, elements);
677             return multimap.keys();
678           }
679         })
680         .named("LinkedListMultimap.keys")
681         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
682         .createTestSuite());
683 
684     suite.addTest(MultisetTestSuiteBuilder.using(
685         new TestStringMultisetGenerator() {
686           @Override protected Multiset<String> create(String[] elements) {
687             ImmutableListMultimap.Builder<String, Integer> builder
688                 = ImmutableListMultimap.builder();
689             for (int i = 0; i < elements.length; i++) {
690               builder.put(elements[i], i);
691             }
692             Multimap<String, Integer> multimap = builder.build();
693             return multimap.keys();
694           }
695         })
696         .named("ImmutableListMultimap.keys")
697         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER)
698         .createTestSuite());
699 
700     suite.addTest(MultisetTestSuiteBuilder.using(
701         new TestStringMultisetGenerator() {
702           @Override protected Multiset<String> create(String[] elements) {
703             PopulatableMapAsMultimap<String, Integer> multimap
704                 = PopulatableMapAsMultimap.create();
705             populateMultimapForKeys(multimap, elements);
706             return multimap.build().keys();
707           }
708         })
709         .named("Multimaps.forMap.keys")
710         .withFeatures(FOR_MAP_FEATURES_ANY)
711         .suppressing(getReadsDuplicateInitializingMethods())
712         .suppressing(getSetCountDuplicateInitializingMethods())
713         .suppressing(getIteratorDuplicateInitializingMethods())
714         .createTestSuite());
715 
716     suite.addTest(MultisetTestSuiteBuilder.using(
717         new TestStringMultisetGenerator() {
718         @Override protected Multiset<String> create(String[] elements) {
719           SetMultimap<String, Integer> multimap = LinkedHashMultimap.create();
720           populateMultimapForKeys(multimap, elements);
721           multimap.put("badkey", 3);
722           multimap.put("a", 55556);
723           return Multimaps.filterEntries(multimap, FILTER_KEYSET_PREDICATE).keys();
724           }
725         })
726         .named("Multimaps.filterEntries.keys")
727         .withFeatures(COLLECTION_FEATURES_REMOVE_ORDER)
728         .suppressing(CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod())
729         .suppressing(MultisetWritesTester.getEntrySetIteratorMethod())
730         .suppressing(getIteratorDuplicateInitializingMethods())
731         .createTestSuite());
732 
733     suite.addTest(CollectionTestSuiteBuilder.using(
734         new TestEntrySetGenerator() {
735           @Override SetMultimap<String, Integer> createMultimap() {
736             return HashMultimap.create();
737           }
738         })
739         .named("HashMultimap.entries")
740         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS)
741         .createTestSuite());
742 
743     suite.addTest(CollectionTestSuiteBuilder.using(
744         new TestEntrySetGenerator() {
745           @Override SetMultimap<String, Integer> createMultimap() {
746             return LinkedHashMultimap.create();
747           }
748         })
749         .named("LinkedHashMultimap.entries")
750         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
751             CollectionFeature.KNOWN_ORDER)
752         .createTestSuite());
753 
754     suite.addTest(CollectionTestSuiteBuilder.using(
755         new TestEntrySetGenerator() {
756           @Override SetMultimap<String, Integer> createMultimap() {
757             return TreeMultimap.create(Ordering.natural().nullsFirst(),
758                 Ordering.natural().nullsLast());
759           }
760         })
761         .named("TreeMultimap.entries")
762         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
763             CollectionFeature.KNOWN_ORDER)
764         .createTestSuite());
765 
766     suite.addTest(CollectionTestSuiteBuilder.using(
767         new TestEntriesGenerator() {
768           @Override Multimap<String, Integer> createMultimap() {
769             return ArrayListMultimap.create();
770           }
771         })
772         .named("ArrayListMultimap.entries")
773         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS)
774         .createTestSuite());
775 
776     suite.addTest(CollectionTestSuiteBuilder.using(
777         new TestEntriesGenerator() {
778           @Override Multimap<String, Integer> createMultimap() {
779             return Multimaps.synchronizedListMultimap(
780                 ArrayListMultimap.<String, Integer>create());
781           }
782         })
783         .named("synchronized ArrayListMultimap.entries")
784         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS)
785         .createTestSuite());
786 
787     suite.addTest(ListTestSuiteBuilder.using(
788         new TestEntriesListGenerator() {
789           @Override Multimap<String, Integer> createMultimap() {
790             return LinkedListMultimap.create();
791           }
792         })
793         .named("LinkedListMultimap.entries")
794         .withFeatures(CollectionSize.ANY, ListFeature.REMOVE_OPERATIONS,
795             CollectionFeature.KNOWN_ORDER)
796         .createTestSuite());
797 
798     suite.addTest(CollectionTestSuiteBuilder.using(
799         new TestEntriesGenerator() {
800           @Override Multimap<String, Integer> createMultimap() {
801             return ImmutableListMultimap.of();
802           }
803 
804           @Override public Collection<Entry<String, Integer>> create(
805               Object... elements) {
806             ImmutableListMultimap.Builder<String, Integer> builder
807                 = ImmutableListMultimap.builder();
808             for (Object element : elements) {
809               @SuppressWarnings("unchecked")
810               Entry<String, Integer> entry = (Entry<String, Integer>) element;
811               builder.put(entry.getKey(), entry.getValue());
812             }
813             return builder.build().entries();
814           }
815         })
816         .named("ImmutableListMultimap.entries")
817         .withFeatures(CollectionSize.ANY, CollectionFeature.KNOWN_ORDER)
818         .createTestSuite());
819 
820     suite.addTest(CollectionTestSuiteBuilder.using(
821         new TestEntriesGenerator() {
822           @Override Multimap<String, Integer> createMultimap() {
823             Multimap<String, Integer> multimap = LinkedHashMultimap.create();
824             multimap.put("badkey", 3);
825             multimap.put("a", 55556);
826             return Multimaps.filterEntries(multimap, FILTER_KEYSET_PREDICATE);
827           }
828         })
829         .named("Multimap.filterEntries.entries")
830         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS,
831             CollectionFeature.KNOWN_ORDER)
832         .suppressing(CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod())
833         .createTestSuite());
834 
835     suite.addTest(ListTestSuiteBuilder.using(new TestStringListGenerator() {
836       @Override protected List<String> create(String[] elements) {
837         ListMultimap<Integer, String> multimap = ArrayListMultimap.create();
838         populateMultimapForGet(multimap, elements);
839         return Multimaps.transformValues(
840             multimap, Functions.<String> identity()).get(3);
841       }
842     }).named("Multimaps.transformValues[ListMultimap].get").withFeatures(
843         CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES,
844         CollectionFeature.REMOVE_OPERATIONS,
845         ListFeature.SUPPORTS_REMOVE_WITH_INDEX).createTestSuite());
846 
847     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
848       @Override protected Set<String> create(String[] elements) {
849         ListMultimap<String, Integer> multimap = ArrayListMultimap.create();
850         populateMultimapForKeySet(multimap, elements);
851         return Multimaps.transformValues(
852             multimap, Functions.<Integer> identity()).keySet();
853       }
854     }).named("Multimaps.transformValues[ListMultimap].keySet").withFeatures(
855         CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES,
856         CollectionFeature.REMOVE_OPERATIONS).createTestSuite());
857 
858     suite.addTest(MultisetTestSuiteBuilder.using(
859         new TestStringMultisetGenerator() {
860           @Override protected Multiset<String> create(String[] elements) {
861             ListMultimap<String, Integer> multimap
862                 = ArrayListMultimap.create();
863             populateMultimapForKeys(multimap, elements);
864             return Multimaps.transformValues(
865                 multimap, Functions.<Integer> identity()).keys();
866           }
867         })
868         .named("Multimaps.transform[ListMultimap].keys")
869         .withFeatures(COLLECTION_FEATURES_REMOVE)
870         .createTestSuite());
871 
872     suite.addTest(
873         CollectionTestSuiteBuilder.using(new TestStringCollectionGenerator() {
874           @Override public Collection<String> create(String[] elements) {
875             ListMultimap<Integer, String> multimap = ArrayListMultimap.create();
876             populateMultimapForValues(multimap, elements);
877             return Multimaps.transformValues(
878                 multimap, Functions.<String> identity()).values();
879           }
880         }).named("Multimaps.transformValues[ListMultimap].values").withFeatures(
881             COLLECTION_FEATURES_REMOVE).createTestSuite());
882 
883     suite.addTest(CollectionTestSuiteBuilder.using(new TestEntriesGenerator() {
884       @Override public Collection<Entry<String, Integer>> create(
885           Object... elements) {
886         ListMultimap<String, Integer> multimap = ArrayListMultimap.create();
887         for (Object element : elements) {
888           @SuppressWarnings("unchecked")
889           Entry<String, Integer> entry = (Entry<String, Integer>) element;
890           multimap.put(entry.getKey(), entry.getValue());
891         }
892         return Multimaps.transformValues(
893             multimap, Functions.<Integer> identity()).entries();
894       }
895 
896       @Override Multimap<String, Integer> createMultimap() {
897         return Multimaps.transformValues(
898             ArrayListMultimap.<String, Integer> create(),
899             Functions.<Integer> identity());
900       }
901     }).named("Multimaps.transformValues[ListMultimap].entries")
902         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS)
903         .createTestSuite());
904 
905     suite.addTest(
906         CollectionTestSuiteBuilder.using(new TestStringCollectionGenerator() {
907           @Override protected Collection<String> create(String[] elements) {
908             Multimap<Integer, String> multimap = ArrayListMultimap.create();
909             populateMultimapForGet(multimap, elements);
910             return Multimaps.transformValues(
911                 multimap, Functions.<String> identity()).get(3);
912           }
913         }).named("Multimaps.transformValues[Multimap].get").withFeatures(
914             CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES,
915             CollectionFeature.REMOVE_OPERATIONS).createTestSuite());
916 
917     suite.addTest(SetTestSuiteBuilder.using(new TestStringSetGenerator() {
918       @Override protected Set<String> create(String[] elements) {
919         Multimap<String, Integer> multimap = ArrayListMultimap.create();
920         populateMultimapForKeySet(multimap, elements);
921         return Multimaps.transformValues(
922             multimap, Functions.<Integer> identity()).keySet();
923       }
924     }).named("Multimaps.transformValues[Multimap].keySet").withFeatures(
925         COLLECTION_FEATURES_REMOVE).createTestSuite());
926 
927     suite.addTest(MultisetTestSuiteBuilder.using(
928         new TestStringMultisetGenerator() {
929           @Override protected Multiset<String> create(String[] elements) {
930             Multimap<String, Integer> multimap
931                 = ArrayListMultimap.create();
932             populateMultimapForKeys(multimap, elements);
933             return Multimaps.transformValues(
934                 multimap, Functions.<Integer> identity()).keys();
935           }
936         })
937         .named("Multimaps.transformValues[Multimap].keys")
938         .withFeatures(COLLECTION_FEATURES_REMOVE)
939         .createTestSuite());
940 
941     suite.addTest(
942         CollectionTestSuiteBuilder.using(new TestStringCollectionGenerator() {
943           @Override public Collection<String> create(String[] elements) {
944             Multimap<Integer, String> multimap = ArrayListMultimap.create();
945             populateMultimapForValues(multimap, elements);
946             return Multimaps.transformValues(
947                 multimap, Functions.<String> identity()).values();
948           }
949         }).named("Multimaps.transformValues[Multimap].values").withFeatures(
950             COLLECTION_FEATURES_REMOVE).createTestSuite());
951 
952     suite.addTest(CollectionTestSuiteBuilder.using(new TestEntriesGenerator() {
953       @Override public Collection<Entry<String, Integer>> create(
954           Object... elements) {
955         Multimap<String, Integer> multimap = ArrayListMultimap.create();
956         for (Object element : elements) {
957           @SuppressWarnings("unchecked")
958           Entry<String, Integer> entry = (Entry<String, Integer>) element;
959           multimap.put(entry.getKey(), entry.getValue());
960         }
961         return Multimaps.transformValues(
962             multimap, Functions.<Integer> identity()).entries();
963       }
964      @Override Multimap<String, Integer> createMultimap() {
965        return Multimaps.transformValues(
966            (Multimap<String, Integer>)
967                 ArrayListMultimap.<String, Integer> create(),
968                 Functions.<Integer> identity());
969       }
970     }).named("Multimaps.transformValues[Multimap].entries")
971         .withFeatures(CollectionSize.ANY, CollectionFeature.REMOVE_OPERATIONS)
972         .createTestSuite());
973 
974     // TODO: use collection testers on Multimaps.forMap.entries
975 
976     return suite;
977   }
978 }
979