| /* |
| * Copyright (C) 2008 The Guava Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.common.collect.testing; |
| |
| import static com.google.common.collect.testing.DerivedCollectionGenerators.keySetGenerator; |
| |
| import com.google.common.annotations.GwtIncompatible; |
| import com.google.common.collect.testing.DerivedCollectionGenerators.MapEntrySetGenerator; |
| import com.google.common.collect.testing.DerivedCollectionGenerators.MapValueCollectionGenerator; |
| import com.google.common.collect.testing.features.CollectionFeature; |
| import com.google.common.collect.testing.features.CollectionSize; |
| import com.google.common.collect.testing.features.Feature; |
| import com.google.common.collect.testing.features.MapFeature; |
| import com.google.common.collect.testing.testers.MapClearTester; |
| import com.google.common.collect.testing.testers.MapComputeIfAbsentTester; |
| import com.google.common.collect.testing.testers.MapComputeIfPresentTester; |
| import com.google.common.collect.testing.testers.MapComputeTester; |
| import com.google.common.collect.testing.testers.MapContainsKeyTester; |
| import com.google.common.collect.testing.testers.MapContainsValueTester; |
| import com.google.common.collect.testing.testers.MapCreationTester; |
| import com.google.common.collect.testing.testers.MapEntrySetTester; |
| import com.google.common.collect.testing.testers.MapEqualsTester; |
| import com.google.common.collect.testing.testers.MapForEachTester; |
| import com.google.common.collect.testing.testers.MapGetOrDefaultTester; |
| import com.google.common.collect.testing.testers.MapGetTester; |
| import com.google.common.collect.testing.testers.MapHashCodeTester; |
| import com.google.common.collect.testing.testers.MapIsEmptyTester; |
| import com.google.common.collect.testing.testers.MapMergeTester; |
| import com.google.common.collect.testing.testers.MapPutAllTester; |
| import com.google.common.collect.testing.testers.MapPutIfAbsentTester; |
| import com.google.common.collect.testing.testers.MapPutTester; |
| import com.google.common.collect.testing.testers.MapRemoveEntryTester; |
| import com.google.common.collect.testing.testers.MapRemoveTester; |
| import com.google.common.collect.testing.testers.MapReplaceAllTester; |
| import com.google.common.collect.testing.testers.MapReplaceEntryTester; |
| import com.google.common.collect.testing.testers.MapReplaceTester; |
| import com.google.common.collect.testing.testers.MapSerializationTester; |
| import com.google.common.collect.testing.testers.MapSizeTester; |
| import com.google.common.collect.testing.testers.MapToStringTester; |
| import com.google.common.testing.SerializableTester; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| import junit.framework.TestSuite; |
| |
| /** |
| * Creates, based on your criteria, a JUnit test suite that exhaustively tests a Map implementation. |
| * |
| * @author George van den Driessche |
| */ |
| @GwtIncompatible |
| public class MapTestSuiteBuilder<K, V> |
| extends PerCollectionSizeTestSuiteBuilder< |
| MapTestSuiteBuilder<K, V>, TestMapGenerator<K, V>, Map<K, V>, Entry<K, V>> { |
| public static <K, V> MapTestSuiteBuilder<K, V> using(TestMapGenerator<K, V> generator) { |
| return new MapTestSuiteBuilder<K, V>().usingGenerator(generator); |
| } |
| |
| @SuppressWarnings("unchecked") // Class parameters must be raw. |
| @Override |
| protected List<Class<? extends AbstractTester>> getTesters() { |
| return Arrays.<Class<? extends AbstractTester>>asList( |
| MapClearTester.class, |
| MapComputeTester.class, |
| MapComputeIfAbsentTester.class, |
| MapComputeIfPresentTester.class, |
| MapContainsKeyTester.class, |
| MapContainsValueTester.class, |
| MapCreationTester.class, |
| MapEntrySetTester.class, |
| MapEqualsTester.class, |
| MapForEachTester.class, |
| MapGetTester.class, |
| MapGetOrDefaultTester.class, |
| MapHashCodeTester.class, |
| MapIsEmptyTester.class, |
| MapMergeTester.class, |
| MapPutTester.class, |
| MapPutAllTester.class, |
| MapPutIfAbsentTester.class, |
| MapRemoveTester.class, |
| MapRemoveEntryTester.class, |
| MapReplaceTester.class, |
| MapReplaceAllTester.class, |
| MapReplaceEntryTester.class, |
| MapSerializationTester.class, |
| MapSizeTester.class, |
| MapToStringTester.class); |
| } |
| |
| @Override |
| protected List<TestSuite> createDerivedSuites( |
| FeatureSpecificTestSuiteBuilder< |
| ?, ? extends OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>>> |
| parentBuilder) { |
| // TODO: Once invariant support is added, supply invariants to each of the |
| // derived suites, to check that mutations to the derived collections are |
| // reflected in the underlying map. |
| |
| List<TestSuite> derivedSuites = super.createDerivedSuites(parentBuilder); |
| |
| if (parentBuilder.getFeatures().contains(CollectionFeature.SERIALIZABLE)) { |
| derivedSuites.add( |
| MapTestSuiteBuilder.using( |
| new ReserializedMapGenerator<K, V>(parentBuilder.getSubjectGenerator())) |
| .withFeatures(computeReserializedMapFeatures(parentBuilder.getFeatures())) |
| .named(parentBuilder.getName() + " reserialized") |
| .suppressing(parentBuilder.getSuppressedTests()) |
| .createTestSuite()); |
| } |
| |
| derivedSuites.add( |
| createDerivedEntrySetSuite( |
| new MapEntrySetGenerator<K, V>(parentBuilder.getSubjectGenerator())) |
| .withFeatures(computeEntrySetFeatures(parentBuilder.getFeatures())) |
| .named(parentBuilder.getName() + " entrySet") |
| .suppressing(parentBuilder.getSuppressedTests()) |
| .createTestSuite()); |
| |
| derivedSuites.add( |
| createDerivedKeySetSuite(keySetGenerator(parentBuilder.getSubjectGenerator())) |
| .withFeatures(computeKeySetFeatures(parentBuilder.getFeatures())) |
| .named(parentBuilder.getName() + " keys") |
| .suppressing(parentBuilder.getSuppressedTests()) |
| .createTestSuite()); |
| |
| derivedSuites.add( |
| createDerivedValueCollectionSuite( |
| new MapValueCollectionGenerator<K, V>(parentBuilder.getSubjectGenerator())) |
| .named(parentBuilder.getName() + " values") |
| .withFeatures(computeValuesCollectionFeatures(parentBuilder.getFeatures())) |
| .suppressing(parentBuilder.getSuppressedTests()) |
| .createTestSuite()); |
| |
| return derivedSuites; |
| } |
| |
| protected SetTestSuiteBuilder<Entry<K, V>> createDerivedEntrySetSuite( |
| TestSetGenerator<Entry<K, V>> entrySetGenerator) { |
| return SetTestSuiteBuilder.using(entrySetGenerator); |
| } |
| |
| protected SetTestSuiteBuilder<K> createDerivedKeySetSuite(TestSetGenerator<K> keySetGenerator) { |
| return SetTestSuiteBuilder.using(keySetGenerator); |
| } |
| |
| protected CollectionTestSuiteBuilder<V> createDerivedValueCollectionSuite( |
| TestCollectionGenerator<V> valueCollectionGenerator) { |
| return CollectionTestSuiteBuilder.using(valueCollectionGenerator); |
| } |
| |
| private static Set<Feature<?>> computeReserializedMapFeatures(Set<Feature<?>> mapFeatures) { |
| Set<Feature<?>> derivedFeatures = Helpers.copyToSet(mapFeatures); |
| derivedFeatures.remove(CollectionFeature.SERIALIZABLE); |
| derivedFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS); |
| return derivedFeatures; |
| } |
| |
| private static Set<Feature<?>> computeEntrySetFeatures(Set<Feature<?>> mapFeatures) { |
| Set<Feature<?>> entrySetFeatures = computeCommonDerivedCollectionFeatures(mapFeatures); |
| if (mapFeatures.contains(MapFeature.ALLOWS_NULL_ENTRY_QUERIES)) { |
| entrySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES); |
| } |
| return entrySetFeatures; |
| } |
| |
| private static Set<Feature<?>> computeKeySetFeatures(Set<Feature<?>> mapFeatures) { |
| Set<Feature<?>> keySetFeatures = computeCommonDerivedCollectionFeatures(mapFeatures); |
| |
| // TODO(lowasser): make this trigger only if the map is a submap |
| // currently, the KeySetGenerator won't work properly for a subset of a keyset of a submap |
| keySetFeatures.add(CollectionFeature.SUBSET_VIEW); |
| if (mapFeatures.contains(MapFeature.ALLOWS_NULL_KEYS)) { |
| keySetFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES); |
| } else if (mapFeatures.contains(MapFeature.ALLOWS_NULL_KEY_QUERIES)) { |
| keySetFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES); |
| } |
| |
| return keySetFeatures; |
| } |
| |
| private static Set<Feature<?>> computeValuesCollectionFeatures(Set<Feature<?>> mapFeatures) { |
| Set<Feature<?>> valuesCollectionFeatures = computeCommonDerivedCollectionFeatures(mapFeatures); |
| if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUE_QUERIES)) { |
| valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES); |
| } |
| if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) { |
| valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES); |
| } |
| |
| return valuesCollectionFeatures; |
| } |
| |
| public static Set<Feature<?>> computeCommonDerivedCollectionFeatures( |
| Set<Feature<?>> mapFeatures) { |
| mapFeatures = new HashSet<>(mapFeatures); |
| Set<Feature<?>> derivedFeatures = new HashSet<>(); |
| mapFeatures.remove(CollectionFeature.SERIALIZABLE); |
| if (mapFeatures.remove(CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)) { |
| derivedFeatures.add(CollectionFeature.SERIALIZABLE); |
| } |
| if (mapFeatures.contains(MapFeature.SUPPORTS_REMOVE)) { |
| derivedFeatures.add(CollectionFeature.SUPPORTS_REMOVE); |
| } |
| if (mapFeatures.contains(MapFeature.REJECTS_DUPLICATES_AT_CREATION)) { |
| derivedFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION); |
| } |
| if (mapFeatures.contains(MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION)) { |
| derivedFeatures.add(CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION); |
| } |
| // add the intersection of CollectionFeature.values() and mapFeatures |
| for (CollectionFeature feature : CollectionFeature.values()) { |
| if (mapFeatures.contains(feature)) { |
| derivedFeatures.add(feature); |
| } |
| } |
| // add the intersection of CollectionSize.values() and mapFeatures |
| for (CollectionSize size : CollectionSize.values()) { |
| if (mapFeatures.contains(size)) { |
| derivedFeatures.add(size); |
| } |
| } |
| return derivedFeatures; |
| } |
| |
| private static class ReserializedMapGenerator<K, V> implements TestMapGenerator<K, V> { |
| private final OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator; |
| |
| public ReserializedMapGenerator( |
| OneSizeTestContainerGenerator<Map<K, V>, Entry<K, V>> mapGenerator) { |
| this.mapGenerator = mapGenerator; |
| } |
| |
| @Override |
| public SampleElements<Entry<K, V>> samples() { |
| return mapGenerator.samples(); |
| } |
| |
| @Override |
| public Entry<K, V>[] createArray(int length) { |
| return mapGenerator.createArray(length); |
| } |
| |
| @Override |
| public Iterable<Entry<K, V>> order(List<Entry<K, V>> insertionOrder) { |
| return mapGenerator.order(insertionOrder); |
| } |
| |
| @Override |
| public Map<K, V> create(Object... elements) { |
| return SerializableTester.reserialize(mapGenerator.create(elements)); |
| } |
| |
| @Override |
| public K[] createKeyArray(int length) { |
| return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createKeyArray(length); |
| } |
| |
| @Override |
| public V[] createValueArray(int length) { |
| return ((TestMapGenerator<K, V>) mapGenerator.getInnerGenerator()).createValueArray(length); |
| } |
| } |
| } |