Java
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@Override56public SampleElements<Entry<K, V>> samples() {57return mapGenerator.samples();58}59
60@Override61public Set<Entry<K, V>> create(Object... elements) {62return mapGenerator.create(elements).entrySet();63}64
65@Override66public Entry<K, V>[] createArray(int length) {67return mapGenerator.createArray(length);68}69
70@Override71public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {72return mapGenerator.order(insertionOrder);73}74
75@Override76public OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> getInnerGenerator() {77return mapGenerator;78}79}80
81// TODO: investigate some API changes to SampleElements that would tidy up82// 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 TestSortedMapGenerator89&& ((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@Override114public SampleElements<K> samples() {115return samples;116}117
118@Override119public Set<K> create(Object... elements) {120@SuppressWarnings("unchecked")121K[] keysArray = (K[]) elements;122
123// Start with a suitably shaped collection of entries124Collection<Entry<K, V>> originalEntries = mapGenerator.getSampleElements(elements.length);125
126// Create a copy of that, with the desired value for each key127Collection<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@Override137public K[] createArray(int length) {138// TODO: with appropriate refactoring of OneSizeGenerator, we can perhaps139// tidy this up and get rid of the casts here and in140// MapValueCollectionGenerator.141
142return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createKeyArray(length);143}144
145@Override146public 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@Override161public 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@Override178public SortedSet<K> create(Object... elements) {179return (SortedSet<K>) super.create(elements);180}181
182@Override183public K belowSamplesLesser() {184return delegate.belowSamplesLesser().getKey();185}186
187@Override188public K belowSamplesGreater() {189return delegate.belowSamplesGreater().getKey();190}191
192@Override193public K aboveSamplesLesser() {194return delegate.aboveSamplesLesser().getKey();195}196
197@Override198public 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@Override223public SampleElements<V> samples() {224return samples;225}226
227@Override228public Collection<V> create(Object... elements) {229@SuppressWarnings("unchecked")230V[] valuesArray = (V[]) elements;231
232// Start with a suitably shaped collection of entries233Collection<Entry<K, V>> originalEntries = mapGenerator.getSampleElements(elements.length);234
235// Create a copy of that, with the desired value for each value236Collection<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@Override246public V[] createArray(int length) {247// noinspection UnnecessaryLocalVariable248V[] vs = ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createValueArray(length);249return vs;250}251
252@Override253public Iterable<V> order(List<V> insertionOrder) {254List<Entry<K, V>> orderedEntries =255castOrCopyToList(mapGenerator.order(castOrCopyToList(mapGenerator.getSampleElements(5))));256sort(257insertionOrder,258new Comparator<V>() {259@Override260public 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@Override279public 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@Override294public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {295return delegate.order(insertionOrder);296}297
298@Override299public K[] createKeyArray(int length) {300return delegate.createKeyArray(length);301}302
303@Override304public V[] createValueArray(int length) {305return delegate.createValueArray(length);306}307
308@Override309public SampleElements<Entry<K, V>> samples() {310return delegate.samples();311}312
313@Override314public Map<K, V> create(Object... elements) {315return delegate.create(elements);316}317
318@Override319public 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@Override369public SampleElements<E> samples() {370return delegate.samples();371}372
373@Override374public E[] createArray(int length) {375return delegate.createArray(length);376}377
378@Override379public Iterable<E> order(List<E> insertionOrder) {380return delegate.order(insertionOrder);381}382
383@Override384public 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 altogether389for (Object o : elements) {390if (o == null) {391throw new NullPointerException();392}393}394
395// prepare extreme values to be filtered out of view396E 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 filtering408List<@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@Override430public E belowSamplesLesser() {431throw new UnsupportedOperationException();432}433
434@Override435public E belowSamplesGreater() {436throw new UnsupportedOperationException();437}438
439@Override440public E aboveSamplesLesser() {441throw new UnsupportedOperationException();442}443
444@Override445public 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 samples473SampleElements<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@Override482public SortedMap<K, V> create(Object... entries) {483List<Entry<K, V>> extremeValues = new ArrayList<>();484
485// prepare extreme values to be filtered out of view486K 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 filtering498List<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@Override537public Entry<K, V> belowSamplesLesser() {538// should never reach here!539throw new UnsupportedOperationException();540}541
542@Override543public Entry<K, V> belowSamplesGreater() {544// should never reach here!545throw new UnsupportedOperationException();546}547
548@Override549public Entry<K, V> aboveSamplesLesser() {550// should never reach here!551throw new UnsupportedOperationException();552}553
554@Override555public Entry<K, V> aboveSamplesGreater() {556// should never reach here!557throw new UnsupportedOperationException();558}559}560
561private DerivedCollectionGenerators() {}562}
563