• 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.DerivedCollectionGenerators.keySetGenerator;
20 
21 import com.google.common.annotations.GwtIncompatible;
22 import com.google.common.collect.testing.DerivedCollectionGenerators.MapEntrySetGenerator;
23 import com.google.common.collect.testing.DerivedCollectionGenerators.MapValueCollectionGenerator;
24 import com.google.common.collect.testing.features.CollectionFeature;
25 import com.google.common.collect.testing.features.CollectionSize;
26 import com.google.common.collect.testing.features.Feature;
27 import com.google.common.collect.testing.features.MapFeature;
28 import com.google.common.collect.testing.testers.MapClearTester;
29 import com.google.common.collect.testing.testers.MapContainsKeyTester;
30 import com.google.common.collect.testing.testers.MapContainsValueTester;
31 import com.google.common.collect.testing.testers.MapCreationTester;
32 import com.google.common.collect.testing.testers.MapEntrySetTester;
33 import com.google.common.collect.testing.testers.MapEqualsTester;
34 import com.google.common.collect.testing.testers.MapGetTester;
35 import com.google.common.collect.testing.testers.MapHashCodeTester;
36 import com.google.common.collect.testing.testers.MapIsEmptyTester;
37 import com.google.common.collect.testing.testers.MapPutAllTester;
38 import com.google.common.collect.testing.testers.MapPutTester;
39 import com.google.common.collect.testing.testers.MapRemoveTester;
40 import com.google.common.collect.testing.testers.MapSerializationTester;
41 import com.google.common.collect.testing.testers.MapSizeTester;
42 import com.google.common.collect.testing.testers.MapToStringTester;
43 import com.google.common.testing.SerializableTester;
44 import java.util.Arrays;
45 import java.util.HashSet;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Map.Entry;
49 import java.util.Set;
50 import junit.framework.TestSuite;
51 
52 /**
53  * Creates, based on your criteria, a JUnit test suite that exhaustively tests a Map implementation.
54  *
55  * @author George van den Driessche
56  */
57 @GwtIncompatible
58 public class MapTestSuiteBuilder<K, V>
59     extends PerCollectionSizeTestSuiteBuilder<
60         MapTestSuiteBuilder<K, V>, TestMapGenerator<K, V>, Map<K, V>, Entry<K, V>> {
using(TestMapGenerator<K, V> generator)61   public static <K, V> MapTestSuiteBuilder<K, V> using(TestMapGenerator<K, V> generator) {
62     return new MapTestSuiteBuilder<K, V>().usingGenerator(generator);
63   }
64 
65   @SuppressWarnings("unchecked") // Class parameters must be raw.
66   @Override
getTesters()67   protected List<Class<? extends AbstractTester>> getTesters() {
68     return Arrays.<Class<? extends AbstractTester>>asList(
69         MapClearTester.class,
70         MapContainsKeyTester.class,
71         MapContainsValueTester.class,
72         MapCreationTester.class,
73         MapEntrySetTester.class,
74         MapEqualsTester.class,
75         MapGetTester.class,
76         MapHashCodeTester.class,
77         MapIsEmptyTester.class,
78         MapPutTester.class,
79         MapPutAllTester.class,
80         MapRemoveTester.class,
81         MapSerializationTester.class,
82         MapSizeTester.class,
83         MapToStringTester.class);
84   }
85 
86   @Override
createDerivedSuites( FeatureSpecificTestSuiteBuilder< ?, ? extends OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>>> parentBuilder)87   protected List<TestSuite> createDerivedSuites(
88       FeatureSpecificTestSuiteBuilder<
89               ?, ? extends OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>>>
90           parentBuilder) {
91     // TODO: Once invariant support is added, supply invariants to each of the
92     // derived suites, to check that mutations to the derived collections are
93     // reflected in the underlying map.
94 
95     List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder);
96 
97     if (parentBuilder.getFeatures().contains(CollectionFeature.SERIALIZABLE)) {
98       derivedSuites.add(
99           MapTestSuiteBuilder.using(
100                   new ReserializedMapGenerator<K, V>(parentBuilder.getSubjectGenerator()))
101               .withFeatures(computeReserializedMapFeatures(parentBuilder.getFeatures()))
102               .named(parentBuilder.getName() + " reserialized")
103               .suppressing(parentBuilder.getSuppressedTests())
104               .withSetUp(parentBuilder.getSetUp())
105               .withTearDown(parentBuilder.getTearDown())
106               .createTestSuite());
107     }
108 
109     derivedSuites.add(
110         createDerivedEntrySetSuite(
111                 new MapEntrySetGenerator<K, V>(parentBuilder.getSubjectGenerator()))
112             .withFeatures(computeEntrySetFeatures(parentBuilder.getFeatures()))
113             .named(parentBuilder.getName() + " entrySet")
114             .suppressing(parentBuilder.getSuppressedTests())
115             .withSetUp(parentBuilder.getSetUp())
116             .withTearDown(parentBuilder.getTearDown())
117             .createTestSuite());
118 
119     derivedSuites.add(
120         createDerivedKeySetSuite(keySetGenerator(parentBuilder.getSubjectGenerator()))
121             .withFeatures(computeKeySetFeatures(parentBuilder.getFeatures()))
122             .named(parentBuilder.getName() + " keys")
123             .suppressing(parentBuilder.getSuppressedTests())
124             .withSetUp(parentBuilder.getSetUp())
125             .withTearDown(parentBuilder.getTearDown())
126             .createTestSuite());
127 
128     derivedSuites.add(
129         createDerivedValueCollectionSuite(
130                 new MapValueCollectionGenerator<K, V>(parentBuilder.getSubjectGenerator()))
131             .named(parentBuilder.getName() + " values")
132             .withFeatures(computeValuesCollectionFeatures(parentBuilder.getFeatures()))
133             .suppressing(parentBuilder.getSuppressedTests())
134             .withSetUp(parentBuilder.getSetUp())
135             .withTearDown(parentBuilder.getTearDown())
136             .createTestSuite());
137 
138     return derivedSuites;
139   }
140 
createDerivedEntrySetSuite( TestSetGenerator<Entry<K, V>> entrySetGenerator)141   protected SetTestSuiteBuilder<Entry<K, V>> createDerivedEntrySetSuite(
142       TestSetGenerator<Entry<K, V>> entrySetGenerator) {
143     return SetTestSuiteBuilder.using(entrySetGenerator);
144   }
145 
createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator)146   protected SetTestSuiteBuilder<K> createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator) {
147     return SetTestSuiteBuilder.using(keySetGenerator);
148   }
149 
createDerivedValueCollectionSuite( TestCollectionGenerator<V> valueCollectionGenerator)150   protected CollectionTestSuiteBuilder<V> createDerivedValueCollectionSuite(
151       TestCollectionGenerator<V> valueCollectionGenerator) {
152     return CollectionTestSuiteBuilder.using(valueCollectionGenerator);
153   }
154 
computeReserializedMapFeatures(Set<Feature<?>> mapFeatures)155   private static Set<Feature<?>> computeReserializedMapFeatures(Set<Feature<?>> mapFeatures) {
156     Set<Feature<?>> derivedFeatures = Helpers.copyToSet(mapFeatures);
157     derivedFeatures.remove(CollectionFeature.SERIALIZABLE);
158     derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS);
159     return derivedFeatures;
160   }
161 
computeEntrySetFeatures(Set<Feature<?>> mapFeatures)162   private static Set<Feature<?>> computeEntrySetFeatures(Set<Feature<?>> mapFeatures) {
163     Set<Feature<?>> entrySetFeatures = computeCommonDerivedCollectionFeatures(mapFeatures);
164     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_ENTRY_QUERIES)) {
165       entrySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
166     }
167     return entrySetFeatures;
168   }
169 
computeKeySetFeatures(Set<Feature<?>> mapFeatures)170   private static Set<Feature<?>> computeKeySetFeatures(Set<Feature<?>> mapFeatures) {
171     Set<Feature<?>> keySetFeatures = computeCommonDerivedCollectionFeatures(mapFeatures);
172 
173     // TODO(lowasser): make this trigger only if the map is a submap
174     // currently, the KeySetGenerator won't work properly for a subset of a keyset of a submap
175     keySetFeatures.add(CollectionFeature.SUBSET_VIEW);
176     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_KEYS)) {
177       keySetFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES);
178     } else if (mapFeatures.contains(MapFeature.ALLOWS_NULL_KEY_QUERIES)) {
179       keySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
180     }
181 
182     return keySetFeatures;
183   }
184 
computeValuesCollectionFeatures(Set<Feature<?>> mapFeatures)185   private static Set<Feature<?>> computeValuesCollectionFeatures(Set<Feature<?>> mapFeatures) {
186     Set<Feature<?>> valuesCollectionFeatures = computeCommonDerivedCollectionFeatures(mapFeatures);
187     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUE_QUERIES)) {
188       valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
189     }
190     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) {
191       valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES);
192     }
193 
194     return valuesCollectionFeatures;
195   }
196 
computeCommonDerivedCollectionFeatures( Set<Feature<?>> mapFeatures)197   public static Set<Feature<?>> computeCommonDerivedCollectionFeatures(
198       Set<Feature<?>> mapFeatures) {
199     mapFeatures = new HashSet<>(mapFeatures);
200     Set<Feature<?>> derivedFeatures = new HashSet<>();
201     mapFeatures.remove(CollectionFeature.SERIALIZABLE);
202     if (mapFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) {
203       derivedFeatures.add(CollectionFeature.SERIALIZABLE);
204     }
205     if (mapFeatures.contains(MapFeature.SUPPORTS_REMOVE)) {
206       derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE);
207     }
208     if (mapFeatures.contains(MapFeature.REJECTS_DUPLICATES_AT_CREATION)) {
209       derivedFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION);
210     }
211     if (mapFeatures.contains(MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION)) {
212       derivedFeatures.add(CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION);
213     }
214     // add the intersection of CollectionFeature.values() and mapFeatures
215     for (CollectionFeature feature : CollectionFeature.values()) {
216       if (mapFeatures.contains(feature)) {
217         derivedFeatures.add(feature);
218       }
219     }
220     // add the intersection of CollectionSize.values() and mapFeatures
221     for (CollectionSize size : CollectionSize.values()) {
222       if (mapFeatures.contains(size)) {
223         derivedFeatures.add(size);
224       }
225     }
226     return derivedFeatures;
227   }
228 
229   private static class ReserializedMapGenerator<K, V> implements TestMapGenerator<K, V> {
230     private final OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator;
231 
ReserializedMapGenerator( OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator)232     public ReserializedMapGenerator(
233         OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) {
234       this.mapGenerator = mapGenerator;
235     }
236 
237     @Override
samples()238     public SampleElements<Entry<K, V>> samples() {
239       return mapGenerator.samples();
240     }
241 
242     @Override
createArray(int length)243     public Entry<K, V>[] createArray(int length) {
244       return mapGenerator.createArray(length);
245     }
246 
247     @Override
order(List<Entry<K, V>> insertionOrder)248     public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) {
249       return mapGenerator.order(insertionOrder);
250     }
251 
252     @Override
create(Object... elements)253     public Map<K, V> create(Object... elements) {
254       return SerializableTester.reserialize(mapGenerator.create(elements));
255     }
256 
257     @Override
createKeyArray(int length)258     public K[] createKeyArray(int length) {
259       return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createKeyArray(length);
260     }
261 
262     @Override
createValueArray(int length)263     public V[] createValueArray(int length) {
264       return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createValueArray(length);
265     }
266   }
267 }
268