1/* 2 * Copyright (C) 2009 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 17package com.google.common.collect.testing; 18 19import com.google.common.collect.testing.features.CollectionFeature; 20import com.google.common.collect.testing.features.CollectionSize; 21import com.google.common.collect.testing.features.MapFeature; 22 23import junit.framework.Test; 24import junit.framework.TestSuite; 25 26import java.lang.reflect.Method; 27import java.util.Collection; 28import java.util.Collections; 29import java.util.Comparator; 30import java.util.EnumMap; 31import java.util.HashMap; 32import java.util.LinkedHashMap; 33import java.util.List; 34import java.util.Map; 35import java.util.Map.Entry; 36import java.util.TreeMap; 37import java.util.concurrent.ConcurrentHashMap; 38 39/** 40 * Generates a test suite covering the {@link Map} implementations in the 41 * {@link java.util} package. Can be subclassed to specify tests that should 42 * be suppressed. 43 * 44 * @author Kevin Bourrillion 45 */ 46public class TestsForMapsInJavaUtil { 47 public static Test suite() { 48 return new TestsForMapsInJavaUtil().allTests(); 49 } 50 51 public Test allTests() { 52 TestSuite suite = new TestSuite("java.util Maps"); 53 suite.addTest(testsForEmptyMap()); 54 suite.addTest(testsForSingletonMap()); 55 suite.addTest(testsForHashMap()); 56 suite.addTest(testsForLinkedHashMap()); 57 suite.addTest(testsForTreeMap()); 58 suite.addTest(testsForEnumMap()); 59 suite.addTest(testsForConcurrentHashMap()); 60 return suite; 61 } 62 63 protected Collection<Method> suppressForEmptyMap() { 64 return Collections.emptySet(); 65 } 66 protected Collection<Method> suppressForSingletonMap() { 67 return Collections.emptySet(); 68 } 69 protected Collection<Method> suppressForHashMap() { 70 return Collections.emptySet(); 71 } 72 protected Collection<Method> suppressForLinkedHashMap() { 73 return Collections.emptySet(); 74 } 75 protected Collection<Method> suppressForTreeMap() { 76 return Collections.emptySet(); 77 } 78 protected Collection<Method> suppressForEnumMap() { 79 return Collections.emptySet(); 80 } 81 protected Collection<Method> suppressForConcurrentHashMap() { 82 return Collections.emptySet(); 83 } 84 85 public Test testsForEmptyMap() { 86 return MapTestSuiteBuilder 87 .using(new TestStringMapGenerator() { 88 @Override protected Map<String, String> create( 89 Entry<String, String>[] entries) { 90 return Collections.emptyMap(); 91 } 92 }) 93 .named("emptyMap") 94 .withFeatures( 95 CollectionFeature.NONE, 96 CollectionSize.ZERO) 97 .suppressing(suppressForEmptyMap()) 98 .createTestSuite(); 99 } 100 101 public Test testsForSingletonMap() { 102 return MapTestSuiteBuilder 103 .using(new TestStringMapGenerator() { 104 @Override protected Map<String, String> create( 105 Entry<String, String>[] entries) { 106 return Collections.singletonMap( 107 entries[0].getKey(), entries[0].getValue()); 108 } 109 }) 110 .named("singletonMap") 111 .withFeatures( 112 MapFeature.ALLOWS_NULL_KEYS, 113 MapFeature.ALLOWS_NULL_VALUES, 114 CollectionSize.ONE) 115 .suppressing(suppressForSingletonMap()) 116 .createTestSuite(); 117 } 118 119 public Test testsForHashMap() { 120 return MapTestSuiteBuilder 121 .using(new TestStringMapGenerator() { 122 @Override protected Map<String, String> create( 123 Entry<String, String>[] entries) { 124 return toHashMap(entries); 125 } 126 @Override public Iterable<Entry<String, String>> order( 127 List<Entry<String, String>> insertionOrder) { 128 /* 129 * For convenience, make this test double as a test that no tester 130 * calls order() on a container without the KNOWN_ORDER feature. 131 */ 132 throw new UnsupportedOperationException(); 133 } 134 }) 135 .named("HashMap") 136 .withFeatures( 137 MapFeature.GENERAL_PURPOSE, 138 MapFeature.ALLOWS_NULL_KEYS, 139 MapFeature.ALLOWS_NULL_VALUES, 140 CollectionSize.ANY) 141 .suppressing(suppressForHashMap()) 142 .createTestSuite(); 143 } 144 145 public Test testsForLinkedHashMap() { 146 return MapTestSuiteBuilder 147 .using(new TestStringMapGenerator() { 148 @Override protected Map<String, String> create( 149 Entry<String, String>[] entries) { 150 return populate(new LinkedHashMap<String, String>(), entries); 151 } 152 }) 153 .named("LinkedHashMap") 154 .withFeatures( 155 MapFeature.GENERAL_PURPOSE, 156 MapFeature.ALLOWS_NULL_KEYS, 157 MapFeature.ALLOWS_NULL_VALUES, 158 CollectionFeature.KNOWN_ORDER, 159 CollectionSize.ANY) 160 .suppressing(suppressForLinkedHashMap()) 161 .createTestSuite(); 162 } 163 164 public Test testsForTreeMap() { 165 return NavigableMapTestSuiteBuilder 166 .using(new TestStringMapGenerator() { 167 @Override protected Map<String, String> create( 168 Entry<String, String>[] entries) { 169 return populate(new TreeMap<String, String>( 170 arbitraryNullFriendlyComparator()), entries); 171 } 172 }) 173 .named("TreeMap") 174 .withFeatures( 175 MapFeature.GENERAL_PURPOSE, 176 MapFeature.ALLOWS_NULL_KEYS, 177 MapFeature.ALLOWS_NULL_VALUES, 178 CollectionFeature.KNOWN_ORDER, 179 CollectionSize.ANY) 180 .suppressing(suppressForTreeMap()) 181 .createTestSuite(); 182 } 183 184 public Test testsForEnumMap() { 185 return MapTestSuiteBuilder 186 .using(new TestEnumMapGenerator() { 187 @Override protected Map<AnEnum, String> create( 188 Entry<AnEnum, String>[] entries) { 189 return populate( 190 new EnumMap<AnEnum, String>(AnEnum.class), entries); 191 } 192 }) 193 .named("EnumMap") 194 .withFeatures( 195 MapFeature.GENERAL_PURPOSE, 196 MapFeature.ALLOWS_NULL_VALUES, 197 MapFeature.RESTRICTS_KEYS, 198 CollectionFeature.KNOWN_ORDER, 199 CollectionSize.ANY) 200 .suppressing(suppressForEnumMap()) 201 .createTestSuite(); 202 } 203 204 public Test testsForConcurrentHashMap() { 205 return MapTestSuiteBuilder 206 .using(new TestStringMapGenerator() { 207 @Override protected Map<String, String> create( 208 Entry<String, String>[] entries) { 209 return populate(new ConcurrentHashMap<String, String>(), entries); 210 } 211 }) 212 .named("ConcurrentHashMap") 213 .withFeatures( 214 MapFeature.GENERAL_PURPOSE, 215 CollectionSize.ANY) 216 .suppressing(suppressForConcurrentHashMap()) 217 .createTestSuite(); 218 } 219 220 // TODO: IdentityHashMap, AbstractMap 221 222 private static Map<String, String> toHashMap( 223 Entry<String, String>[] entries) { 224 return populate(new HashMap<String, String>(), entries); 225 } 226 227 // TODO: call conversion constructors or factory methods instead of using 228 // populate() on an empty map 229 private static <T> Map<T, String> populate( 230 Map<T, String> map, Entry<T, String>[] entries) { 231 for (Entry<T, String> entry : entries) { 232 map.put(entry.getKey(), entry.getValue()); 233 } 234 return map; 235 } 236 237 static <T> Comparator<T> arbitraryNullFriendlyComparator() { 238 return new Comparator<T>() { 239 @Override 240 public int compare(T left, T right) { 241 return String.valueOf(left).compareTo(String.valueOf(right)); 242 } 243 }; 244 } 245} 246