MultimapCollectionTest.java revision 1d580d0f6ee4f21eb309ba7b509d2c6d671c4044
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
17package com.google.common.collect;
18
19import static com.google.common.collect.Maps.newHashMap;
20import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
21import static com.google.common.collect.testing.features.CollectionFeature.REMOVE_OPERATIONS;
22import static com.google.common.collect.testing.google.AbstractMultisetSetCountTester.getSetCountDuplicateInitializingMethods;
23import static com.google.common.collect.testing.google.MultisetIteratorTester.getIteratorDuplicateInitializingMethods;
24import static com.google.common.collect.testing.google.MultisetReadsTester.getReadsDuplicateInitializingMethods;
25import static java.lang.reflect.Proxy.newProxyInstance;
26
27import com.google.common.annotations.GwtIncompatible;
28import com.google.common.base.Functions;
29import com.google.common.base.Predicate;
30import com.google.common.base.Supplier;
31import com.google.common.collect.testing.CollectionTestSuiteBuilder;
32import com.google.common.collect.testing.ListTestSuiteBuilder;
33import com.google.common.collect.testing.SampleElements;
34import com.google.common.collect.testing.SetTestSuiteBuilder;
35import com.google.common.collect.testing.TestCollectionGenerator;
36import com.google.common.collect.testing.TestListGenerator;
37import com.google.common.collect.testing.TestStringCollectionGenerator;
38import com.google.common.collect.testing.TestStringListGenerator;
39import com.google.common.collect.testing.TestStringSetGenerator;
40import com.google.common.collect.testing.TestStringSortedSetGenerator;
41import com.google.common.collect.testing.features.CollectionFeature;
42import com.google.common.collect.testing.features.CollectionSize;
43import com.google.common.collect.testing.features.Feature;
44import com.google.common.collect.testing.features.ListFeature;
45import com.google.common.collect.testing.google.MultisetTestSuiteBuilder;
46import com.google.common.collect.testing.google.MultisetWritesTester;
47import com.google.common.collect.testing.google.TestStringMultisetGenerator;
48import com.google.common.collect.testing.testers.CollectionIteratorTester;
49
50import junit.framework.Test;
51import junit.framework.TestCase;
52import junit.framework.TestSuite;
53
54import java.lang.reflect.InvocationHandler;
55import java.lang.reflect.Method;
56import java.util.Collection;
57import java.util.Collections;
58import java.util.List;
59import java.util.Map;
60import java.util.Map.Entry;
61import java.util.Set;
62import java.util.SortedSet;
63import 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
71public 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
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
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
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
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
175    static <K, V> PopulatableMapAsMultimap<K, V> create() {
176      return new PopulatableMapAsMultimap<K, V>();
177    }
178
179    @SuppressWarnings("unchecked") // all methods throw immediately
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
194    @Override protected Multimap<K, V> delegate() {
195      return unusableDelegate;
196    }
197
198    @Override public boolean put(K key, V value) {
199      map.put(key, value);
200      return true;
201    }
202
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
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
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
231    abstract Multimap<String, Integer> createMultimap();
232
233    @Override
234    @SuppressWarnings("unchecked")
235    public Entry<String, Integer>[] createArray(int length) {
236      return (Entry<String, Integer>[]) new Entry<?, ?>[length];
237    }
238
239    @Override
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>> {
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 {
256    @Override abstract SetMultimap<String, Integer> createMultimap();
257
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
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