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