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