Home | History | Annotate | Download | only in collect
      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 
    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