001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect.testing.google; 018 019import static java.util.Collections.emptySet; 020 021import com.google.common.annotations.GwtIncompatible; 022import com.google.common.collect.BiMap; 023import com.google.common.collect.testing.AbstractTester; 024import com.google.common.collect.testing.FeatureSpecificTestSuiteBuilder; 025import com.google.common.collect.testing.MapTestSuiteBuilder; 026import com.google.common.collect.testing.OneSizeTestContainerGenerator; 027import com.google.common.collect.testing.PerCollectionSizeTestSuiteBuilder; 028import com.google.common.collect.testing.SetTestSuiteBuilder; 029import com.google.common.collect.testing.features.CollectionFeature; 030import com.google.common.collect.testing.features.Feature; 031import com.google.common.collect.testing.features.MapFeature; 032import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.BiMapValueSetGenerator; 033import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.InverseBiMapGenerator; 034import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.MapGenerator; 035import com.google.common.collect.testing.testers.SetCreationTester; 036import java.util.ArrayList; 037import java.util.HashSet; 038import java.util.List; 039import java.util.Map.Entry; 040import java.util.Set; 041import junit.framework.TestSuite; 042 043/** 044 * Creates, based on your criteria, a JUnit test suite that exhaustively tests a {@code BiMap} 045 * implementation. 046 * 047 * @author Louis Wasserman 048 */ 049@GwtIncompatible 050public class BiMapTestSuiteBuilder<K, V> 051 extends PerCollectionSizeTestSuiteBuilder< 052 BiMapTestSuiteBuilder<K, V>, TestBiMapGenerator<K, V>, BiMap<K, V>, Entry<K, V>> { 053 public static <K, V> BiMapTestSuiteBuilder<K, V> using(TestBiMapGenerator<K, V> generator) { 054 return new BiMapTestSuiteBuilder<K, V>().usingGenerator(generator); 055 } 056 057 @SuppressWarnings("rawtypes") // class literals 058 @Override 059 protected List<Class<? extends AbstractTester>> getTesters() { 060 List<Class<? extends AbstractTester>> testers = new ArrayList<>(); 061 testers.add(BiMapEntrySetTester.class); 062 testers.add(BiMapPutTester.class); 063 testers.add(BiMapInverseTester.class); 064 testers.add(BiMapRemoveTester.class); 065 testers.add(BiMapClearTester.class); 066 return testers; 067 } 068 069 enum NoRecurse implements Feature<Void> { 070 INVERSE; 071 072 @Override 073 public Set<Feature<? super Void>> getImpliedFeatures() { 074 return emptySet(); 075 } 076 } 077 078 @Override 079 protected List<TestSuite> createDerivedSuites( 080 FeatureSpecificTestSuiteBuilder< 081 ?, ? extends OneSizeTestContainerGenerator<BiMap<K, V>, Entry<K, V>>> 082 parentBuilder) { 083 List<TestSuite> derived = super.createDerivedSuites(parentBuilder); 084 // TODO(cpovirk): consider using this approach (derived suites instead of extension) in 085 // ListTestSuiteBuilder, etc.? 086 derived.add( 087 MapTestSuiteBuilder.using(new MapGenerator<K, V>(parentBuilder.getSubjectGenerator())) 088 .withFeatures(parentBuilder.getFeatures()) 089 .named(parentBuilder.getName() + " [Map]") 090 .suppressing(parentBuilder.getSuppressedTests()) 091 .suppressing(SetCreationTester.class.getMethods()) 092 // BiMap.entrySet() duplicate-handling behavior is too confusing for SetCreationTester 093 .withSetUp(parentBuilder.getSetUp()) 094 .withTearDown(parentBuilder.getTearDown()) 095 .createTestSuite()); 096 /* 097 * TODO(cpovirk): the Map tests duplicate most of this effort by using a 098 * CollectionTestSuiteBuilder on values(). It would be nice to avoid that 099 */ 100 derived.add( 101 SetTestSuiteBuilder.using( 102 new BiMapValueSetGenerator<K, V>(parentBuilder.getSubjectGenerator())) 103 .withFeatures(computeValuesSetFeatures(parentBuilder.getFeatures())) 104 .named(parentBuilder.getName() + " values [Set]") 105 .suppressing(parentBuilder.getSuppressedTests()) 106 .suppressing(SetCreationTester.class.getMethods()) 107 // BiMap.values() duplicate-handling behavior is too confusing for SetCreationTester 108 .withSetUp(parentBuilder.getSetUp()) 109 .withTearDown(parentBuilder.getTearDown()) 110 .createTestSuite()); 111 if (!parentBuilder.getFeatures().contains(NoRecurse.INVERSE)) { 112 derived.add( 113 BiMapTestSuiteBuilder.using( 114 new InverseBiMapGenerator<K, V>(parentBuilder.getSubjectGenerator())) 115 .withFeatures(computeInverseFeatures(parentBuilder.getFeatures())) 116 .named(parentBuilder.getName() + " inverse") 117 .suppressing(parentBuilder.getSuppressedTests()) 118 .withSetUp(parentBuilder.getSetUp()) 119 .withTearDown(parentBuilder.getTearDown()) 120 .createTestSuite()); 121 } 122 123 return derived; 124 } 125 126 private static Set<Feature<?>> computeInverseFeatures(Set<Feature<?>> mapFeatures) { 127 Set<Feature<?>> inverseFeatures = new HashSet<>(mapFeatures); 128 129 boolean nullKeys = inverseFeatures.remove(MapFeature.ALLOWS_NULL_KEYS); 130 boolean nullValues = inverseFeatures.remove(MapFeature.ALLOWS_NULL_VALUES); 131 132 if (nullKeys) { 133 inverseFeatures.add(MapFeature.ALLOWS_NULL_VALUES); 134 } 135 if (nullValues) { 136 inverseFeatures.add(MapFeature.ALLOWS_NULL_KEYS); 137 } 138 139 inverseFeatures.add(NoRecurse.INVERSE); 140 inverseFeatures.remove(CollectionFeature.KNOWN_ORDER); 141 inverseFeatures.add(MapFeature.REJECTS_DUPLICATES_AT_CREATION); 142 143 return inverseFeatures; 144 } 145 146 // TODO(lowasser): can we eliminate the duplication from MapTestSuiteBuilder here? 147 148 private static Set<Feature<?>> computeValuesSetFeatures(Set<Feature<?>> mapFeatures) { 149 Set<Feature<?>> valuesCollectionFeatures = computeCommonDerivedCollectionFeatures(mapFeatures); 150 valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES); 151 152 if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) { 153 valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES); 154 } 155 156 valuesCollectionFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION); 157 158 return valuesCollectionFeatures; 159 } 160 161 private static Set<Feature<?>> computeCommonDerivedCollectionFeatures( 162 Set<Feature<?>> mapFeatures) { 163 return MapTestSuiteBuilder.computeCommonDerivedCollectionFeatures(mapFeatures); 164 } 165}