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 17 package com.google.common.collect.testing; 18 19 import com.google.common.collect.testing.features.CollectionFeature; 20 import com.google.common.collect.testing.features.CollectionSize; 21 import com.google.common.collect.testing.features.MapFeature; 22 23 import junit.framework.Test; 24 import junit.framework.TestSuite; 25 26 import java.io.Serializable; 27 import java.lang.reflect.Method; 28 import java.util.Collection; 29 import java.util.Collections; 30 import java.util.Comparator; 31 import java.util.EnumMap; 32 import java.util.HashMap; 33 import java.util.LinkedHashMap; 34 import java.util.Map; 35 import java.util.Map.Entry; 36 import java.util.SortedMap; 37 import java.util.TreeMap; 38 import java.util.concurrent.ConcurrentHashMap; 39 import java.util.concurrent.ConcurrentSkipListMap; 40 41 /** 42 * Generates a test suite covering the {@link Map} implementations in the 43 * {@link java.util} package. Can be subclassed to specify tests that should 44 * be suppressed. 45 * 46 * @author Kevin Bourrillion 47 */ 48 public class TestsForMapsInJavaUtil { 49 50 public static Test suite() { 51 return new TestsForMapsInJavaUtil().allTests(); 52 } 53 54 public Test allTests() { 55 TestSuite suite = new TestSuite("java.util Maps"); 56 suite.addTest(testsForEmptyMap()); 57 suite.addTest(testsForSingletonMap()); 58 suite.addTest(testsForHashMap()); 59 suite.addTest(testsForLinkedHashMap()); 60 suite.addTest(testsForTreeMapNatural()); 61 suite.addTest(testsForTreeMapWithComparator()); 62 suite.addTest(testsForEnumMap()); 63 suite.addTest(testsForConcurrentHashMap()); 64 suite.addTest(testsForConcurrentSkipListMapNatural()); 65 suite.addTest(testsForConcurrentSkipListMapWithComparator()); 66 return suite; 67 } 68 69 protected Collection<Method> suppressForEmptyMap() { 70 return Collections.emptySet(); 71 } 72 protected Collection<Method> suppressForSingletonMap() { 73 return Collections.emptySet(); 74 } 75 protected Collection<Method> suppressForHashMap() { 76 return Collections.emptySet(); 77 } 78 protected Collection<Method> suppressForLinkedHashMap() { 79 return Collections.emptySet(); 80 } 81 protected Collection<Method> suppressForTreeMapNatural() { 82 return Collections.emptySet(); 83 } 84 protected Collection<Method> suppressForTreeMapWithComparator() { 85 return Collections.emptySet(); 86 } 87 protected Collection<Method> suppressForEnumMap() { 88 return Collections.emptySet(); 89 } 90 protected Collection<Method> suppressForConcurrentHashMap() { 91 return Collections.emptySet(); 92 } 93 protected Collection<Method> suppressForConcurrentSkipListMap() { 94 return Collections.emptySet(); 95 } 96 97 public Test testsForEmptyMap() { 98 return MapTestSuiteBuilder 99 .using(new TestStringMapGenerator() { 100 @Override protected Map<String, String> create( 101 Entry<String, String>[] entries) { 102 return Collections.emptyMap(); 103 } 104 }) 105 .named("emptyMap") 106 .withFeatures( 107 CollectionFeature.SERIALIZABLE, 108 CollectionSize.ZERO) 109 .suppressing(suppressForEmptyMap()) 110 .createTestSuite(); 111 } 112 113 public Test testsForSingletonMap() { 114 return MapTestSuiteBuilder 115 .using(new TestStringMapGenerator() { 116 @Override protected Map<String, String> create( 117 Entry<String, String>[] entries) { 118 return Collections.singletonMap( 119 entries[0].getKey(), entries[0].getValue()); 120 } 121 }) 122 .named("singletonMap") 123 .withFeatures( 124 MapFeature.ALLOWS_NULL_KEYS, 125 MapFeature.ALLOWS_NULL_VALUES, 126 MapFeature.ALLOWS_ANY_NULL_QUERIES, 127 CollectionFeature.SERIALIZABLE, 128 CollectionSize.ONE) 129 .suppressing(suppressForSingletonMap()) 130 .createTestSuite(); 131 } 132 133 public Test testsForHashMap() { 134 return MapTestSuiteBuilder 135 .using(new TestStringMapGenerator() { 136 @Override protected Map<String, String> create( 137 Entry<String, String>[] entries) { 138 return toHashMap(entries); 139 } 140 }) 141 .named("HashMap") 142 .withFeatures( 143 MapFeature.GENERAL_PURPOSE, 144 MapFeature.ALLOWS_NULL_KEYS, 145 MapFeature.ALLOWS_NULL_VALUES, 146 MapFeature.ALLOWS_ANY_NULL_QUERIES, 147 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 148 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 149 CollectionFeature.SERIALIZABLE, 150 CollectionSize.ANY) 151 .suppressing(suppressForHashMap()) 152 .createTestSuite(); 153 } 154 155 public Test testsForLinkedHashMap() { 156 return MapTestSuiteBuilder 157 .using(new TestStringMapGenerator() { 158 @Override protected Map<String, String> create( 159 Entry<String, String>[] entries) { 160 return populate(new LinkedHashMap<String, String>(), entries); 161 } 162 }) 163 .named("LinkedHashMap") 164 .withFeatures( 165 MapFeature.GENERAL_PURPOSE, 166 MapFeature.ALLOWS_NULL_KEYS, 167 MapFeature.ALLOWS_NULL_VALUES, 168 MapFeature.ALLOWS_ANY_NULL_QUERIES, 169 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 170 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 171 CollectionFeature.KNOWN_ORDER, 172 CollectionFeature.SERIALIZABLE, 173 CollectionSize.ANY) 174 .suppressing(suppressForLinkedHashMap()) 175 .createTestSuite(); 176 } 177 178 public Test testsForTreeMapNatural() { 179 return NavigableMapTestSuiteBuilder 180 .using(new TestStringSortedMapGenerator() { 181 @Override protected SortedMap<String, String> create( 182 Entry<String, String>[] entries) { 183 /* 184 * TODO(cpovirk): it would be nice to create an input Map and use 185 * the copy constructor here and in the other tests 186 */ 187 return populate(new TreeMap<String, String>(), entries); 188 } 189 }) 190 .named("TreeMap, natural") 191 .withFeatures( 192 MapFeature.GENERAL_PURPOSE, 193 MapFeature.ALLOWS_NULL_VALUES, 194 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 195 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 196 CollectionFeature.KNOWN_ORDER, 197 CollectionFeature.SERIALIZABLE, 198 CollectionSize.ANY) 199 .suppressing(suppressForTreeMapNatural()) 200 .createTestSuite(); 201 } 202 203 public Test testsForTreeMapWithComparator() { 204 return NavigableMapTestSuiteBuilder 205 .using(new TestStringSortedMapGenerator() { 206 @Override protected SortedMap<String, String> create( 207 Entry<String, String>[] entries) { 208 return populate(new TreeMap<String, String>( 209 arbitraryNullFriendlyComparator()), entries); 210 } 211 }) 212 .named("TreeMap, with comparator") 213 .withFeatures( 214 MapFeature.GENERAL_PURPOSE, 215 MapFeature.ALLOWS_NULL_KEYS, 216 MapFeature.ALLOWS_NULL_VALUES, 217 MapFeature.ALLOWS_ANY_NULL_QUERIES, 218 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 219 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 220 CollectionFeature.KNOWN_ORDER, 221 CollectionFeature.SERIALIZABLE, 222 CollectionSize.ANY) 223 .suppressing(suppressForTreeMapWithComparator()) 224 .createTestSuite(); 225 } 226 227 public Test testsForEnumMap() { 228 return MapTestSuiteBuilder 229 .using(new TestEnumMapGenerator() { 230 @Override protected Map<AnEnum, String> create( 231 Entry<AnEnum, String>[] entries) { 232 return populate( 233 new EnumMap<AnEnum, String>(AnEnum.class), entries); 234 } 235 }) 236 .named("EnumMap") 237 .withFeatures( 238 MapFeature.GENERAL_PURPOSE, 239 MapFeature.ALLOWS_NULL_VALUES, 240 MapFeature.RESTRICTS_KEYS, 241 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 242 CollectionFeature.KNOWN_ORDER, 243 CollectionFeature.SERIALIZABLE, 244 CollectionSize.ANY) 245 .suppressing(suppressForEnumMap()) 246 .createTestSuite(); 247 } 248 249 public Test testsForConcurrentHashMap() { 250 return MapTestSuiteBuilder 251 .using(new TestStringMapGenerator() { 252 @Override protected Map<String, String> create( 253 Entry<String, String>[] entries) { 254 return populate(new ConcurrentHashMap<String, String>(), entries); 255 } 256 }) 257 .named("ConcurrentHashMap") 258 .withFeatures( 259 MapFeature.GENERAL_PURPOSE, 260 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 261 CollectionFeature.SERIALIZABLE, 262 CollectionSize.ANY) 263 .suppressing(suppressForConcurrentHashMap()) 264 .createTestSuite(); 265 } 266 267 public Test testsForConcurrentSkipListMapNatural() { 268 return NavigableMapTestSuiteBuilder 269 .using(new TestStringSortedMapGenerator() { 270 @Override protected SortedMap<String, String> create( 271 Entry<String, String>[] entries) { 272 return populate(new ConcurrentSkipListMap<String, String>(), entries); 273 } 274 }) 275 .named("ConcurrentSkipListMap, natural") 276 .withFeatures( 277 MapFeature.GENERAL_PURPOSE, 278 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 279 CollectionFeature.KNOWN_ORDER, 280 CollectionFeature.SERIALIZABLE, 281 CollectionSize.ANY) 282 .suppressing(suppressForConcurrentSkipListMap()) 283 .createTestSuite(); 284 } 285 286 public Test testsForConcurrentSkipListMapWithComparator() { 287 return NavigableMapTestSuiteBuilder 288 .using(new TestStringSortedMapGenerator() { 289 @Override protected SortedMap<String, String> create( 290 Entry<String, String>[] entries) { 291 return populate(new ConcurrentSkipListMap<String, String>( 292 arbitraryNullFriendlyComparator()), entries); 293 } 294 }) 295 .named("ConcurrentSkipListMap, with comparator") 296 .withFeatures( 297 MapFeature.GENERAL_PURPOSE, 298 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 299 CollectionFeature.KNOWN_ORDER, 300 CollectionFeature.SERIALIZABLE, 301 CollectionSize.ANY) 302 .suppressing(suppressForConcurrentSkipListMap()) 303 .createTestSuite(); 304 } 305 306 // TODO: IdentityHashMap, AbstractMap 307 308 private static Map<String, String> toHashMap( 309 Entry<String, String>[] entries) { 310 return populate(new HashMap<String, String>(), entries); 311 } 312 313 // TODO: call conversion constructors or factory methods instead of using 314 // populate() on an empty map 315 private static <T, M extends Map<T, String>> M populate( 316 M map, Entry<T, String>[] entries) { 317 for (Entry<T, String> entry : entries) { 318 map.put(entry.getKey(), entry.getValue()); 319 } 320 return map; 321 } 322 323 static <T> Comparator<T> arbitraryNullFriendlyComparator() { 324 return new NullFriendlyComparator<T>(); 325 } 326 327 private static final class NullFriendlyComparator<T> implements Comparator<T>, Serializable { 328 @Override 329 public int compare(T left, T right) { 330 return String.valueOf(left).compareTo(String.valueOf(right)); 331 } 332 } 333 } 334