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