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 com.google.common.collect.testing.testers.CollectionSpliteratorTester.getSpliteratorNotImmutableCollectionAllowsAddMethod; 020import static com.google.common.collect.testing.testers.CollectionSpliteratorTester.getSpliteratorNotImmutableCollectionAllowsRemoveMethod; 021import static java.util.Arrays.asList; 022import static java.util.Collections.emptySet; 023import static java.util.Collections.singleton; 024import static java.util.Collections.unmodifiableSet; 025 026import com.google.common.annotations.GwtIncompatible; 027import com.google.common.collect.testing.features.CollectionFeature; 028import com.google.common.collect.testing.features.CollectionSize; 029import com.google.common.collect.testing.features.SetFeature; 030import java.io.Serializable; 031import java.lang.reflect.Method; 032import java.util.AbstractSet; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.Comparator; 036import java.util.EnumSet; 037import java.util.HashSet; 038import java.util.Iterator; 039import java.util.LinkedHashSet; 040import java.util.NavigableSet; 041import java.util.Set; 042import java.util.SortedSet; 043import java.util.TreeSet; 044import java.util.concurrent.ConcurrentSkipListSet; 045import java.util.concurrent.CopyOnWriteArraySet; 046import junit.framework.Test; 047import junit.framework.TestSuite; 048 049/** 050 * Generates a test suite covering the {@link Set} implementations in the {@link java.util} package. 051 * Can be subclassed to specify tests that should be suppressed. 052 * 053 * @author Kevin Bourrillion 054 */ 055@GwtIncompatible 056public class TestsForSetsInJavaUtil { 057 public static Test suite() { 058 return new TestsForSetsInJavaUtil().allTests(); 059 } 060 061 public Test allTests() { 062 TestSuite suite = new TestSuite("java.util Sets"); 063 suite.addTest(testsForCheckedNavigableSet()); 064 suite.addTest(testsForEmptySet()); 065 suite.addTest(testsForEmptyNavigableSet()); 066 suite.addTest(testsForEmptySortedSet()); 067 suite.addTest(testsForSingletonSet()); 068 suite.addTest(testsForHashSet()); 069 suite.addTest(testsForLinkedHashSet()); 070 suite.addTest(testsForEnumSet()); 071 suite.addTest(testsForSynchronizedNavigableSet()); 072 suite.addTest(testsForTreeSetNatural()); 073 suite.addTest(testsForTreeSetWithComparator()); 074 suite.addTest(testsForCopyOnWriteArraySet()); 075 suite.addTest(testsForUnmodifiableSet()); 076 suite.addTest(testsForUnmodifiableNavigableSet()); 077 suite.addTest(testsForCheckedSet()); 078 suite.addTest(testsForCheckedSortedSet()); 079 suite.addTest(testsForAbstractSet()); 080 suite.addTest(testsForBadlyCollidingHashSet()); 081 suite.addTest(testsForConcurrentSkipListSetNatural()); 082 suite.addTest(testsForConcurrentSkipListSetWithComparator()); 083 084 return suite; 085 } 086 087 protected Collection<Method> suppressForCheckedNavigableSet() { 088 return emptySet(); 089 } 090 091 protected Collection<Method> suppressForEmptySet() { 092 return emptySet(); 093 } 094 095 protected Collection<Method> suppressForEmptyNavigableSet() { 096 return emptySet(); 097 } 098 099 protected Collection<Method> suppressForEmptySortedSet() { 100 return emptySet(); 101 } 102 103 protected Collection<Method> suppressForSingletonSet() { 104 return emptySet(); 105 } 106 107 protected Collection<Method> suppressForHashSet() { 108 return emptySet(); 109 } 110 111 protected Collection<Method> suppressForLinkedHashSet() { 112 return emptySet(); 113 } 114 115 protected Collection<Method> suppressForEnumSet() { 116 return emptySet(); 117 } 118 119 protected Collection<Method> suppressForSynchronizedNavigableSet() { 120 return emptySet(); 121 } 122 123 protected Collection<Method> suppressForTreeSetNatural() { 124 return emptySet(); 125 } 126 127 protected Collection<Method> suppressForTreeSetWithComparator() { 128 return emptySet(); 129 } 130 131 protected Collection<Method> suppressForCopyOnWriteArraySet() { 132 return asList( 133 getSpliteratorNotImmutableCollectionAllowsAddMethod(), 134 getSpliteratorNotImmutableCollectionAllowsRemoveMethod()); 135 } 136 137 protected Collection<Method> suppressForUnmodifiableSet() { 138 return emptySet(); 139 } 140 141 protected Collection<Method> suppressForUnmodifiableNavigableSet() { 142 return emptySet(); 143 } 144 145 protected Collection<Method> suppressForCheckedSet() { 146 return emptySet(); 147 } 148 149 protected Collection<Method> suppressForCheckedSortedSet() { 150 return emptySet(); 151 } 152 153 protected Collection<Method> suppressForAbstractSet() { 154 return emptySet(); 155 } 156 157 protected Collection<Method> suppressForConcurrentSkipListSetNatural() { 158 return emptySet(); 159 } 160 161 protected Collection<Method> suppressForConcurrentSkipListSetWithComparator() { 162 return emptySet(); 163 } 164 165 public Test testsForCheckedNavigableSet() { 166 return SortedSetTestSuiteBuilder.using( 167 new TestStringSortedSetGenerator() { 168 @Override 169 public NavigableSet<String> create(String[] elements) { 170 NavigableSet<String> innerSet = new TreeSet<>(); 171 Collections.addAll(innerSet, elements); 172 return Collections.checkedNavigableSet(innerSet, String.class); 173 } 174 }) 175 .named("checkedNavigableSet/TreeSet, natural") 176 .withFeatures( 177 SetFeature.GENERAL_PURPOSE, 178 CollectionFeature.KNOWN_ORDER, 179 CollectionFeature.SERIALIZABLE, 180 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 181 CollectionFeature.RESTRICTS_ELEMENTS, 182 CollectionSize.ANY) 183 .suppressing(suppressForCheckedNavigableSet()) 184 .createTestSuite(); 185 } 186 187 public Test testsForEmptySet() { 188 return SetTestSuiteBuilder.using( 189 new TestStringSetGenerator() { 190 @Override 191 public Set<String> create(String[] elements) { 192 return emptySet(); 193 } 194 }) 195 .named("emptySet") 196 .withFeatures(CollectionFeature.SERIALIZABLE, CollectionSize.ZERO) 197 .suppressing(suppressForEmptySet()) 198 .createTestSuite(); 199 } 200 201 public Test testsForEmptyNavigableSet() { 202 return SetTestSuiteBuilder.using( 203 new TestStringSortedSetGenerator() { 204 @Override 205 public NavigableSet<String> create(String[] elements) { 206 return Collections.emptyNavigableSet(); 207 } 208 }) 209 .named("emptyNavigableSet") 210 .withFeatures(CollectionFeature.SERIALIZABLE, CollectionSize.ZERO) 211 .suppressing(suppressForEmptyNavigableSet()) 212 .createTestSuite(); 213 } 214 215 public Test testsForEmptySortedSet() { 216 return SetTestSuiteBuilder.using( 217 new TestStringSortedSetGenerator() { 218 @Override 219 public SortedSet<String> create(String[] elements) { 220 return Collections.emptySortedSet(); 221 } 222 }) 223 .named("emptySortedSet") 224 .withFeatures(CollectionFeature.SERIALIZABLE, CollectionSize.ZERO) 225 .suppressing(suppressForEmptySortedSet()) 226 .createTestSuite(); 227 } 228 229 public Test testsForSingletonSet() { 230 return SetTestSuiteBuilder.using( 231 new TestStringSetGenerator() { 232 @Override 233 public Set<String> create(String[] elements) { 234 return singleton(elements[0]); 235 } 236 }) 237 .named("singleton") 238 .withFeatures( 239 CollectionFeature.SERIALIZABLE, 240 CollectionFeature.ALLOWS_NULL_VALUES, 241 CollectionSize.ONE) 242 .suppressing(suppressForSingletonSet()) 243 .createTestSuite(); 244 } 245 246 public Test testsForHashSet() { 247 return SetTestSuiteBuilder.using( 248 new TestStringSetGenerator() { 249 @Override 250 public Set<String> create(String[] elements) { 251 return new HashSet<>(MinimalCollection.of(elements)); 252 } 253 }) 254 .named("HashSet") 255 .withFeatures( 256 SetFeature.GENERAL_PURPOSE, 257 CollectionFeature.SERIALIZABLE, 258 CollectionFeature.ALLOWS_NULL_VALUES, 259 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 260 CollectionSize.ANY) 261 .suppressing(suppressForHashSet()) 262 .createTestSuite(); 263 } 264 265 public Test testsForLinkedHashSet() { 266 return SetTestSuiteBuilder.using( 267 new TestStringSetGenerator() { 268 @Override 269 public Set<String> create(String[] elements) { 270 return new LinkedHashSet<>(MinimalCollection.of(elements)); 271 } 272 }) 273 .named("LinkedHashSet") 274 .withFeatures( 275 SetFeature.GENERAL_PURPOSE, 276 CollectionFeature.SERIALIZABLE, 277 CollectionFeature.ALLOWS_NULL_VALUES, 278 CollectionFeature.KNOWN_ORDER, 279 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 280 CollectionSize.ANY) 281 .suppressing(suppressForLinkedHashSet()) 282 .createTestSuite(); 283 } 284 285 public Test testsForEnumSet() { 286 return SetTestSuiteBuilder.using( 287 new TestEnumSetGenerator() { 288 @Override 289 public Set<AnEnum> create(AnEnum[] elements) { 290 return (elements.length == 0) 291 ? EnumSet.noneOf(AnEnum.class) 292 : EnumSet.copyOf(MinimalCollection.of(elements)); 293 } 294 }) 295 .named("EnumSet") 296 .withFeatures( 297 SetFeature.GENERAL_PURPOSE, 298 CollectionFeature.SERIALIZABLE, 299 CollectionFeature.KNOWN_ORDER, 300 CollectionFeature.RESTRICTS_ELEMENTS, 301 CollectionSize.ANY) 302 .suppressing(suppressForEnumSet()) 303 .createTestSuite(); 304 } 305 306 /** 307 * Tests regular NavigableSet behavior of synchronizedNavigableSet(treeSet); does not test the 308 * fact that it's synchronized. 309 */ 310 public Test testsForSynchronizedNavigableSet() { 311 return NavigableSetTestSuiteBuilder.using( 312 new TestStringSortedSetGenerator() { 313 @Override 314 public SortedSet<String> create(String[] elements) { 315 NavigableSet<String> delegate = new TreeSet<>(MinimalCollection.of(elements)); 316 return Collections.synchronizedNavigableSet(delegate); 317 } 318 }) 319 .named("synchronizedNavigableSet/TreeSet, natural") 320 .withFeatures( 321 SetFeature.GENERAL_PURPOSE, 322 CollectionFeature.SERIALIZABLE, 323 CollectionFeature.KNOWN_ORDER, 324 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 325 CollectionSize.ANY) 326 .suppressing(suppressForSynchronizedNavigableSet()) 327 .createTestSuite(); 328 } 329 330 public Test testsForTreeSetNatural() { 331 return NavigableSetTestSuiteBuilder.using( 332 new TestStringSortedSetGenerator() { 333 @Override 334 public SortedSet<String> create(String[] elements) { 335 return new TreeSet<>(MinimalCollection.of(elements)); 336 } 337 }) 338 .named("TreeSet, natural") 339 .withFeatures( 340 SetFeature.GENERAL_PURPOSE, 341 CollectionFeature.SERIALIZABLE, 342 CollectionFeature.KNOWN_ORDER, 343 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 344 CollectionSize.ANY) 345 .suppressing(suppressForTreeSetNatural()) 346 .createTestSuite(); 347 } 348 349 public Test testsForTreeSetWithComparator() { 350 return NavigableSetTestSuiteBuilder.using( 351 new TestStringSortedSetGenerator() { 352 @Override 353 public SortedSet<String> create(String[] elements) { 354 SortedSet<String> set = new TreeSet<>(arbitraryNullFriendlyComparator()); 355 Collections.addAll(set, elements); 356 return set; 357 } 358 }) 359 .named("TreeSet, with comparator") 360 .withFeatures( 361 SetFeature.GENERAL_PURPOSE, 362 CollectionFeature.SERIALIZABLE, 363 CollectionFeature.ALLOWS_NULL_VALUES, 364 CollectionFeature.KNOWN_ORDER, 365 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 366 CollectionSize.ANY) 367 .suppressing(suppressForTreeSetWithComparator()) 368 .createTestSuite(); 369 } 370 371 public Test testsForCopyOnWriteArraySet() { 372 return SetTestSuiteBuilder.using( 373 new TestStringSetGenerator() { 374 @Override 375 public Set<String> create(String[] elements) { 376 return new CopyOnWriteArraySet<>(MinimalCollection.of(elements)); 377 } 378 }) 379 .named("CopyOnWriteArraySet") 380 .withFeatures( 381 CollectionFeature.SUPPORTS_ADD, 382 CollectionFeature.SUPPORTS_REMOVE, 383 CollectionFeature.SERIALIZABLE, 384 CollectionFeature.ALLOWS_NULL_VALUES, 385 CollectionFeature.KNOWN_ORDER, 386 CollectionSize.ANY) 387 .suppressing(suppressForCopyOnWriteArraySet()) 388 .createTestSuite(); 389 } 390 391 public Test testsForUnmodifiableSet() { 392 return SetTestSuiteBuilder.using( 393 new TestStringSetGenerator() { 394 @Override 395 public Set<String> create(String[] elements) { 396 Set<String> innerSet = new HashSet<>(); 397 Collections.addAll(innerSet, elements); 398 return unmodifiableSet(innerSet); 399 } 400 }) 401 .named("unmodifiableSet/HashSet") 402 .withFeatures( 403 CollectionFeature.NONE, 404 CollectionFeature.SERIALIZABLE, 405 CollectionFeature.ALLOWS_NULL_VALUES, 406 CollectionSize.ANY) 407 .suppressing(suppressForUnmodifiableSet()) 408 .createTestSuite(); 409 } 410 411 public Test testsForUnmodifiableNavigableSet() { 412 return SetTestSuiteBuilder.using( 413 new TestStringSortedSetGenerator() { 414 @Override 415 public NavigableSet<String> create(String[] elements) { 416 NavigableSet<String> innerSet = new TreeSet<>(); 417 Collections.addAll(innerSet, elements); 418 return Collections.unmodifiableNavigableSet(innerSet); 419 } 420 }) 421 .named("unmodifiableNavigableSet/TreeSet, natural") 422 .withFeatures( 423 CollectionFeature.KNOWN_ORDER, 424 CollectionFeature.RESTRICTS_ELEMENTS, 425 CollectionFeature.SERIALIZABLE, 426 CollectionSize.ANY) 427 .suppressing(suppressForUnmodifiableNavigableSet()) 428 .createTestSuite(); 429 } 430 431 public Test testsForCheckedSet() { 432 return SetTestSuiteBuilder.using( 433 new TestStringSetGenerator() { 434 @Override 435 public Set<String> create(String[] elements) { 436 Set<String> innerSet = new HashSet<>(); 437 Collections.addAll(innerSet, elements); 438 return Collections.checkedSet(innerSet, String.class); 439 } 440 }) 441 .named("checkedSet/HashSet") 442 .withFeatures( 443 SetFeature.GENERAL_PURPOSE, 444 CollectionFeature.SERIALIZABLE, 445 CollectionFeature.ALLOWS_NULL_VALUES, 446 CollectionFeature.RESTRICTS_ELEMENTS, 447 CollectionSize.ANY) 448 .suppressing(suppressForCheckedSet()) 449 .createTestSuite(); 450 } 451 452 public Test testsForCheckedSortedSet() { 453 return SortedSetTestSuiteBuilder.using( 454 new TestStringSortedSetGenerator() { 455 @Override 456 public SortedSet<String> create(String[] elements) { 457 SortedSet<String> innerSet = new TreeSet<>(); 458 Collections.addAll(innerSet, elements); 459 return Collections.checkedSortedSet(innerSet, String.class); 460 } 461 }) 462 .named("checkedSortedSet/TreeSet, natural") 463 .withFeatures( 464 SetFeature.GENERAL_PURPOSE, 465 CollectionFeature.KNOWN_ORDER, 466 CollectionFeature.SERIALIZABLE, 467 CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 468 CollectionFeature.RESTRICTS_ELEMENTS, 469 CollectionSize.ANY) 470 .suppressing(suppressForCheckedSortedSet()) 471 .createTestSuite(); 472 } 473 474 public Test testsForAbstractSet() { 475 return SetTestSuiteBuilder.using( 476 new TestStringSetGenerator() { 477 @Override 478 protected Set<String> create(String[] elements) { 479 String[] deduped = dedupe(elements); 480 return new AbstractSet<String>() { 481 @Override 482 public int size() { 483 return deduped.length; 484 } 485 486 @Override 487 public Iterator<String> iterator() { 488 return MinimalCollection.of(deduped).iterator(); 489 } 490 }; 491 } 492 }) 493 .named("AbstractSet") 494 .withFeatures( 495 CollectionFeature.NONE, 496 CollectionFeature.ALLOWS_NULL_VALUES, 497 CollectionFeature.KNOWN_ORDER, // in this case, anyway 498 CollectionSize.ANY) 499 .suppressing(suppressForAbstractSet()) 500 .createTestSuite(); 501 } 502 503 public Test testsForBadlyCollidingHashSet() { 504 return SetTestSuiteBuilder.using( 505 new TestCollidingSetGenerator() { 506 @Override 507 public Set<Object> create(Object... elements) { 508 return new HashSet<>(MinimalCollection.of(elements)); 509 } 510 }) 511 .named("badly colliding HashSet") 512 .withFeatures( 513 SetFeature.GENERAL_PURPOSE, 514 CollectionFeature.ALLOWS_NULL_VALUES, 515 CollectionSize.SEVERAL) 516 .suppressing(suppressForHashSet()) 517 .createTestSuite(); 518 } 519 520 public Test testsForConcurrentSkipListSetNatural() { 521 return SetTestSuiteBuilder.using( 522 new TestStringSortedSetGenerator() { 523 @Override 524 public SortedSet<String> create(String[] elements) { 525 return new ConcurrentSkipListSet<>(MinimalCollection.of(elements)); 526 } 527 }) 528 .named("ConcurrentSkipListSet, natural") 529 .withFeatures( 530 SetFeature.GENERAL_PURPOSE, 531 CollectionFeature.SERIALIZABLE, 532 CollectionFeature.KNOWN_ORDER, 533 CollectionSize.ANY) 534 .suppressing(suppressForConcurrentSkipListSetNatural()) 535 .createTestSuite(); 536 } 537 538 public Test testsForConcurrentSkipListSetWithComparator() { 539 return SetTestSuiteBuilder.using( 540 new TestStringSortedSetGenerator() { 541 @Override 542 public SortedSet<String> create(String[] elements) { 543 SortedSet<String> set = 544 new ConcurrentSkipListSet<>(arbitraryNullFriendlyComparator()); 545 Collections.addAll(set, elements); 546 return set; 547 } 548 }) 549 .named("ConcurrentSkipListSet, with comparator") 550 .withFeatures( 551 SetFeature.GENERAL_PURPOSE, 552 CollectionFeature.SERIALIZABLE, 553 CollectionFeature.KNOWN_ORDER, 554 CollectionSize.ANY) 555 .suppressing(suppressForConcurrentSkipListSetWithComparator()) 556 .createTestSuite(); 557 } 558 559 private static String[] dedupe(String[] elements) { 560 Set<String> tmp = new LinkedHashSet<>(); 561 Collections.addAll(tmp, elements); 562 return tmp.toArray(new String[0]); 563 } 564 565 static <T> Comparator<T> arbitraryNullFriendlyComparator() { 566 return new NullFriendlyComparator<>(); 567 } 568 569 private static final class NullFriendlyComparator<T> implements Comparator<T>, Serializable { 570 @Override 571 public int compare(T left, T right) { 572 return String.valueOf(left).compareTo(String.valueOf(right)); 573 } 574 } 575}