• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 a {@code Multimap}
61  * 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, Entry<K, V>> {
69 
using( TestMultimapGenerator<K, V, M> generator)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
getTesters()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
createDerivedSuites( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeValuesTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeEntriesTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeMultimapGetTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeMultimapAsMapGetTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeKeysTestSuite( FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<M, Entry<K, V>>> parentBuilder)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 
computeDerivedCollectionFeatures(Set<Feature<?>> multimapFeatures)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 
computeEntriesFeatures(Set<Feature<?>> multimapFeatures)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 
computeValuesFeatures(Set<Feature<?>> multimapFeatures)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 
computeKeysFeatures(Set<Feature<?>> multimapFeatures)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 
computeReserializedMultimapFeatures( Set<Feature<?>> multimapFeatures)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 
computeAsMapFeatures(Set<Feature<?>> multimapFeatures)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 
computeMultimapGetFeatures(Set<Feature<?>> multimapFeatures)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 
computeMultimapAsMapGetFeatures(Set<Feature<?>> multimapFeatures)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 
AsMapGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)317     public AsMapGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
318       this.multimapGenerator = multimapGenerator;
319     }
320 
321     @Override
getInnerGenerator()322     public TestSubjectGenerator<?> getInnerGenerator() {
323       return multimapGenerator;
324     }
325 
createCollection(V v)326     private Collection<V> createCollection(V v) {
327       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
328           .createCollection(Collections.singleton(v));
329     }
330 
331     @Override
samples()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
create(Object... elements)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
createArray(int length)362     public Entry<K, Collection<V>>[] createArray(int length) {
363       return new Entry[length];
364     }
365 
366     @Override
order(List<Entry<K, Collection<V>>> insertionOrder)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
createKeyArray(int length)385     public K[] createKeyArray(int length) {
386       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
387           .createKeyArray(length);
388     }
389 
390     @SuppressWarnings("unchecked")
391     @Override
createValueArray(int length)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 
EntriesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)401     public EntriesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
402       this.multimapGenerator = multimapGenerator;
403     }
404 
405     @Override
getInnerGenerator()406     public TestSubjectGenerator<?> getInnerGenerator() {
407       return multimapGenerator;
408     }
409 
410     @Override
samples()411     public SampleElements<Entry<K, V>> samples() {
412       return multimapGenerator.samples();
413     }
414 
415     @Override
create(Object... elements)416     public Collection<Entry<K, V>> create(Object... elements) {
417       return multimapGenerator.create(elements).entries();
418     }
419 
420     @SuppressWarnings("unchecked")
421     @Override
createArray(int length)422     public Entry<K, V>[] createArray(int length) {
423       return new Entry[length];
424     }
425 
426     @Override
order(List<Entry<K, V>> insertionOrder)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 
ValuesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)436     public ValuesGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
437       this.multimapGenerator = multimapGenerator;
438     }
439 
440     @Override
samples()441     public SampleElements<V> samples() {
442       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
443           .sampleValues();
444     }
445 
446     @Override
create(Object... elements)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
createArray(int length)461     public V[] createArray(int length) {
462       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
463           .createValueArray(length);
464     }
465 
466     @Override
order(List<V> insertionOrder)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 
KeysGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)489     public KeysGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
490       this.multimapGenerator = multimapGenerator;
491     }
492 
493     @Override
getInnerGenerator()494     public TestSubjectGenerator<?> getInnerGenerator() {
495       return multimapGenerator;
496     }
497 
498     @Override
samples()499     public SampleElements<K> samples() {
500       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys();
501     }
502 
503     @Override
create(Object... elements)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 
sampleValuesIterator()524     private Iterator<V> sampleValuesIterator() {
525       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
526           .sampleValues()
527           .iterator();
528     }
529 
530     @SuppressWarnings("unchecked")
531     @Override
createArray(int length)532     public K[] createArray(int length) {
533       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
534           .createKeyArray(length);
535     }
536 
537     @Override
order(List<K> insertionOrder)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 
MultimapGetGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)557     public MultimapGetGenerator(OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
558       this.multimapGenerator = multimapGenerator;
559     }
560 
561     @Override
samples()562     public SampleElements<V> samples() {
563       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
564           .sampleValues();
565     }
566 
567     @Override
createArray(int length)568     public V[] createArray(int length) {
569       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
570           .createValueArray(length);
571     }
572 
573     @Override
order(List<V> insertionOrder)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
create(Object... elements)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 
MultimapAsMapGetGenerator( OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)608     public MultimapAsMapGetGenerator(
609         OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
610       super(multimapGenerator);
611     }
612 
613     @Override
create(Object... elements)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 
ReserializedMultimapGenerator( OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator)631     public ReserializedMultimapGenerator(
632         OneSizeTestContainerGenerator<M, Entry<K, V>> multimapGenerator) {
633       this.multimapGenerator = multimapGenerator;
634     }
635 
636     @Override
samples()637     public SampleElements<Entry<K, V>> samples() {
638       return multimapGenerator.samples();
639     }
640 
641     @Override
createArray(int length)642     public Entry<K, V>[] createArray(int length) {
643       return multimapGenerator.createArray(length);
644     }
645 
646     @Override
order(List<Entry<K, V>> insertionOrder)647     public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
648       return multimapGenerator.order(insertionOrder);
649     }
650 
651     @Override
create(Object... elements)652     public M create(Object... elements) {
653       return SerializableTester.reserialize(
654           ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
655               .create(elements));
656     }
657 
658     @Override
createKeyArray(int length)659     public K[] createKeyArray(int length) {
660       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
661           .createKeyArray(length);
662     }
663 
664     @Override
createValueArray(int length)665     public V[] createValueArray(int length) {
666       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
667           .createValueArray(length);
668     }
669 
670     @Override
sampleKeys()671     public SampleElements<K> sampleKeys() {
672       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator()).sampleKeys();
673     }
674 
675     @Override
sampleValues()676     public SampleElements<V> sampleValues() {
677       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
678           .sampleValues();
679     }
680 
681     @Override
createCollection(Iterable<? extends V> values)682     public Collection<V> createCollection(Iterable<? extends V> values) {
683       return ((TestMultimapGenerator<K, V, M>) multimapGenerator.getInnerGenerator())
684           .createCollection(values);
685     }
686   }
687 }
688