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