1 /*
2  * Copyright (C) 2009 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect.testing;
18 
19 import static com.google.common.collect.testing.testers.CollectionSpliteratorTester.getSpliteratorNotImmutableCollectionAllowsAddMethod;
20 import static com.google.common.collect.testing.testers.CollectionSpliteratorTester.getSpliteratorNotImmutableCollectionAllowsRemoveMethod;
21 import static java.util.Arrays.asList;
22 
23 import com.google.common.annotations.GwtIncompatible;
24 import com.google.common.collect.testing.features.CollectionFeature;
25 import com.google.common.collect.testing.features.CollectionSize;
26 import com.google.common.collect.testing.features.SetFeature;
27 import java.io.Serializable;
28 import java.lang.reflect.Method;
29 import java.util.AbstractSet;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Comparator;
33 import java.util.EnumSet;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.LinkedHashSet;
37 import java.util.NavigableSet;
38 import java.util.Set;
39 import java.util.SortedSet;
40 import java.util.TreeSet;
41 import java.util.concurrent.ConcurrentSkipListSet;
42 import java.util.concurrent.CopyOnWriteArraySet;
43 import junit.framework.Test;
44 import junit.framework.TestSuite;
45 
46 /**
47  * Generates a test suite covering the {@link Set} implementations in the {@link java.util} package.
48  * Can be subclassed to specify tests that should be suppressed.
49  *
50  * @author Kevin Bourrillion
51  */
52 @GwtIncompatible
53 public class TestsForSetsInJavaUtil {
suite()54   public static Test suite() {
55     return new TestsForSetsInJavaUtil().allTests();
56   }
57 
allTests()58   public Test allTests() {
59     TestSuite suite = new TestSuite("java.util Sets");
60     suite.addTest(testsForCheckedNavigableSet());
61     suite.addTest(testsForEmptySet());
62     suite.addTest(testsForEmptyNavigableSet());
63     suite.addTest(testsForEmptySortedSet());
64     suite.addTest(testsForSingletonSet());
65     suite.addTest(testsForHashSet());
66     suite.addTest(testsForLinkedHashSet());
67     suite.addTest(testsForEnumSet());
68     suite.addTest(testsForSynchronizedNavigableSet());
69     suite.addTest(testsForTreeSetNatural());
70     suite.addTest(testsForTreeSetWithComparator());
71     suite.addTest(testsForCopyOnWriteArraySet());
72     suite.addTest(testsForUnmodifiableSet());
73     suite.addTest(testsForUnmodifiableNavigableSet());
74     suite.addTest(testsForCheckedSet());
75     suite.addTest(testsForCheckedSortedSet());
76     suite.addTest(testsForAbstractSet());
77     suite.addTest(testsForBadlyCollidingHashSet());
78     suite.addTest(testsForConcurrentSkipListSetNatural());
79     suite.addTest(testsForConcurrentSkipListSetWithComparator());
80 
81     return suite;
82   }
83 
suppressForCheckedNavigableSet()84   protected Collection<Method> suppressForCheckedNavigableSet() {
85     return Collections.emptySet();
86   }
87 
suppressForEmptySet()88   protected Collection<Method> suppressForEmptySet() {
89     return Collections.emptySet();
90   }
91 
suppressForEmptyNavigableSet()92   protected Collection<Method> suppressForEmptyNavigableSet() {
93     return Collections.emptySet();
94   }
95 
suppressForEmptySortedSet()96   protected Collection<Method> suppressForEmptySortedSet() {
97     return Collections.emptySet();
98   }
99 
suppressForSingletonSet()100   protected Collection<Method> suppressForSingletonSet() {
101     return Collections.emptySet();
102   }
103 
suppressForHashSet()104   protected Collection<Method> suppressForHashSet() {
105     return Collections.emptySet();
106   }
107 
suppressForLinkedHashSet()108   protected Collection<Method> suppressForLinkedHashSet() {
109     return Collections.emptySet();
110   }
111 
suppressForEnumSet()112   protected Collection<Method> suppressForEnumSet() {
113     return Collections.emptySet();
114   }
115 
suppressForSynchronizedNavigableSet()116   protected Collection<Method> suppressForSynchronizedNavigableSet() {
117     return Collections.emptySet();
118   }
119 
suppressForTreeSetNatural()120   protected Collection<Method> suppressForTreeSetNatural() {
121     return Collections.emptySet();
122   }
123 
suppressForTreeSetWithComparator()124   protected Collection<Method> suppressForTreeSetWithComparator() {
125     return Collections.emptySet();
126   }
127 
suppressForCopyOnWriteArraySet()128   protected Collection<Method> suppressForCopyOnWriteArraySet() {
129     return asList(
130         getSpliteratorNotImmutableCollectionAllowsAddMethod(),
131         getSpliteratorNotImmutableCollectionAllowsRemoveMethod());
132   }
133 
suppressForUnmodifiableSet()134   protected Collection<Method> suppressForUnmodifiableSet() {
135     return Collections.emptySet();
136   }
137 
suppressForUnmodifiableNavigableSet()138   protected Collection<Method> suppressForUnmodifiableNavigableSet() {
139     return Collections.emptySet();
140   }
141 
suppressForCheckedSet()142   protected Collection<Method> suppressForCheckedSet() {
143     return Collections.emptySet();
144   }
145 
suppressForCheckedSortedSet()146   protected Collection<Method> suppressForCheckedSortedSet() {
147     return Collections.emptySet();
148   }
149 
suppressForAbstractSet()150   protected Collection<Method> suppressForAbstractSet() {
151     return Collections.emptySet();
152   }
153 
suppressForConcurrentSkipListSetNatural()154   protected Collection<Method> suppressForConcurrentSkipListSetNatural() {
155     return Collections.emptySet();
156   }
157 
suppressForConcurrentSkipListSetWithComparator()158   protected Collection<Method> suppressForConcurrentSkipListSetWithComparator() {
159     return Collections.emptySet();
160   }
161 
testsForCheckedNavigableSet()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 }
573