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 com.google.common.annotations.GwtIncompatible; 020import com.google.common.collect.BiMap; 021import com.google.common.collect.testing.AbstractTester; 022import com.google.common.collect.testing.FeatureSpecificTestSuiteBuilder; 023import com.google.common.collect.testing.MapTestSuiteBuilder; 024import com.google.common.collect.testing.OneSizeTestContainerGenerator; 025import com.google.common.collect.testing.PerCollectionSizeTestSuiteBuilder; 026import com.google.common.collect.testing.SetTestSuiteBuilder; 027import com.google.common.collect.testing.features.CollectionFeature; 028import com.google.common.collect.testing.features.Feature; 029import com.google.common.collect.testing.features.MapFeature; 030import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.BiMapValueSetGenerator; 031import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.InverseBiMapGenerator; 032import com.google.common.collect.testing.google.DerivedGoogleCollectionGenerators.MapGenerator; 033import com.google.common.collect.testing.testers.SetCreationTester; 034import java.util.ArrayList; 035import java.util.Collections; 036import java.util.HashSet; 037import java.util.List; 038import java.util.Map.Entry; 039import java.util.Set; 040import junit.framework.TestSuite; 041 042/** 043 * Creates, based on your criteria, a JUnit test suite that exhaustively tests a {@code BiMap} 044 * implementation. 045 * 046 * @author Louis Wasserman 047 */ 048@GwtIncompatible 049public class BiMapTestSuiteBuilder<K, V> 050 extends PerCollectionSizeTestSuiteBuilder< 051 BiMapTestSuiteBuilder<K, V>, TestBiMapGenerator<K, V>, BiMap<K, V>, Entry<K, V>> { 052 public static <K, V> BiMapTestSuiteBuilder<K, V> using(TestBiMapGenerator<K, V> generator) { 053 return new BiMapTestSuiteBuilder<K, V>().usingGenerator(generator); 054 } 055 056 @SuppressWarnings("rawtypes") // class literals 057 @Override 058 protected List<Class<? extends AbstractTester>> getTesters() { 059 List<Class<? extends AbstractTester>> testers = new ArrayList<>(); 060 testers.add(BiMapEntrySetTester.class); 061 testers.add(BiMapPutTester.class); 062 testers.add(BiMapInverseTester.class); 063 testers.add(BiMapRemoveTester.class); 064 testers.add(BiMapClearTester.class); 065 return testers; 066 } 067 068 enum NoRecurse implements Feature<Void> { 069 INVERSE; 070 071 @Override 072 public Set<Feature<? super Void>> getImpliedFeatures() { 073 return Collections.emptySet(); 074 } 075 } 076 077 @Override 078 protected List<TestSuite> createDerivedSuites( 079 FeatureSpecificTestSuiteBuilder< 080 ?, ? extends OneSizeTestContainerGenerator<BiMap<K, V>, Entry<K, V>>> 081 parentBuilder) { 082 List<TestSuite> derived = super.createDerivedSuites(parentBuilder); 083 // TODO(cpovirk): consider using this approach (derived suites instead of extension) in 084 // ListTestSuiteBuilder, etc.? 085 derived.add( 086 MapTestSuiteBuilder.using(new MapGenerator<K, V>(parentBuilder.getSubjectGenerator())) 087 .withFeatures(parentBuilder.getFeatures()) 088 .named(parentBuilder.getName() + " [Map]") 089 .suppressing(parentBuilder.getSuppressedTests()) 090 .suppressing(SetCreationTester.class.getMethods()) 091 // BiMap.entrySet() duplicate-handling behavior is too confusing for SetCreationTester 092 .withSetUp(parentBuilder.getSetUp()) 093 .withTearDown(parentBuilder.getTearDown()) 094 .createTestSuite()); 095 /* 096 * TODO(cpovirk): the Map tests duplicate most of this effort by using a 097 * CollectionTestSuiteBuilder on values(). It would be nice to avoid that 098 */ 099 derived.add( 100 SetTestSuiteBuilder.using( 101 new BiMapValueSetGenerator<K, V>(parentBuilder.getSubjectGenerator())) 102 .withFeatures(computeValuesSetFeatures(parentBuilder.getFeatures())) 103 .named(parentBuilder.getName() + " values [Set]") 104 .suppressing(parentBuilder.getSuppressedTests()) 105 .suppressing(SetCreationTester.class.getMethods()) 106 // BiMap.values() duplicate-handling behavior is too confusing for SetCreationTester 107 .withSetUp(parentBuilder.getSetUp()) 108 .withTearDown(parentBuilder.getTearDown()) 109 .createTestSuite()); 110 if (!parentBuilder.getFeatures().contains(NoRecurse.INVERSE)) { 111 derived.add( 112 BiMapTestSuiteBuilder.using( 113 new InverseBiMapGenerator<K, V>(parentBuilder.getSubjectGenerator())) 114 .withFeatures(computeInverseFeatures(parentBuilder.getFeatures())) 115 .named(parentBuilder.getName() + " inverse") 116 .suppressing(parentBuilder.getSuppressedTests()) 117 .withSetUp(parentBuilder.getSetUp()) 118 .withTearDown(parentBuilder.getTearDown()) 119 .createTestSuite()); 120 } 121 122 return derived; 123 } 124 125 private static Set<Feature<?>> computeInverseFeatures(Set<Feature<?>> mapFeatures) { 126 Set<Feature<?>> inverseFeatures = new HashSet<>(mapFeatures); 127 128 boolean nullKeys = inverseFeatures.remove(MapFeature.ALLOWS_NULL_KEYS); 129 boolean nullValues = inverseFeatures.remove(MapFeature.ALLOWS_NULL_VALUES); 130 131 if (nullKeys) { 132 inverseFeatures.add(MapFeature.ALLOWS_NULL_VALUES); 133 } 134 if (nullValues) { 135 inverseFeatures.add(MapFeature.ALLOWS_NULL_KEYS); 136 } 137 138 inverseFeatures.add(NoRecurse.INVERSE); 139 inverseFeatures.remove(CollectionFeature.KNOWN_ORDER); 140 inverseFeatures.add(MapFeature.REJECTS_DUPLICATES_AT_CREATION); 141 142 return inverseFeatures; 143 } 144 145 // TODO(lowasser): can we eliminate the duplication from MapTestSuiteBuilder here? 146 147 private static Set<Feature<?>> computeValuesSetFeatures(Set<Feature<?>> mapFeatures) { 148 Set<Feature<?>> valuesCollectionFeatures = computeCommonDerivedCollectionFeatures(mapFeatures); 149 valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_QUERIES); 150 151 if (mapFeatures.contains(MapFeature.ALLOWS_NULL_VALUES)) { 152 valuesCollectionFeatures.add(CollectionFeature.ALLOWS_NULL_VALUES); 153 } 154 155 valuesCollectionFeatures.add(CollectionFeature.REJECTS_DUPLICATES_AT_CREATION); 156 157 return valuesCollectionFeatures; 158 } 159 160 private static Set<Feature<?>> computeCommonDerivedCollectionFeatures( 161 Set<Feature<?>> mapFeatures) { 162 return MapTestSuiteBuilder.computeCommonDerivedCollectionFeatures(mapFeatures); 163 } 164}