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