• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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;
18 
19 import static com.google.common.collect.testing.Helpers.castOrCopyToList;
20 import static com.google.common.collect.testing.Helpers.equal;
21 import static com.google.common.collect.testing.Helpers.mapEntry;
22 import static java.util.Collections.sort;
23 
24 import com.google.common.annotations.GwtCompatible;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.Set;
34 import java.util.SortedMap;
35 import java.util.SortedSet;
36 
37 /**
38  * Derived suite generators, split out of the suite builders so that they are available to GWT.
39  *
40  * @author George van den Driessche
41  */
42 @GwtCompatible
43 public final class DerivedCollectionGenerators {
44   public static class MapEntrySetGenerator<K, V>
45       implements TestSetGenerator<Entry<K, V>>, DerivedGenerator {
46     private final OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator;
47 
MapEntrySetGenerator( OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)48     public MapEntrySetGenerator(
49         OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
50       this.mapGenerator = mapGenerator;
51     }
52 
53     @Override
samples()54     public SampleElements<Entry<K, V>> samples() {
55       return mapGenerator.samples();
56     }
57 
58     @Override
create(Object... elements)59     public Set<Entry<K, V>> create(Object... elements) {
60       return mapGenerator.create(elements).entrySet();
61     }
62 
63     @Override
createArray(int length)64     public Entry<K, V>[] createArray(int length) {
65       return mapGenerator.createArray(length);
66     }
67 
68     @Override
order(List<Entry<K, V>> insertionOrder)69     public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
70       return mapGenerator.order(insertionOrder);
71     }
72 
73     @Override
getInnerGenerator()74     public OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> getInnerGenerator() {
75       return mapGenerator;
76     }
77   }
78 
79   // TODO: investigate some API changes to SampleElements that would tidy up
80   // parts of the following classes.
81 
keySetGenerator( OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)82   static <K, V> TestSetGenerator<K> keySetGenerator(
83       OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
84     TestContainerGenerator<Map<K, V>, Entry<K, V>> generator = mapGenerator.getInnerGenerator();
85     if (generator instanceof TestSortedMapGenerator
86         && ((TestSortedMapGenerator<K, V>) generator).create().keySet() instanceof SortedSet) {
87       return new MapSortedKeySetGenerator<>(mapGenerator);
88     } else {
89       return new MapKeySetGenerator<>(mapGenerator);
90     }
91   }
92 
93   public static class MapKeySetGenerator<K, V> implements TestSetGenerator<K>, DerivedGenerator {
94     private final OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator;
95     private final SampleElements<K> samples;
96 
MapKeySetGenerator(OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)97     public MapKeySetGenerator(OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
98       this.mapGenerator = mapGenerator;
99       SampleElements<Entry<K, V>> mapSamples = this.mapGenerator.samples();
100       this.samples =
101           new SampleElements<>(
102               mapSamples.e0().getKey(),
103               mapSamples.e1().getKey(),
104               mapSamples.e2().getKey(),
105               mapSamples.e3().getKey(),
106               mapSamples.e4().getKey());
107     }
108 
109     @Override
samples()110     public SampleElements<K> samples() {
111       return samples;
112     }
113 
114     @Override
create(Object... elements)115     public Set<K> create(Object... elements) {
116       @SuppressWarnings("unchecked")
117       K[] keysArray = (K[]) elements;
118 
119       // Start with a suitably shaped collection of entries
120       Collection<Entry<K, V>> originalEntries = mapGenerator.getSampleElements(elements.length);
121 
122       // Create a copy of that, with the desired value for each key
123       Collection<Entry<K, V>> entries = new ArrayList<>(elements.length);
124       int i = 0;
125       for (Entry<K, V> entry : originalEntries) {
126         entries.add(Helpers.mapEntry(keysArray[i++], entry.getValue()));
127       }
128 
129       return mapGenerator.create(entries.toArray()).keySet();
130     }
131 
132     @Override
createArray(int length)133     public K[] createArray(int length) {
134       // TODO: with appropriate refactoring of OneSizeGenerator, we can perhaps
135       // tidy this up and get rid of the casts here and in
136       // MapValueCollectionGenerator.
137 
138       return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createKeyArray(length);
139     }
140 
141     @Override
order(List<K> insertionOrder)142     public Iterable<K> order(List<K> insertionOrder) {
143       V v = ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).samples().e0().getValue();
144       List<Entry<K, V>> entries = new ArrayList<>();
145       for (K element : insertionOrder) {
146         entries.add(mapEntry(element, v));
147       }
148 
149       List<K> keys = new ArrayList<>();
150       for (Entry<K, V> entry : mapGenerator.order(entries)) {
151         keys.add(entry.getKey());
152       }
153       return keys;
154     }
155 
156     @Override
getInnerGenerator()157     public OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> getInnerGenerator() {
158       return mapGenerator;
159     }
160   }
161 
162   public static class MapSortedKeySetGenerator<K, V> extends MapKeySetGenerator<K, V>
163       implements TestSortedSetGenerator<K>, DerivedGenerator {
164     private final TestSortedMapGenerator<K, V> delegate;
165 
MapSortedKeySetGenerator( OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)166     public MapSortedKeySetGenerator(
167         OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
168       super(mapGenerator);
169       this.delegate = (TestSortedMapGenerator<K, V>) mapGenerator.getInnerGenerator();
170     }
171 
172     @Override
create(Object... elements)173     public SortedSet<K> create(Object... elements) {
174       return (SortedSet<K>) super.create(elements);
175     }
176 
177     @Override
belowSamplesLesser()178     public K belowSamplesLesser() {
179       return delegate.belowSamplesLesser().getKey();
180     }
181 
182     @Override
belowSamplesGreater()183     public K belowSamplesGreater() {
184       return delegate.belowSamplesGreater().getKey();
185     }
186 
187     @Override
aboveSamplesLesser()188     public K aboveSamplesLesser() {
189       return delegate.aboveSamplesLesser().getKey();
190     }
191 
192     @Override
aboveSamplesGreater()193     public K aboveSamplesGreater() {
194       return delegate.aboveSamplesGreater().getKey();
195     }
196   }
197 
198   public static class MapValueCollectionGenerator<K, V>
199       implements TestCollectionGenerator<V>, DerivedGenerator {
200     private final OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator;
201     private final SampleElements<V> samples;
202 
MapValueCollectionGenerator( OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)203     public MapValueCollectionGenerator(
204         OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
205       this.mapGenerator = mapGenerator;
206       SampleElements<Entry<K, V>> mapSamples = this.mapGenerator.samples();
207       this.samples =
208           new SampleElements<>(
209               mapSamples.e0().getValue(),
210               mapSamples.e1().getValue(),
211               mapSamples.e2().getValue(),
212               mapSamples.e3().getValue(),
213               mapSamples.e4().getValue());
214     }
215 
216     @Override
samples()217     public SampleElements<V> samples() {
218       return samples;
219     }
220 
221     @Override
create(Object... elements)222     public Collection<V> create(Object... elements) {
223       @SuppressWarnings("unchecked")
224       V[] valuesArray = (V[]) elements;
225 
226       // Start with a suitably shaped collection of entries
227       Collection<Entry<K, V>> originalEntries = mapGenerator.getSampleElements(elements.length);
228 
229       // Create a copy of that, with the desired value for each value
230       Collection<Entry<K, V>> entries = new ArrayList<>(elements.length);
231       int i = 0;
232       for (Entry<K, V> entry : originalEntries) {
233         entries.add(Helpers.mapEntry(entry.getKey(), valuesArray[i++]));
234       }
235 
236       return mapGenerator.create(entries.toArray()).values();
237     }
238 
239     @Override
createArray(int length)240     public V[] createArray(int length) {
241       // noinspection UnnecessaryLocalVariable
242       V[] vs = ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createValueArray(length);
243       return vs;
244     }
245 
246     @Override
order(List<V> insertionOrder)247     public Iterable<V> order(List<V> insertionOrder) {
248       List<Entry<K, V>> orderedEntries =
249           castOrCopyToList(mapGenerator.order(castOrCopyToList(mapGenerator.getSampleElements(5))));
250       sort(
251           insertionOrder,
252           new Comparator<V>() {
253             @Override
254             public int compare(V left, V right) {
255               // The indexes are small enough for the subtraction trick to be safe.
256               return indexOfEntryWithValue(left) - indexOfEntryWithValue(right);
257             }
258 
259             int indexOfEntryWithValue(V value) {
260               for (int i = 0; i < orderedEntries.size(); i++) {
261                 if (equal(orderedEntries.get(i).getValue(), value)) {
262                   return i;
263                 }
264               }
265               throw new IllegalArgumentException(
266                   "Map.values generator can order only sample values");
267             }
268           });
269       return insertionOrder;
270     }
271 
272     @Override
getInnerGenerator()273     public OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> getInnerGenerator() {
274       return mapGenerator;
275     }
276   }
277 
278   // TODO(cpovirk): could something like this be used elsewhere, e.g., ReserializedListGenerator?
279   static class ForwardingTestMapGenerator<K, V> implements TestMapGenerator<K, V> {
280     TestMapGenerator<K, V> delegate;
281 
ForwardingTestMapGenerator(TestMapGenerator<K, V> delegate)282     ForwardingTestMapGenerator(TestMapGenerator<K, V> delegate) {
283       this.delegate = delegate;
284     }
285 
286     @Override
order(List<Entry<K, V>> insertionOrder)287     public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
288       return delegate.order(insertionOrder);
289     }
290 
291     @Override
createKeyArray(int length)292     public K[] createKeyArray(int length) {
293       return delegate.createKeyArray(length);
294     }
295 
296     @Override
createValueArray(int length)297     public V[] createValueArray(int length) {
298       return delegate.createValueArray(length);
299     }
300 
301     @Override
samples()302     public SampleElements<Entry<K, V>> samples() {
303       return delegate.samples();
304     }
305 
306     @Override
create(Object... elements)307     public Map<K, V> create(Object... elements) {
308       return delegate.create(elements);
309     }
310 
311     @Override
createArray(int length)312     public Entry<K, V>[] createArray(int length) {
313       return delegate.createArray(length);
314     }
315   }
316 
317   /** Two bounds (from and to) define how to build a subMap. */
318   public enum Bound {
319     INCLUSIVE,
320     EXCLUSIVE,
321     NO_BOUND;
322   }
323 
324   public static class SortedSetSubsetTestSetGenerator<E> implements TestSortedSetGenerator<E> {
325     final Bound to;
326     final Bound from;
327     final E firstInclusive;
328     final E lastInclusive;
329     private final Comparator<? super E> comparator;
330     private final TestSortedSetGenerator<E> delegate;
331 
SortedSetSubsetTestSetGenerator( TestSortedSetGenerator<E> delegate, Bound to, Bound from)332     public SortedSetSubsetTestSetGenerator(
333         TestSortedSetGenerator<E> delegate, Bound to, Bound from) {
334       this.to = to;
335       this.from = from;
336       this.delegate = delegate;
337 
338       SortedSet<E> emptySet = delegate.create();
339       this.comparator = emptySet.comparator();
340 
341       SampleElements<E> samples = delegate.samples();
342       List<E> samplesList = new ArrayList<>(samples.asList());
343       Collections.sort(samplesList, comparator);
344       this.firstInclusive = samplesList.get(0);
345       this.lastInclusive = samplesList.get(samplesList.size() - 1);
346     }
347 
getInnerGenerator()348     public final TestSortedSetGenerator<E> getInnerGenerator() {
349       return delegate;
350     }
351 
getTo()352     public final Bound getTo() {
353       return to;
354     }
355 
getFrom()356     public final Bound getFrom() {
357       return from;
358     }
359 
360     @Override
samples()361     public SampleElements<E> samples() {
362       return delegate.samples();
363     }
364 
365     @Override
createArray(int length)366     public E[] createArray(int length) {
367       return delegate.createArray(length);
368     }
369 
370     @Override
order(List<E> insertionOrder)371     public Iterable<E> order(List<E> insertionOrder) {
372       return delegate.order(insertionOrder);
373     }
374 
375     @Override
create(Object... elements)376     public SortedSet<E> create(Object... elements) {
377       List<?> normalValues = (List<?>) Arrays.asList(elements);
378       List<E> extremeValues = new ArrayList<>();
379 
380       // nulls are usually out of bounds for a subset, so ban them altogether
381       for (Object o : elements) {
382         if (o == null) {
383           throw new NullPointerException();
384         }
385       }
386 
387       // prepare extreme values to be filtered out of view
388       E firstExclusive = delegate.belowSamplesGreater();
389       E lastExclusive = delegate.aboveSamplesLesser();
390       if (from != Bound.NO_BOUND) {
391         extremeValues.add(delegate.belowSamplesLesser());
392         extremeValues.add(delegate.belowSamplesGreater());
393       }
394       if (to != Bound.NO_BOUND) {
395         extremeValues.add(delegate.aboveSamplesLesser());
396         extremeValues.add(delegate.aboveSamplesGreater());
397       }
398 
399       // the regular values should be visible after filtering
400       List<Object> allEntries = new ArrayList<>();
401       allEntries.addAll(extremeValues);
402       allEntries.addAll(normalValues);
403       SortedSet<E> set = delegate.create(allEntries.toArray());
404 
405       return createSubSet(set, firstExclusive, lastExclusive);
406     }
407 
408     /** Calls the smallest subSet overload that filters out the extreme values. */
createSubSet(SortedSet<E> set, E firstExclusive, E lastExclusive)409     SortedSet<E> createSubSet(SortedSet<E> set, E firstExclusive, E lastExclusive) {
410       if (from == Bound.NO_BOUND && to == Bound.EXCLUSIVE) {
411         return set.headSet(lastExclusive);
412       } else if (from == Bound.INCLUSIVE && to == Bound.NO_BOUND) {
413         return set.tailSet(firstInclusive);
414       } else if (from == Bound.INCLUSIVE && to == Bound.EXCLUSIVE) {
415         return set.subSet(firstInclusive, lastExclusive);
416       } else {
417         throw new IllegalArgumentException();
418       }
419     }
420 
421     @Override
belowSamplesLesser()422     public E belowSamplesLesser() {
423       throw new UnsupportedOperationException();
424     }
425 
426     @Override
belowSamplesGreater()427     public E belowSamplesGreater() {
428       throw new UnsupportedOperationException();
429     }
430 
431     @Override
aboveSamplesLesser()432     public E aboveSamplesLesser() {
433       throw new UnsupportedOperationException();
434     }
435 
436     @Override
aboveSamplesGreater()437     public E aboveSamplesGreater() {
438       throw new UnsupportedOperationException();
439     }
440   }
441 
442   /*
443    * TODO(cpovirk): surely we can find a less ugly solution than a class that accepts 3 parameters,
444    * exposes as many getters, does work in the constructor, and has both a superclass and a subclass
445    */
446   public static class SortedMapSubmapTestMapGenerator<K, V> extends ForwardingTestMapGenerator<K, V>
447       implements TestSortedMapGenerator<K, V> {
448     final Bound to;
449     final Bound from;
450     final K firstInclusive;
451     final K lastInclusive;
452     private final Comparator<Entry<K, V>> entryComparator;
453 
SortedMapSubmapTestMapGenerator( TestSortedMapGenerator<K, V> delegate, Bound to, Bound from)454     public SortedMapSubmapTestMapGenerator(
455         TestSortedMapGenerator<K, V> delegate, Bound to, Bound from) {
456       super(delegate);
457       this.to = to;
458       this.from = from;
459 
460       SortedMap<K, V> emptyMap = delegate.create();
461       this.entryComparator = Helpers.entryComparator(emptyMap.comparator());
462 
463       // derive values for inclusive filtering from the input samples
464       SampleElements<Entry<K, V>> samples = delegate.samples();
465       @SuppressWarnings("unchecked") // no elements are inserted into the array
466       List<Entry<K, V>> samplesList =
467           Arrays.asList(samples.e0(), samples.e1(), samples.e2(), samples.e3(), samples.e4());
468       Collections.sort(samplesList, entryComparator);
469       this.firstInclusive = samplesList.get(0).getKey();
470       this.lastInclusive = samplesList.get(samplesList.size() - 1).getKey();
471     }
472 
473     @Override
create(Object... entries)474     public SortedMap<K, V> create(Object... entries) {
475       List<Entry<K, V>> extremeValues = new ArrayList<>();
476 
477       // prepare extreme values to be filtered out of view
478       K firstExclusive = getInnerGenerator().belowSamplesGreater().getKey();
479       K lastExclusive = getInnerGenerator().aboveSamplesLesser().getKey();
480       if (from != Bound.NO_BOUND) {
481         extremeValues.add(getInnerGenerator().belowSamplesLesser());
482         extremeValues.add(getInnerGenerator().belowSamplesGreater());
483       }
484       if (to != Bound.NO_BOUND) {
485         extremeValues.add(getInnerGenerator().aboveSamplesLesser());
486         extremeValues.add(getInnerGenerator().aboveSamplesGreater());
487       }
488 
489       // the regular values should be visible after filtering
490       List<Entry<?, ?>> allEntries = new ArrayList<>();
491       allEntries.addAll(extremeValues);
492       for (Object entry : entries) {
493         allEntries.add((Entry<?, ?>) entry);
494       }
495       SortedMap<K, V> map = (SortedMap<K, V>) delegate.create(allEntries.toArray());
496 
497       return createSubMap(map, firstExclusive, lastExclusive);
498     }
499 
500     /**
501      * Calls the smallest subMap overload that filters out the extreme values. This method is
502      * overridden in NavigableMapTestSuiteBuilder.
503      */
createSubMap(SortedMap<K, V> map, K firstExclusive, K lastExclusive)504     SortedMap<K, V> createSubMap(SortedMap<K, V> map, K firstExclusive, K lastExclusive) {
505       if (from == Bound.NO_BOUND && to == Bound.EXCLUSIVE) {
506         return map.headMap(lastExclusive);
507       } else if (from == Bound.INCLUSIVE && to == Bound.NO_BOUND) {
508         return map.tailMap(firstInclusive);
509       } else if (from == Bound.INCLUSIVE && to == Bound.EXCLUSIVE) {
510         return map.subMap(firstInclusive, lastExclusive);
511       } else {
512         throw new IllegalArgumentException();
513       }
514     }
515 
getTo()516     public final Bound getTo() {
517       return to;
518     }
519 
getFrom()520     public final Bound getFrom() {
521       return from;
522     }
523 
getInnerGenerator()524     public final TestSortedMapGenerator<K, V> getInnerGenerator() {
525       return (TestSortedMapGenerator<K, V>) delegate;
526     }
527 
528     @Override
belowSamplesLesser()529     public Entry<K, V> belowSamplesLesser() {
530       // should never reach here!
531       throw new UnsupportedOperationException();
532     }
533 
534     @Override
belowSamplesGreater()535     public Entry<K, V> belowSamplesGreater() {
536       // should never reach here!
537       throw new UnsupportedOperationException();
538     }
539 
540     @Override
aboveSamplesLesser()541     public Entry<K, V> aboveSamplesLesser() {
542       // should never reach here!
543       throw new UnsupportedOperationException();
544     }
545 
546     @Override
aboveSamplesGreater()547     public Entry<K, V> aboveSamplesGreater() {
548       // should never reach here!
549       throw new UnsupportedOperationException();
550     }
551   }
552 
DerivedCollectionGenerators()553   private DerivedCollectionGenerators() {}
554 }
555