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}