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