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