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