• 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 com.google.common.collect.testing.features.CollectionFeature;
20 import com.google.common.collect.testing.features.CollectionSize;
21 import com.google.common.collect.testing.features.Feature;
22 import com.google.common.collect.testing.features.MapFeature;
23 import com.google.common.collect.testing.testers.MapClearTester;
24 import com.google.common.collect.testing.testers.MapContainsKeyTester;
25 import com.google.common.collect.testing.testers.MapContainsValueTester;
26 import com.google.common.collect.testing.testers.MapCreationTester;
27 import com.google.common.collect.testing.testers.MapEqualsTester;
28 import com.google.common.collect.testing.testers.MapGetTester;
29 import com.google.common.collect.testing.testers.MapHashCodeTester;
30 import com.google.common.collect.testing.testers.MapIsEmptyTester;
31 import com.google.common.collect.testing.testers.MapPutAllTester;
32 import com.google.common.collect.testing.testers.MapPutTester;
33 import com.google.common.collect.testing.testers.MapRemoveTester;
34 import com.google.common.collect.testing.testers.MapSizeTester;
35 
36 import junit.framework.TestSuite;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Map.Entry;
45 import java.util.Set;
46 
47 /**
48  * Creates, based on your criteria, a JUnit test suite that exhaustively tests
49  * a Map implementation.
50  *
51  * @author George van den Driessche
52  */
53 public class MapTestSuiteBuilder<K, V>
54     extends PerCollectionSizeTestSuiteBuilder<
55         MapTestSuiteBuilder<K, V>,
56         TestMapGenerator<K, V>, Map<K, V>, Map.Entry<K, V>> {
using( TestMapGenerator<K, V> generator)57   public static <K, V> MapTestSuiteBuilder<K, V> using(
58       TestMapGenerator<K, V> generator) {
59     return new MapTestSuiteBuilder<K, V>().usingGenerator(generator);
60   }
61 
62   @SuppressWarnings("unchecked") // Class parameters must be raw.
getTesters()63   @Override protected List<Class<? extends AbstractTester>> getTesters() {
64     return Arrays.<Class<? extends AbstractTester>>asList(
65         MapClearTester.class,
66         MapContainsKeyTester.class,
67         MapContainsValueTester.class,
68         MapCreationTester.class,
69         MapEqualsTester.class,
70         MapGetTester.class,
71         MapHashCodeTester.class,
72         MapIsEmptyTester.class,
73         MapPutTester.class,
74         MapPutAllTester.class,
75         MapRemoveTester.class,
76         MapSizeTester.class
77     );
78   }
79 
createDerivedSuites( FeatureSpecificTestSuiteBuilder< ?, ? extends OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>> parentBuilder)80   @Override List<TestSuite> createDerivedSuites(
81       FeatureSpecificTestSuiteBuilder<
82           ?,
83           ? extends OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>>
84       parentBuilder) {
85     // TODO: Once invariant support is added, supply invariants to each of the
86     // derived suites, to check that mutations to the derived collections are
87     // reflected in the underlying map.
88 
89     List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder);
90 
91     derivedSuites.add(SetTestSuiteBuilder.using(
92             new MapEntrySetGenerator<K, V>(parentBuilder.getSubjectGenerator()))
93         .withFeatures(computeEntrySetFeatures(parentBuilder.getFeatures()))
94         .named(parentBuilder.getName() + " entrySet")
95         .suppressing(parentBuilder.getSuppressedTests())
96         .createTestSuite());
97 
98     derivedSuites.add(createDerivedKeySetSuite(
99             new MapKeySetGenerator<K, V>(parentBuilder.getSubjectGenerator()))
100         .withFeatures(computeKeySetFeatures(parentBuilder.getFeatures()))
101         .named(parentBuilder.getName() + " keys")
102         .suppressing(parentBuilder.getSuppressedTests())
103         .createTestSuite());
104 
105     derivedSuites.add(CollectionTestSuiteBuilder.using(
106             new MapValueCollectionGenerator<K, V>(
107                 parentBuilder.getSubjectGenerator()))
108         .named(parentBuilder.getName() + " values")
109         .withFeatures(computeValuesCollectionFeatures(
110             parentBuilder.getFeatures()))
111         .suppressing(parentBuilder.getSuppressedTests())
112         .createTestSuite());
113 
114     return derivedSuites;
115   }
116 
createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator)117   protected SetTestSuiteBuilder<K> createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator) {
118     return SetTestSuiteBuilder.using(keySetGenerator);
119   }
120 
computeEntrySetFeatures( Set<Feature<?>> mapFeatures)121   private static Set<Feature<?>> computeEntrySetFeatures(
122       Set<Feature<?>> mapFeatures) {
123     Set<Feature<?>> entrySetFeatures =
124         computeCommonDerivedCollectionFeatures(mapFeatures);
125     entrySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
126     return entrySetFeatures;
127   }
128 
computeKeySetFeatures( Set<Feature<?>> mapFeatures)129   private static Set<Feature<?>> computeKeySetFeatures(
130       Set<Feature<?>> mapFeatures) {
131     Set<Feature<?>> keySetFeatures =
132         computeCommonDerivedCollectionFeatures(mapFeatures);
133 
134     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_KEYS)) {
135       keySetFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES);
136     } else if (mapFeatures.contains(MapFeature.ALLOWS_NULL_QUERIES)) {
137       keySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
138     }
139 
140     return keySetFeatures;
141   }
142 
computeValuesCollectionFeatures( Set<Feature<?>> mapFeatures)143   private static Set<Feature<?>> computeValuesCollectionFeatures(
144       Set<Feature<?>> mapFeatures) {
145     Set<Feature<?>> valuesCollectionFeatures =
146         computeCommonDerivedCollectionFeatures(mapFeatures);
147     valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES);
148 
149     if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) {
150       valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES);
151     }
152 
153     return valuesCollectionFeatures;
154   }
155 
computeCommonDerivedCollectionFeatures( Set<Feature<?>> mapFeatures)156   private static Set<Feature<?>> computeCommonDerivedCollectionFeatures(
157       Set<Feature<?>> mapFeatures) {
158     Set<Feature<?>> derivedFeatures = new HashSet<Feature<?>>();
159     if (mapFeatures.contains(MapFeature.SUPPORTS_REMOVE)) {
160       derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE);
161       derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE_ALL);
162       derivedFeatures.add(CollectionFeature.SUPPORTS_RETAIN_ALL);
163     }
164     if (mapFeatures.contains(MapFeature.SUPPORTS_CLEAR)) {
165       derivedFeatures.add(CollectionFeature.SUPPORTS_CLEAR);
166     }
167     if (mapFeatures.contains(MapFeature.REJECTS_DUPLICATES_AT_CREATION)) {
168       derivedFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION);
169     }
170     // add the intersection of CollectionSize.values() and mapFeatures
171     for (CollectionSize size : CollectionSize.values()) {
172       if (mapFeatures.contains(size)) {
173         derivedFeatures.add(size);
174       }
175     }
176     return derivedFeatures;
177   }
178 
179   private static class MapEntrySetGenerator<K, V>
180       implements TestSetGenerator<Map.Entry<K, V>> {
181     private final OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>
182         mapGenerator;
183 
MapEntrySetGenerator( OneSizeTestContainerGenerator< Map<K, V>, Map.Entry<K, V>> mapGenerator)184     public MapEntrySetGenerator(
185         OneSizeTestContainerGenerator<
186             Map<K, V>, Map.Entry<K, V>> mapGenerator) {
187       this.mapGenerator = mapGenerator;
188     }
189 
190     @Override
samples()191     public SampleElements<Map.Entry<K, V>> samples() {
192       return mapGenerator.samples();
193     }
194 
195     @Override
create(Object... elements)196     public Set<Map.Entry<K, V>> create(Object... elements) {
197       return mapGenerator.create(elements).entrySet();
198     }
199 
200     @Override
createArray(int length)201     public Map.Entry<K, V>[] createArray(int length) {
202       return mapGenerator.createArray(length);
203     }
204 
205     @Override
order( List<Map.Entry<K, V>> insertionOrder)206     public Iterable<Map.Entry<K, V>> order(
207         List<Map.Entry<K, V>> insertionOrder) {
208       return mapGenerator.order(insertionOrder);
209     }
210   }
211 
212   // TODO: investigate some API changes to SampleElements that would tidy up
213   // parts of the following classes.
214 
215   private static class MapKeySetGenerator<K, V> implements TestSetGenerator<K> {
216     private final OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>
217         mapGenerator;
218     private final SampleElements<K> samples;
219 
MapKeySetGenerator( OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>> mapGenerator)220     public MapKeySetGenerator(
221         OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>
222             mapGenerator) {
223       this.mapGenerator = mapGenerator;
224       final SampleElements<Map.Entry<K, V>> mapSamples =
225           this.mapGenerator.samples();
226       this.samples = new SampleElements<K>(
227           mapSamples.e0.getKey(),
228           mapSamples.e1.getKey(),
229           mapSamples.e2.getKey(),
230           mapSamples.e3.getKey(),
231           mapSamples.e4.getKey());
232     }
233 
234     @Override
samples()235     public SampleElements<K> samples() {
236       return samples;
237     }
238 
239     @Override
create(Object... elements)240     public Set<K> create(Object... elements) {
241       @SuppressWarnings("unchecked")
242       K[] keysArray = (K[]) elements;
243 
244       // Start with a suitably shaped collection of entries
245       Collection<Map.Entry<K, V>> originalEntries =
246           mapGenerator.getSampleElements(elements.length);
247 
248       // Create a copy of that, with the desired value for each key
249       Collection<Map.Entry<K, V>> entries =
250           new ArrayList<Entry<K, V>>(elements.length);
251       int i = 0;
252       for (Map.Entry<K, V> entry : originalEntries) {
253         entries.add(Helpers.mapEntry(keysArray[i++], entry.getValue()));
254       }
255 
256       return mapGenerator.create(entries.toArray()).keySet();
257     }
258 
259     @Override
createArray(int length)260     public K[] createArray(int length) {
261       // TODO: with appropriate refactoring of OneSizeGenerator, we can perhaps
262       // tidy this up and get rid of the casts here and in
263       // MapValueCollectionGenerator.
264 
265       return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator())
266           .createKeyArray(length);
267     }
268 
269     @Override
order(List<K> insertionOrder)270     public Iterable<K> order(List<K> insertionOrder) {
271       return insertionOrder;
272     }
273   }
274 
275   private static class MapValueCollectionGenerator<K, V>
276       implements TestCollectionGenerator<V> {
277     private final OneSizeTestContainerGenerator<Map<K, V>, Map.Entry<K, V>>
278         mapGenerator;
279     private final SampleElements<V> samples;
280 
MapValueCollectionGenerator( OneSizeTestContainerGenerator< Map<K, V>, Map.Entry<K, V>> mapGenerator)281     public MapValueCollectionGenerator(
282         OneSizeTestContainerGenerator<
283             Map<K, V>, Map.Entry<K, V>> mapGenerator) {
284       this.mapGenerator = mapGenerator;
285       final SampleElements<Map.Entry<K, V>> mapSamples =
286           this.mapGenerator.samples();
287       this.samples = new SampleElements<V>(
288           mapSamples.e0.getValue(),
289           mapSamples.e1.getValue(),
290           mapSamples.e2.getValue(),
291           mapSamples.e3.getValue(),
292           mapSamples.e4.getValue());
293     }
294 
295     @Override
samples()296     public SampleElements<V> samples() {
297       return samples;
298     }
299 
300     @Override
create(Object... elements)301     public Collection<V> create(Object... elements) {
302       @SuppressWarnings("unchecked")
303       V[] valuesArray = (V[]) elements;
304 
305       // Start with a suitably shaped collection of entries
306       Collection<Map.Entry<K, V>> originalEntries =
307           mapGenerator.getSampleElements(elements.length);
308 
309       // Create a copy of that, with the desired value for each value
310       Collection<Map.Entry<K, V>> entries =
311           new ArrayList<Entry<K, V>>(elements.length);
312       int i = 0;
313       for (Map.Entry<K, V> entry : originalEntries) {
314         entries.add(Helpers.mapEntry(entry.getKey(), valuesArray[i++]));
315       }
316 
317       return mapGenerator.create(entries.toArray()).values();
318     }
319 
320     @Override
createArray(int length)321     public V[] createArray(int length) {
322       //noinspection UnnecessaryLocalVariable
323       final V[] vs = ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator())
324           .createValueArray(length);
325       return vs;
326     }
327 
328     @Override
order(List<V> insertionOrder)329     public Iterable<V> order(List<V> insertionOrder) {
330       return insertionOrder;
331     }
332   }
333 }
334