001/*
002 * Copyright (C) 2012 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing.google;
018
019import static com.google.common.base.Preconditions.checkArgument;
020import static com.google.common.collect.testing.Helpers.mapEntry;
021
022import com.google.common.annotations.GwtIncompatible;
023import com.google.common.collect.ImmutableList;
024import com.google.common.collect.ImmutableMultimap;
025import com.google.common.collect.Multimap;
026import com.google.common.collect.Multiset;
027import com.google.common.collect.testing.AbstractTester;
028import com.google.common.collect.testing.CollectionTestSuiteBuilder;
029import com.google.common.collect.testing.DerivedGenerator;
030import com.google.common.collect.testing.FeatureSpecificTestSuiteBuilder;
031import com.google.common.collect.testing.Helpers;
032import com.google.common.collect.testing.MapTestSuiteBuilder;
033import com.google.common.collect.testing.OneSizeTestContainerGenerator;
034import com.google.common.collect.testing.PerCollectionSizeTestSuiteBuilder;
035import com.google.common.collect.testing.SampleElements;
036import com.google.common.collect.testing.TestCollectionGenerator;
037import com.google.common.collect.testing.TestMapGenerator;
038import com.google.common.collect.testing.TestSubjectGenerator;
039import com.google.common.collect.testing.features.CollectionFeature;
040import com.google.common.collect.testing.features.CollectionSize;
041import com.google.common.collect.testing.features.Feature;
042import com.google.common.collect.testing.features.ListFeature;
043import com.google.common.collect.testing.features.MapFeature;
044import com.google.common.testing.SerializableTester;
045import java.util.ArrayList;
046import java.util.Collection;
047import java.util.Collections;
048import java.util.EnumSet;
049import java.util.HashMap;
050import java.util.HashSet;
051import java.util.Iterator;
052import java.util.LinkedHashMap;
053import java.util.List;
054import java.util.Map;
055import java.util.Map.Entry;
056import java.util.Set;
057import junit.framework.TestSuite;
058
059/**
060 * Creates, based on your criteria, a JUnit test suite that exhaustively tests a {@code Multimap}
061 * implementation.
062 *
063 * @author Louis Wasserman
064 */
065@GwtIncompatible
066public class MultimapTestSuiteBuilder<K, V, M extends Multimap<K, V>>
067    extends PerCollectionSizeTestSuiteBuilder<
068        MultimapTestSuiteBuilder<K, V, M>, TestMultimapGenerator<K, V, M>, M, Entry<K, V>> {
069
070  public static <K, V, M extends Multimap<K, V>> MultimapTestSuiteBuilder<K, V, M> using(
071      TestMultimapGenerator<K, V, M> generator) {
072    return new MultimapTestSuiteBuilder<K, V, M>().usingGenerator(generator);
073  }
074
075  // Class parameters must be raw.
076  @Override
077  protected List<Class<? extends AbstractTester>> getTesters() {
078    return ImmutableList.<Class<? extends AbstractTester>>of(
079        MultimapAsMapGetTester.class,
080        MultimapAsMapTester.class,
081        MultimapSizeTester.class,
082        MultimapClearTester.class,
083        MultimapContainsKeyTester.class,
084        MultimapContainsValueTester.class,
085        MultimapContainsEntryTester.class,
086        MultimapEntriesTester.class,
087        MultimapEqualsTester.class,
088        MultimapGetTester.class,
089        MultimapKeySetTester.class,
090        MultimapKeysTester.class,
091        MultimapPutTester.class,
092        MultimapPutAllMultimapTester.class,
093        MultimapPutIterableTester.class,
094        MultimapReplaceValuesTester.class,
095        MultimapRemoveEntryTester.class,
096        MultimapRemoveAllTester.class,
097        MultimapToStringTester.class,
098        MultimapValuesTester.class);
099  }
100
101  @Override
102  protected List<TestSuite> createDerivedSuites(
103      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
104          parentBuilder) {
105    // TODO: Once invariant support is added, supply invariants to each of the
106    // derived suites, to check that mutations to the derived collections are
107    // reflected in the underlying map.
108
109    List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder);
110
111    if (parentBuilder.getFeatures().contains(CollectionFeature.SERIALIZABLE)) {
112      derivedSuites.add(
113          MultimapTestSuiteBuilder.using(
114                  new ReserializedMultimapGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
115              .withFeatures(computeReserializedMultimapFeatures(parentBuilder.getFeatures()))
116              .named(parentBuilder.getName() + " reserialized")
117              .suppressing(parentBuilder.getSuppressedTests())
118              .withSetUp(parentBuilder.getSetUp())
119              .withTearDown(parentBuilder.getTearDown())
120              .createTestSuite());
121    }
122
123    derivedSuites.add(
124        MapTestSuiteBuilder.using(new AsMapGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
125            .withFeatures(computeAsMapFeatures(parentBuilder.getFeatures()))
126            .named(parentBuilder.getName() + ".asMap")
127            .suppressing(parentBuilder.getSuppressedTests())
128            .withSetUp(parentBuilder.getSetUp())
129            .withTearDown(parentBuilder.getTearDown())
130            .createTestSuite());
131
132    derivedSuites.add(computeEntriesTestSuite(parentBuilder));
133    derivedSuites.add(computeMultimapGetTestSuite(parentBuilder));
134    derivedSuites.add(computeMultimapAsMapGetTestSuite(parentBuilder));
135    derivedSuites.add(computeKeysTestSuite(parentBuilder));
136    derivedSuites.add(computeValuesTestSuite(parentBuilder));
137
138    return derivedSuites;
139  }
140
141  TestSuite computeValuesTestSuite(
142      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
143          parentBuilder) {
144    return CollectionTestSuiteBuilder.using(
145            new ValuesGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
146        .withFeatures(computeValuesFeatures(parentBuilder.getFeatures()))
147        .named(parentBuilder.getName() + ".values")
148        .suppressing(parentBuilder.getSuppressedTests())
149        .createTestSuite();
150  }
151
152  TestSuite computeEntriesTestSuite(
153      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
154          parentBuilder) {
155    return CollectionTestSuiteBuilder.using(
156            new EntriesGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
157        .withFeatures(computeEntriesFeatures(parentBuilder.getFeatures()))
158        .named(parentBuilder.getName() + ".entries")
159        .suppressing(parentBuilder.getSuppressedTests())
160        .withSetUp(parentBuilder.getSetUp())
161        .withTearDown(parentBuilder.getTearDown())
162        .createTestSuite();
163  }
164
165  TestSuite computeMultimapGetTestSuite(
166      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
167          parentBuilder) {
168    return CollectionTestSuiteBuilder.using(
169            new MultimapGetGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
170        .withFeatures(computeMultimapGetFeatures(parentBuilder.getFeatures()))
171        .named(parentBuilder.getName() + ".get[key]")
172        .suppressing(parentBuilder.getSuppressedTests())
173        .withSetUp(parentBuilder.getSetUp())
174        .withTearDown(parentBuilder.getTearDown())
175        .createTestSuite();
176  }
177
178  TestSuite computeMultimapAsMapGetTestSuite(
179      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
180          parentBuilder) {
181    Set<Feature<?>> features = computeMultimapAsMapGetFeatures(parentBuilder.getFeatures());
182    if (Collections.disjoint(features, EnumSet.allOf(CollectionSize.class))) {
183      return new TestSuite();
184    } else {
185      return CollectionTestSuiteBuilder.using(
186              new MultimapAsMapGetGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
187          .withFeatures(features)
188          .named(parentBuilder.getName() + ".asMap[].get[key]")
189          .suppressing(parentBuilder.getSuppressedTests())
190          .withSetUp(parentBuilder.getSetUp())
191          .withTearDown(parentBuilder.getTearDown())
192          .createTestSuite();
193    }
194  }
195
196  TestSuite computeKeysTestSuite(
197      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>>
198          parentBuilder) {
199    return MultisetTestSuiteBuilder.using(
200            new KeysGenerator<K, V, M>(parentBuilder.getSubjectGenerator()))
201        .withFeatures(computeKeysFeatures(parentBuilder.getFeatures()))
202        .named(parentBuilder.getName() + ".keys")
203        .suppressing(parentBuilder.getSuppressedTests())
204        .withSetUp(parentBuilder.getSetUp())
205        .withTearDown(parentBuilder.getTearDown())
206        .createTestSuite();
207  }
208
209  static Set<Feature<?>> computeDerivedCollectionFeatures(Set<Feature<?>> multimapFeatures) {
210    Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures);
211    if (!derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) {
212      derivedFeatures.remove(CollectionFeature.SERIALIZABLE);
213    }
214    if (derivedFeatures.remove(MapFeature.SUPPORTS_REMOVE)) {
215      derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE);
216    }
217    return derivedFeatures;
218  }
219
220  static Set<Feature<?>> computeEntriesFeatures(Set<Feature<?>> multimapFeatures) {
221    Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures);
222    if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_ENTRY_QUERIES)) {
223      result.add(CollectionFeature.ALLOWS_NULL_QUERIES);
224    }
225    return result;
226  }
227
228  static Set<Feature<?>> computeValuesFeatures(Set<Feature<?>> multimapFeatures) {
229    Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures);
230    if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) {
231      result.add(CollectionFeature.ALLOWS_NULL_VALUES);
232    }
233    if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_VALUE_QUERIES)) {
234      result.add(CollectionFeature.ALLOWS_NULL_QUERIES);
235    }
236    return result;
237  }
238
239  static Set<Feature<?>> computeKeysFeatures(Set<Feature<?>> multimapFeatures) {
240    Set<Feature<?>> result = computeDerivedCollectionFeatures(multimapFeatures);
241    if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_KEYS)) {
242      result.add(CollectionFeature.ALLOWS_NULL_VALUES);
243    }
244    if (multimapFeatures.contains(MapFeature.ALLOWS_NULL_KEY_QUERIES)) {
245      result.add(CollectionFeature.ALLOWS_NULL_QUERIES);
246    }
247    return result;
248  }
249
250  private static Set<Feature<?>> computeReserializedMultimapFeatures(
251      Set<Feature<?>> multimapFeatures) {
252    Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures);
253    derivedFeatures.remove(CollectionFeature.SERIALIZABLE);
254    derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS);
255    return derivedFeatures;
256  }
257
258  private static Set<Feature<?>> computeAsMapFeatures(Set<Feature<?>> multimapFeatures) {
259    Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures);
260    derivedFeatures.remove(MapFeature.GENERAL_PURPOSE);
261    derivedFeatures.remove(MapFeature.SUPPORTS_PUT);
262    derivedFeatures.remove(MapFeature.ALLOWS_NULL_VALUES);
263    derivedFeatures.add(MapFeature.ALLOWS_NULL_VALUE_QUERIES);
264    derivedFeatures.add(MapFeature.REJECTS_DUPLICATES_AT_CREATION);
265    if (!derivedFeatures.contains(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) {
266      derivedFeatures.remove(CollectionFeature.SERIALIZABLE);
267    }
268    return derivedFeatures;
269  }
270
271  private static final ImmutableMultimap<Feature<?>, Feature<?>> GET_FEATURE_MAP =
272      ImmutableMultimap.<Feature<?>, Feature<?>>builder()
273          .put(
274              MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
275              CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION)
276          .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_ADD_WITH_INDEX)
277          .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_REMOVE_WITH_INDEX)
278          .put(MapFeature.GENERAL_PURPOSE, ListFeature.SUPPORTS_SET)
279          .put(MapFeature.ALLOWS_NULL_VALUE_QUERIES, CollectionFeature.ALLOWS_NULL_QUERIES)
280          .put(MapFeature.ALLOWS_NULL_VALUES, CollectionFeature.ALLOWS_NULL_VALUES)
281          .put(MapFeature.SUPPORTS_REMOVE, CollectionFeature.SUPPORTS_REMOVE)
282          .put(MapFeature.SUPPORTS_PUT, CollectionFeature.SUPPORTS_ADD)
283          .build();
284
285  Set<Feature<?>> computeMultimapGetFeatures(Set<Feature<?>> multimapFeatures) {
286    Set<Feature<?>> derivedFeatures = Helpers.copyToSet(multimapFeatures);
287    for (Entry<Feature<?>, Feature<?>> entry : GET_FEATURE_MAP.entries()) {
288      if (derivedFeatures.contains(entry.getKey())) {
289        derivedFeatures.add(entry.getValue());
290      }
291    }
292    if (derivedFeatures.remove(MultimapFeature.VALUE_COLLECTIONS_SUPPORT_ITERATOR_REMOVE)) {
293      derivedFeatures.add(CollectionFeature.SUPPORTS_ITERATOR_REMOVE);
294    }
295    if (!derivedFeatures.contains(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) {
296      derivedFeatures.remove(CollectionFeature.SERIALIZABLE);
297    }
298    derivedFeatures.removeAll(GET_FEATURE_MAP.keySet());
299    return derivedFeatures;
300  }
301
302  Set<Feature<?>> computeMultimapAsMapGetFeatures(Set<Feature<?>> multimapFeatures) {
303    Set<Feature<?>> derivedFeatures =
304        Helpers.copyToSet(computeMultimapGetFeatures(multimapFeatures));
305    if (derivedFeatures.remove(CollectionSize.ANY)) {
306      derivedFeatures.addAll(CollectionSize.ANY.getImpliedFeatures());
307    }
308    derivedFeatures.remove(CollectionSize.ZERO);
309    return derivedFeatures;
310  }
311
312  private static class AsMapGenerator<K, V, M extends Multimap<K, V>>
313      implements TestMapGenerator<K, Collection<V>>, DerivedGenerator {
314    private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
315
316    public AsMapGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
317      this.multimapGenerator = multimapGenerator;
318    }
319
320    @Override
321    public TestSubjectGenerator<?> getInnerGenerator() {
322      return multimapGenerator;
323    }
324
325    private Collection<V> createCollection(V v) {
326      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
327          .createCollection(Collections.singleton(v));
328    }
329
330    @Override
331    public SampleElements<Entry<K, Collection<V>>> samples() {
332      SampleElements<K> sampleKeys =
333          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys();
334      SampleElements<V> sampleValues =
335          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleValues();
336      return new SampleElements<>(
337          mapEntry(sampleKeys.e0(), createCollection(sampleValues.e0())),
338          mapEntry(sampleKeys.e1(), createCollection(sampleValues.e1())),
339          mapEntry(sampleKeys.e2(), createCollection(sampleValues.e2())),
340          mapEntry(sampleKeys.e3(), createCollection(sampleValues.e3())),
341          mapEntry(sampleKeys.e4(), createCollection(sampleValues.e4())));
342    }
343
344    @Override
345    public Map<K, Collection<V>> create(Object... elements) {
346      Set<K> keySet = new HashSet<>();
347      List<Entry<K, V>> builder = new ArrayList<>();
348      for (Object o : elements) {
349        Entry<K, Collection<V>> entry = (Entry<K, Collection<V>>) o;
350        keySet.add(entry.getKey());
351        for (V v : entry.getValue()) {
352          builder.add(mapEntry(entry.getKey(), v));
353        }
354      }
355      checkArgument(keySet.size() == elements.length, "Duplicate keys");
356      return multimapGenerator.create(builder.toArray()).asMap();
357    }
358
359    @SuppressWarnings("unchecked")
360    @Override
361    public Entry<K, Collection<V>>[] createArray(int length) {
362      return new Entry[length];
363    }
364
365    @Override
366    public Iterable<Entry<K, Collection<V>>> order(List<Entry<K, Collection<V>>> insertionOrder) {
367      Map<K, Collection<V>> map = new HashMap<>();
368      List<Entry<K, V>> builder = new ArrayList<>();
369      for (Entry<K, Collection<V>> entry : insertionOrder) {
370        for (V v : entry.getValue()) {
371          builder.add(mapEntry(entry.getKey(), v));
372        }
373        map.put(entry.getKey(), entry.getValue());
374      }
375      Iterable<Entry<K, V>> ordered = multimapGenerator.order(builder);
376      LinkedHashMap<K, Collection<V>> orderedMap = new LinkedHashMap<>();
377      for (Entry<K, V> entry : ordered) {
378        orderedMap.put(entry.getKey(), map.get(entry.getKey()));
379      }
380      return orderedMap.entrySet();
381    }
382
383    @Override
384    public K[] createKeyArray(int length) {
385      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
386          .createKeyArray(length);
387    }
388
389    @SuppressWarnings("unchecked")
390    @Override
391    public Collection<V>[] createValueArray(int length) {
392      return new Collection[length];
393    }
394  }
395
396  static class EntriesGenerator<K, V, M extends Multimap<K, V>>
397      implements TestCollectionGenerator<Entry<K, V>>, DerivedGenerator {
398    private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
399
400    public EntriesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
401      this.multimapGenerator = multimapGenerator;
402    }
403
404    @Override
405    public TestSubjectGenerator<?> getInnerGenerator() {
406      return multimapGenerator;
407    }
408
409    @Override
410    public SampleElements<Entry<K, V>> samples() {
411      return multimapGenerator.samples();
412    }
413
414    @Override
415    public Collection<Entry<K, V>> create(Object... elements) {
416      return multimapGenerator.create(elements).entries();
417    }
418
419    @SuppressWarnings("unchecked")
420    @Override
421    public Entry<K, V>[] createArray(int length) {
422      return new Entry[length];
423    }
424
425    @Override
426    public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
427      return multimapGenerator.order(insertionOrder);
428    }
429  }
430
431  static class ValuesGenerator<K, V, M extends Multimap<K, V>>
432      implements TestCollectionGenerator<V> {
433    private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
434
435    public ValuesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
436      this.multimapGenerator = multimapGenerator;
437    }
438
439    @Override
440    public SampleElements<V> samples() {
441      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
442          .sampleValues();
443    }
444
445    @Override
446    public Collection<V> create(Object... elements) {
447      K k =
448          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
449              .sampleKeys()
450              .e0();
451      Entry<K, V>[] entries = new Entry[elements.length];
452      for (int i = 0; i < elements.length; i++) {
453        entries[i] = mapEntry(k, (V) elements[i]);
454      }
455      return multimapGenerator.create((Object[]) entries).values();
456    }
457
458    @SuppressWarnings("unchecked")
459    @Override
460    public V[] createArray(int length) {
461      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
462          .createValueArray(length);
463    }
464
465    @Override
466    public Iterable<V> order(List<V> insertionOrder) {
467      K k =
468          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
469              .sampleKeys()
470              .e0();
471      List<Entry<K, V>> entries = new ArrayList<>();
472      for (V v : insertionOrder) {
473        entries.add(mapEntry(k, v));
474      }
475      Iterable<Entry<K, V>> ordered = multimapGenerator.order(entries);
476      List<V> orderedValues = new ArrayList<>();
477      for (Entry<K, V> entry : ordered) {
478        orderedValues.add(entry.getValue());
479      }
480      return orderedValues;
481    }
482  }
483
484  static class KeysGenerator<K, V, M extends Multimap<K, V>>
485      implements TestMultisetGenerator<K>, DerivedGenerator {
486    private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
487
488    public KeysGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
489      this.multimapGenerator = multimapGenerator;
490    }
491
492    @Override
493    public TestSubjectGenerator<?> getInnerGenerator() {
494      return multimapGenerator;
495    }
496
497    @Override
498    public SampleElements<K> samples() {
499      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys();
500    }
501
502    @Override
503    public Multiset<K> create(Object... elements) {
504      /*
505       * This is nasty and complicated, but it's the only way to make sure keys get mapped to enough
506       * distinct values.
507       */
508      Entry[] entries = new Entry[elements.length];
509      Map<K, Iterator<V>> valueIterators = new HashMap<>();
510      for (int i = 0; i < elements.length; i++) {
511        @SuppressWarnings("unchecked")
512        K key = (K) elements[i];
513
514        Iterator<V> valueItr = valueIterators.get(key);
515        if (valueItr == null) {
516          valueIterators.put(key, valueItr = sampleValuesIterator());
517        }
518        entries[i] = mapEntry((K) elements[i], valueItr.next());
519      }
520      return multimapGenerator.create((Object[]) entries).keys();
521    }
522
523    private Iterator<V> sampleValuesIterator() {
524      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
525          .sampleValues()
526          .iterator();
527    }
528
529    @SuppressWarnings("unchecked")
530    @Override
531    public K[] createArray(int length) {
532      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
533          .createKeyArray(length);
534    }
535
536    @Override
537    public Iterable<K> order(List<K> insertionOrder) {
538      Iterator<V> valueIter = sampleValuesIterator();
539      List<Entry<K, V>> entries = new ArrayList<>();
540      for (K k : insertionOrder) {
541        entries.add(mapEntry(k, valueIter.next()));
542      }
543      Iterable<Entry<K, V>> ordered = multimapGenerator.order(entries);
544      List<K> orderedValues = new ArrayList<>();
545      for (Entry<K, V> entry : ordered) {
546        orderedValues.add(entry.getKey());
547      }
548      return orderedValues;
549    }
550  }
551
552  static class MultimapGetGenerator<K, V, M extends Multimap<K, V>>
553      implements TestCollectionGenerator<V> {
554    final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
555
556    public MultimapGetGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
557      this.multimapGenerator = multimapGenerator;
558    }
559
560    @Override
561    public SampleElements<V> samples() {
562      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
563          .sampleValues();
564    }
565
566    @Override
567    public V[] createArray(int length) {
568      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
569          .createValueArray(length);
570    }
571
572    @Override
573    public Iterable<V> order(List<V> insertionOrder) {
574      K k =
575          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
576              .sampleKeys()
577              .e0();
578      List<Entry<K, V>> entries = new ArrayList<>();
579      for (V v : insertionOrder) {
580        entries.add(mapEntry(k, v));
581      }
582      Iterable<Entry<K, V>> orderedEntries = multimapGenerator.order(entries);
583      List<V> values = new ArrayList<>();
584      for (Entry<K, V> entry : orderedEntries) {
585        values.add(entry.getValue());
586      }
587      return values;
588    }
589
590    @Override
591    public Collection<V> create(Object... elements) {
592      Entry<K, V>[] array = multimapGenerator.createArray(elements.length);
593      K k =
594          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
595              .sampleKeys()
596              .e0();
597      for (int i = 0; i < elements.length; i++) {
598        array[i] = mapEntry(k, (V) elements[i]);
599      }
600      return multimapGenerator.create((Object[]) array).get(k);
601    }
602  }
603
604  static class MultimapAsMapGetGenerator<K, V, M extends Multimap<K, V>>
605      extends MultimapGetGenerator<K, V, M> {
606
607    public MultimapAsMapGetGenerator(
608        OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
609      super(multimapGenerator);
610    }
611
612    @Override
613    public Collection<V> create(Object... elements) {
614      Entry<K, V>[] array = multimapGenerator.createArray(elements.length);
615      K k =
616          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
617              .sampleKeys()
618              .e0();
619      for (int i = 0; i < elements.length; i++) {
620        array[i] = mapEntry(k, (V) elements[i]);
621      }
622      return multimapGenerator.create((Object[]) array).asMap().get(k);
623    }
624  }
625
626  private static class ReserializedMultimapGenerator<K, V, M extends Multimap<K, V>>
627      implements TestMultimapGenerator<K, V, M> {
628    private final OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator;
629
630    public ReserializedMultimapGenerator(
631        OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
632      this.multimapGenerator = multimapGenerator;
633    }
634
635    @Override
636    public SampleElements<Entry<K, V>> samples() {
637      return multimapGenerator.samples();
638    }
639
640    @Override
641    public Entry<K, V>[] createArray(int length) {
642      return multimapGenerator.createArray(length);
643    }
644
645    @Override
646    public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
647      return multimapGenerator.order(insertionOrder);
648    }
649
650    @Override
651    public M create(Object... elements) {
652      return SerializableTester.reserialize(
653          ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
654              .create(elements));
655    }
656
657    @Override
658    public K[] createKeyArray(int length) {
659      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
660          .createKeyArray(length);
661    }
662
663    @Override
664    public V[] createValueArray(int length) {
665      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
666          .createValueArray(length);
667    }
668
669    @Override
670    public SampleElements<K> sampleKeys() {
671      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys();
672    }
673
674    @Override
675    public SampleElements<V> sampleValues() {
676      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
677          .sampleValues();
678    }
679
680    @Override
681    public Collection<V> createCollection(Iterable<? extends V> values) {
682      return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
683          .createCollection(values);
684    }
685  }
686}