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