001/* 002 * Copyright (C) 2009 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; 018 019import static java.util.Arrays.asList; 020 021import com.google.common.annotations.GwtIncompatible; 022import com.google.common.collect.testing.features.CollectionFeature; 023import com.google.common.collect.testing.features.CollectionSize; 024import com.google.common.collect.testing.features.MapFeature; 025import com.google.common.collect.testing.testers.MapEntrySetTester; 026import java.io.Serializable; 027import java.lang.reflect.Method; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.Comparator; 031import java.util.EnumMap; 032import java.util.HashMap; 033import java.util.Hashtable; 034import java.util.LinkedHashMap; 035import java.util.Map; 036import java.util.Map.Entry; 037import java.util.SortedMap; 038import java.util.TreeMap; 039import java.util.concurrent.ConcurrentHashMap; 040import java.util.concurrent.ConcurrentSkipListMap; 041import junit.framework.Test; 042import junit.framework.TestSuite; 043 044/** 045 * Generates a test suite covering the {@link Map} implementations in the {@link java.util} package. 046 * Can be subclassed to specify tests that should be suppressed. 047 * 048 * @author Kevin Bourrillion 049 */ 050@GwtIncompatible 051public class TestsForMapsInJavaUtil { 052 053 public static Test suite() { 054 return new TestsForMapsInJavaUtil().allTests(); 055 } 056 057 public Test allTests() { 058 TestSuite suite = new TestSuite("java.util Maps"); 059 suite.addTest(testsForCheckedMap()); 060 suite.addTest(testsForCheckedSortedMap()); 061 suite.addTest(testsForEmptyMap()); 062 suite.addTest(testsForSingletonMap()); 063 suite.addTest(testsForHashMap()); 064 suite.addTest(testsForHashtable()); 065 suite.addTest(testsForLinkedHashMap()); 066 suite.addTest(testsForTreeMapNatural()); 067 suite.addTest(testsForTreeMapWithComparator()); 068 suite.addTest(testsForUnmodifiableMap()); 069 suite.addTest(testsForUnmodifiableSortedMap()); 070 suite.addTest(testsForEnumMap()); 071 suite.addTest(testsForConcurrentHashMap()); 072 suite.addTest(testsForConcurrentSkipListMapNatural()); 073 suite.addTest(testsForConcurrentSkipListMapWithComparator()); 074 return suite; 075 } 076 077 protected Collection<Method> suppressForCheckedMap() { 078 return Collections.emptySet(); 079 } 080 081 protected Collection<Method> suppressForCheckedSortedMap() { 082 return Collections.emptySet(); 083 } 084 085 protected Collection<Method> suppressForEmptyMap() { 086 return Collections.emptySet(); 087 } 088 089 protected Collection<Method> suppressForSingletonMap() { 090 return Collections.emptySet(); 091 } 092 093 protected Collection<Method> suppressForHashMap() { 094 return Collections.emptySet(); 095 } 096 097 protected Collection<Method> suppressForHashtable() { 098 return Collections.emptySet(); 099 } 100 101 protected Collection<Method> suppressForLinkedHashMap() { 102 return Collections.emptySet(); 103 } 104 105 protected Collection<Method> suppressForTreeMapNatural() { 106 return Collections.emptySet(); 107 } 108 109 protected Collection<Method> suppressForTreeMapWithComparator() { 110 return Collections.emptySet(); 111 } 112 113 protected Collection<Method> suppressForUnmodifiableMap() { 114 return Collections.emptySet(); 115 } 116 117 protected Collection<Method> suppressForUnmodifiableSortedMap() { 118 return Collections.emptySet(); 119 } 120 121 protected Collection<Method> suppressForEnumMap() { 122 return Collections.emptySet(); 123 } 124 125 protected Collection<Method> suppressForConcurrentHashMap() { 126 return Collections.emptySet(); 127 } 128 129 protected Collection<Method> suppressForConcurrentSkipListMap() { 130 return asList( 131 MapEntrySetTester.getSetValueMethod(), 132 MapEntrySetTester.getSetValueWithNullValuesAbsentMethod(), 133 MapEntrySetTester.getSetValueWithNullValuesPresentMethod()); 134 } 135 136 public Test testsForCheckedMap() { 137 return MapTestSuiteBuilder.using( 138 new TestStringMapGenerator() { 139 @Override 140 protected Map<String, String> create(Entry<String, String>[] entries) { 141 Map<String, String> map = populate(new HashMap<String, String>(), entries); 142 return Collections.checkedMap(map, String.class, String.class); 143 } 144 }) 145 .named("checkedMap/HashMap") 146 .withFeatures( 147 MapFeature.GENERAL_PURPOSE, 148 MapFeature.ALLOWS_NULL_KEYS, 149 MapFeature.ALLOWS_NULL_VALUES, 150 MapFeature.ALLOWS_ANY_NULL_QUERIES, 151 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 152 MapFeature.RESTRICTS_KEYS, 153 MapFeature.RESTRICTS_VALUES, 154 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 155 CollectionFeature.SERIALIZABLE, 156 CollectionSize.ANY) 157 .suppressing(suppressForCheckedMap()) 158 .createTestSuite(); 159 } 160 161 public Test testsForCheckedSortedMap() { 162 return SortedMapTestSuiteBuilder.using( 163 new TestStringSortedMapGenerator() { 164 @Override 165 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 166 SortedMap<String, String> map = populate(new TreeMap<String, String>(), entries); 167 return Collections.checkedSortedMap(map, String.class, String.class); 168 } 169 }) 170 .named("checkedSortedMap/TreeMap, natural") 171 .withFeatures( 172 MapFeature.GENERAL_PURPOSE, 173 MapFeature.ALLOWS_NULL_VALUES, 174 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 175 MapFeature.RESTRICTS_KEYS, 176 MapFeature.RESTRICTS_VALUES, 177 CollectionFeature.KNOWN_ORDER, 178 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 179 CollectionFeature.SERIALIZABLE, 180 CollectionSize.ANY) 181 .suppressing(suppressForCheckedSortedMap()) 182 .createTestSuite(); 183 } 184 185 public Test testsForEmptyMap() { 186 return MapTestSuiteBuilder.using( 187 new TestStringMapGenerator() { 188 @Override 189 protected Map<String, String> create(Entry<String, String>[] entries) { 190 return Collections.emptyMap(); 191 } 192 }) 193 .named("emptyMap") 194 .withFeatures(CollectionFeature.SERIALIZABLE, CollectionSize.ZERO) 195 .suppressing(suppressForEmptyMap()) 196 .createTestSuite(); 197 } 198 199 public Test testsForSingletonMap() { 200 return MapTestSuiteBuilder.using( 201 new TestStringMapGenerator() { 202 @Override 203 protected Map<String, String> create(Entry<String, String>[] entries) { 204 return Collections.singletonMap(entries[0].getKey(), entries[0].getValue()); 205 } 206 }) 207 .named("singletonMap") 208 .withFeatures( 209 MapFeature.ALLOWS_NULL_KEYS, 210 MapFeature.ALLOWS_NULL_VALUES, 211 MapFeature.ALLOWS_ANY_NULL_QUERIES, 212 CollectionFeature.SERIALIZABLE, 213 CollectionSize.ONE) 214 .suppressing(suppressForSingletonMap()) 215 .createTestSuite(); 216 } 217 218 public Test testsForHashMap() { 219 return MapTestSuiteBuilder.using( 220 new TestStringMapGenerator() { 221 @Override 222 protected Map<String, String> create(Entry<String, String>[] entries) { 223 return toHashMap(entries); 224 } 225 }) 226 .named("HashMap") 227 .withFeatures( 228 MapFeature.GENERAL_PURPOSE, 229 MapFeature.ALLOWS_NULL_KEYS, 230 MapFeature.ALLOWS_NULL_VALUES, 231 MapFeature.ALLOWS_ANY_NULL_QUERIES, 232 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 233 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 234 CollectionFeature.SERIALIZABLE, 235 CollectionSize.ANY) 236 .suppressing(suppressForHashMap()) 237 .createTestSuite(); 238 } 239 240 public Test testsForHashtable() { 241 return MapTestSuiteBuilder.using( 242 new TestStringMapGenerator() { 243 @Override 244 protected Map<String, String> create(Entry<String, String>[] entries) { 245 return populate(new Hashtable<String, String>(), entries); 246 } 247 }) 248 .withFeatures( 249 MapFeature.GENERAL_PURPOSE, 250 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 251 MapFeature.RESTRICTS_KEYS, 252 MapFeature.SUPPORTS_REMOVE, 253 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 254 CollectionFeature.SERIALIZABLE, 255 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 256 CollectionFeature.SUPPORTS_REMOVE, 257 CollectionSize.ANY) 258 .named("Hashtable") 259 .suppressing(suppressForHashtable()) 260 .createTestSuite(); 261 } 262 263 public Test testsForLinkedHashMap() { 264 return MapTestSuiteBuilder.using( 265 new TestStringMapGenerator() { 266 @Override 267 protected Map<String, String> create(Entry<String, String>[] entries) { 268 return populate(new LinkedHashMap<String, String>(), entries); 269 } 270 }) 271 .named("LinkedHashMap") 272 .withFeatures( 273 MapFeature.GENERAL_PURPOSE, 274 MapFeature.ALLOWS_NULL_KEYS, 275 MapFeature.ALLOWS_NULL_VALUES, 276 MapFeature.ALLOWS_ANY_NULL_QUERIES, 277 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 278 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 279 CollectionFeature.KNOWN_ORDER, 280 CollectionFeature.SERIALIZABLE, 281 CollectionSize.ANY) 282 .suppressing(suppressForLinkedHashMap()) 283 .createTestSuite(); 284 } 285 286 public Test testsForTreeMapNatural() { 287 return NavigableMapTestSuiteBuilder.using( 288 new TestStringSortedMapGenerator() { 289 @Override 290 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 291 /* 292 * TODO(cpovirk): it would be nice to create an input Map and use 293 * the copy constructor here and in the other tests 294 */ 295 return populate(new TreeMap<String, String>(), entries); 296 } 297 }) 298 .named("TreeMap, natural") 299 .withFeatures( 300 MapFeature.GENERAL_PURPOSE, 301 MapFeature.ALLOWS_NULL_VALUES, 302 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 303 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 304 CollectionFeature.KNOWN_ORDER, 305 CollectionFeature.SERIALIZABLE, 306 CollectionSize.ANY) 307 .suppressing(suppressForTreeMapNatural()) 308 .createTestSuite(); 309 } 310 311 public Test testsForTreeMapWithComparator() { 312 return NavigableMapTestSuiteBuilder.using( 313 new TestStringSortedMapGenerator() { 314 @Override 315 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 316 return populate( 317 new TreeMap<String, String>(arbitraryNullFriendlyComparator()), entries); 318 } 319 }) 320 .named("TreeMap, with comparator") 321 .withFeatures( 322 MapFeature.GENERAL_PURPOSE, 323 MapFeature.ALLOWS_NULL_KEYS, 324 MapFeature.ALLOWS_NULL_VALUES, 325 MapFeature.ALLOWS_ANY_NULL_QUERIES, 326 MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 327 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 328 CollectionFeature.KNOWN_ORDER, 329 CollectionFeature.SERIALIZABLE, 330 CollectionSize.ANY) 331 .suppressing(suppressForTreeMapWithComparator()) 332 .createTestSuite(); 333 } 334 335 public Test testsForUnmodifiableMap() { 336 return MapTestSuiteBuilder.using( 337 new TestStringMapGenerator() { 338 @Override 339 protected Map<String, String> create(Entry<String, String>[] entries) { 340 return Collections.unmodifiableMap(toHashMap(entries)); 341 } 342 }) 343 .named("unmodifiableMap/HashMap") 344 .withFeatures( 345 MapFeature.ALLOWS_NULL_KEYS, 346 MapFeature.ALLOWS_NULL_VALUES, 347 MapFeature.ALLOWS_ANY_NULL_QUERIES, 348 CollectionFeature.SERIALIZABLE, 349 CollectionSize.ANY) 350 .suppressing(suppressForUnmodifiableMap()) 351 .createTestSuite(); 352 } 353 354 public Test testsForUnmodifiableSortedMap() { 355 return MapTestSuiteBuilder.using( 356 new TestStringSortedMapGenerator() { 357 @Override 358 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 359 SortedMap<String, String> map = populate(new TreeMap<String, String>(), entries); 360 return Collections.unmodifiableSortedMap(map); 361 } 362 }) 363 .named("unmodifiableSortedMap/TreeMap, natural") 364 .withFeatures( 365 MapFeature.ALLOWS_NULL_VALUES, 366 CollectionFeature.KNOWN_ORDER, 367 CollectionFeature.SERIALIZABLE, 368 CollectionSize.ANY) 369 .suppressing(suppressForUnmodifiableSortedMap()) 370 .createTestSuite(); 371 } 372 373 public Test testsForEnumMap() { 374 return MapTestSuiteBuilder.using( 375 new TestEnumMapGenerator() { 376 @Override 377 protected Map<AnEnum, String> create(Entry<AnEnum, String>[] entries) { 378 return populate(new EnumMap<AnEnum, String>(AnEnum.class), entries); 379 } 380 }) 381 .named("EnumMap") 382 .withFeatures( 383 MapFeature.GENERAL_PURPOSE, 384 MapFeature.ALLOWS_NULL_VALUES, 385 MapFeature.RESTRICTS_KEYS, 386 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 387 CollectionFeature.KNOWN_ORDER, 388 CollectionFeature.SERIALIZABLE, 389 CollectionSize.ANY) 390 .suppressing(suppressForEnumMap()) 391 .createTestSuite(); 392 } 393 394 public Test testsForConcurrentHashMap() { 395 return ConcurrentMapTestSuiteBuilder.using( 396 new TestStringMapGenerator() { 397 @Override 398 protected Map<String, String> create(Entry<String, String>[] entries) { 399 return populate(new ConcurrentHashMap<String, String>(), entries); 400 } 401 }) 402 .named("ConcurrentHashMap") 403 .withFeatures( 404 MapFeature.GENERAL_PURPOSE, 405 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 406 CollectionFeature.SERIALIZABLE, 407 CollectionSize.ANY) 408 .suppressing(suppressForConcurrentHashMap()) 409 .createTestSuite(); 410 } 411 412 public Test testsForConcurrentSkipListMapNatural() { 413 return ConcurrentNavigableMapTestSuiteBuilder.using( 414 new TestStringSortedMapGenerator() { 415 @Override 416 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 417 return populate(new ConcurrentSkipListMap<String, String>(), entries); 418 } 419 }) 420 .named("ConcurrentSkipListMap, natural") 421 .withFeatures( 422 MapFeature.GENERAL_PURPOSE, 423 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 424 CollectionFeature.KNOWN_ORDER, 425 CollectionFeature.SERIALIZABLE, 426 CollectionSize.ANY) 427 .suppressing(suppressForConcurrentSkipListMap()) 428 .createTestSuite(); 429 } 430 431 public Test testsForConcurrentSkipListMapWithComparator() { 432 return ConcurrentNavigableMapTestSuiteBuilder.using( 433 new TestStringSortedMapGenerator() { 434 @Override 435 protected SortedMap<String, String> create(Entry<String, String>[] entries) { 436 return populate( 437 new ConcurrentSkipListMap<String, String>(arbitraryNullFriendlyComparator()), 438 entries); 439 } 440 }) 441 .named("ConcurrentSkipListMap, with comparator") 442 .withFeatures( 443 MapFeature.GENERAL_PURPOSE, 444 CollectionFeature.SUPPORTS_ITERATOR_REMOVE, 445 CollectionFeature.KNOWN_ORDER, 446 CollectionFeature.SERIALIZABLE, 447 CollectionSize.ANY) 448 .suppressing(suppressForConcurrentSkipListMap()) 449 .createTestSuite(); 450 } 451 452 // TODO: IdentityHashMap, AbstractMap 453 454 private static Map<String, String> toHashMap(Entry<String, String>[] entries) { 455 return populate(new HashMap<String, String>(), entries); 456 } 457 458 // TODO: call conversion constructors or factory methods instead of using 459 // populate() on an empty map 460 private static <T, M extends Map<T, String>> M populate(M map, Entry<T, String>[] entries) { 461 for (Entry<T, String> entry : entries) { 462 map.put(entry.getKey(), entry.getValue()); 463 } 464 return map; 465 } 466 467 static <T> Comparator<T> arbitraryNullFriendlyComparator() { 468 return new NullFriendlyComparator<T>(); 469 } 470 471 private static final class NullFriendlyComparator<T> implements Comparator<T>, Serializable { 472 @Override 473 public int compare(T left, T right) { 474 return String.valueOf(left).compareTo(String.valueOf(right)); 475 } 476 } 477}