View Javadoc
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
48   * {@link java.util} package. Can be subclassed to specify tests that should
49   * be suppressed.
50   *
51   * @author Kevin Bourrillion
52   */
53  @GwtIncompatible
54  public class TestsForSetsInJavaUtil {
55    public static Test suite() {
56      return new TestsForSetsInJavaUtil().allTests();
57    }
58  
59    public Test allTests() {
60      TestSuite suite = new TestSuite("java.util Sets");
61      suite.addTest(testsForCheckedNavigableSet());
62      suite.addTest(testsForEmptySet());
63      suite.addTest(testsForEmptyNavigableSet());
64      suite.addTest(testsForEmptySortedSet());
65      suite.addTest(testsForSingletonSet());
66      suite.addTest(testsForHashSet());
67      suite.addTest(testsForLinkedHashSet());
68      suite.addTest(testsForEnumSet());
69      suite.addTest(testsForSynchronizedNavigableSet());
70      suite.addTest(testsForTreeSetNatural());
71      suite.addTest(testsForTreeSetWithComparator());
72      suite.addTest(testsForCopyOnWriteArraySet());
73      suite.addTest(testsForUnmodifiableSet());
74      suite.addTest(testsForUnmodifiableNavigableSet());
75      suite.addTest(testsForCheckedSet());
76      suite.addTest(testsForCheckedSortedSet());
77      suite.addTest(testsForAbstractSet());
78      suite.addTest(testsForBadlyCollidingHashSet());
79      suite.addTest(testsForConcurrentSkipListSetNatural());
80      suite.addTest(testsForConcurrentSkipListSetWithComparator());
81  
82      return suite;
83    }
84  
85    protected Collection<Method> suppressForCheckedNavigableSet() {
86      return Collections.emptySet();
87    }
88  
89    protected Collection<Method> suppressForEmptySet() {
90      return Collections.emptySet();
91    }
92  
93    protected Collection<Method> suppressForEmptyNavigableSet() {
94      return Collections.emptySet();
95    }
96  
97    protected Collection<Method> suppressForEmptySortedSet() {
98      return Collections.emptySet();
99    }
100 
101   protected Collection<Method> suppressForSingletonSet() {
102     return Collections.emptySet();
103   }
104 
105   protected Collection<Method> suppressForHashSet() {
106     return Collections.emptySet();
107   }
108 
109   protected Collection<Method> suppressForLinkedHashSet() {
110     return Collections.emptySet();
111   }
112 
113   protected Collection<Method> suppressForEnumSet() {
114     return Collections.emptySet();
115   }
116 
117   protected Collection<Method> suppressForSynchronizedNavigableSet() {
118     return Collections.emptySet();
119   }
120 
121   protected Collection<Method> suppressForTreeSetNatural() {
122     return Collections.emptySet();
123   }
124 
125   protected Collection<Method> suppressForTreeSetWithComparator() {
126     return Collections.emptySet();
127   }
128 
129   protected Collection<Method> suppressForCopyOnWriteArraySet() {
130     return asList(
131         getSpliteratorNotImmutableCollectionAllowsAddMethod(),
132         getSpliteratorNotImmutableCollectionAllowsRemoveMethod());
133   }
134 
135   protected Collection<Method> suppressForUnmodifiableSet() {
136     return Collections.emptySet();
137   }
138 
139   protected Collection<Method> suppressForUnmodifiableNavigableSet() {
140     return Collections.emptySet();
141   }
142 
143   protected Collection<Method> suppressForCheckedSet() {
144     return Collections.emptySet();
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);
305    * does not test the 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 
328   public Test testsForTreeSetNatural() {
329     return NavigableSetTestSuiteBuilder.using(
330             new TestStringSortedSetGenerator() {
331               @Override
332               public SortedSet<String> create(String[] elements) {
333                 return new TreeSet<>(MinimalCollection.of(elements));
334               }
335             })
336         .named("TreeSet, natural")
337         .withFeatures(
338             SetFeature.GENERAL_PURPOSE,
339             CollectionFeature.SERIALIZABLE,
340             CollectionFeature.KNOWN_ORDER,
341             CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
342             CollectionSize.ANY)
343         .suppressing(suppressForTreeSetNatural())
344         .createTestSuite();
345   }
346 
347   public Test testsForTreeSetWithComparator() {
348     return NavigableSetTestSuiteBuilder.using(
349             new TestStringSortedSetGenerator() {
350               @Override
351               public SortedSet<String> create(String[] elements) {
352                 SortedSet<String> set = new TreeSet<>(arbitraryNullFriendlyComparator());
353                 Collections.addAll(set, elements);
354                 return set;
355               }
356             })
357         .named("TreeSet, with comparator")
358         .withFeatures(
359             SetFeature.GENERAL_PURPOSE,
360             CollectionFeature.SERIALIZABLE,
361             CollectionFeature.ALLOWS_NULL_VALUES,
362             CollectionFeature.KNOWN_ORDER,
363             CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
364             CollectionSize.ANY)
365         .suppressing(suppressForTreeSetWithComparator())
366         .createTestSuite();
367   }
368 
369   public Test testsForCopyOnWriteArraySet() {
370     return SetTestSuiteBuilder.using(
371             new TestStringSetGenerator() {
372               @Override
373               public Set<String> create(String[] elements) {
374                 return new CopyOnWriteArraySet<>(MinimalCollection.of(elements));
375               }
376             })
377         .named("CopyOnWriteArraySet")
378         .withFeatures(
379             CollectionFeature.SUPPORTS_ADD,
380             CollectionFeature.SUPPORTS_REMOVE,
381             CollectionFeature.SERIALIZABLE,
382             CollectionFeature.ALLOWS_NULL_VALUES,
383             CollectionFeature.KNOWN_ORDER,
384             CollectionSize.ANY)
385         .suppressing(suppressForCopyOnWriteArraySet())
386         .createTestSuite();
387   }
388 
389   public Test testsForUnmodifiableSet() {
390     return SetTestSuiteBuilder.using(
391             new TestStringSetGenerator() {
392               @Override
393               public Set<String> create(String[] elements) {
394                 Set<String> innerSet = new HashSet<>();
395                 Collections.addAll(innerSet, elements);
396                 return Collections.unmodifiableSet(innerSet);
397               }
398             })
399         .named("unmodifiableSet/HashSet")
400         .withFeatures(
401             CollectionFeature.NONE,
402             CollectionFeature.SERIALIZABLE,
403             CollectionFeature.ALLOWS_NULL_VALUES,
404             CollectionSize.ANY)
405         .suppressing(suppressForUnmodifiableSet())
406         .createTestSuite();
407   }
408 
409   public Test testsForUnmodifiableNavigableSet() {
410     return SetTestSuiteBuilder.using(
411             new TestStringSortedSetGenerator() {
412               @Override
413               public NavigableSet<String> create(String[] elements) {
414                 NavigableSet<String> innerSet = new TreeSet<>();
415                 Collections.addAll(innerSet, elements);
416                 return Collections.unmodifiableNavigableSet(innerSet);
417               }
418             })
419         .named("unmodifiableNavigableSet/TreeSet, natural")
420         .withFeatures(
421             CollectionFeature.KNOWN_ORDER,
422             CollectionFeature.RESTRICTS_ELEMENTS,
423             CollectionFeature.SERIALIZABLE,
424             CollectionSize.ANY)
425         .suppressing(suppressForUnmodifiableNavigableSet())
426         .createTestSuite();
427   }
428 
429   public Test testsForCheckedSet() {
430     return SetTestSuiteBuilder.using(
431             new TestStringSetGenerator() {
432               @Override
433               public Set<String> create(String[] elements) {
434                 Set<String> innerSet = new HashSet<>();
435                 Collections.addAll(innerSet, elements);
436                 return Collections.checkedSet(innerSet, String.class);
437               }
438             })
439         .named("checkedSet/HashSet")
440         .withFeatures(
441             SetFeature.GENERAL_PURPOSE,
442             CollectionFeature.SERIALIZABLE,
443             CollectionFeature.ALLOWS_NULL_VALUES,
444             CollectionFeature.RESTRICTS_ELEMENTS,
445             CollectionSize.ANY)
446         .suppressing(suppressForCheckedSet())
447         .createTestSuite();
448   }
449 
450   public Test testsForCheckedSortedSet() {
451     return SortedSetTestSuiteBuilder.using(
452             new TestStringSortedSetGenerator() {
453               @Override
454               public SortedSet<String> create(String[] elements) {
455                 SortedSet<String> innerSet = new TreeSet<>();
456                 Collections.addAll(innerSet, elements);
457                 return Collections.checkedSortedSet(innerSet, String.class);
458               }
459             })
460         .named("checkedSortedSet/TreeSet, natural")
461         .withFeatures(
462             SetFeature.GENERAL_PURPOSE,
463             CollectionFeature.KNOWN_ORDER,
464             CollectionFeature.SERIALIZABLE,
465             CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
466             CollectionFeature.RESTRICTS_ELEMENTS,
467             CollectionSize.ANY)
468         .suppressing(suppressForCheckedSortedSet())
469         .createTestSuite();
470   }
471 
472   public Test testsForAbstractSet() {
473     return SetTestSuiteBuilder.using(
474             new TestStringSetGenerator() {
475               @Override
476               protected Set<String> create(String[] elements) {
477                 final String[] deduped = dedupe(elements);
478                 return new AbstractSet<String>() {
479                   @Override
480                   public int size() {
481                     return deduped.length;
482                   }
483 
484                   @Override
485                   public Iterator<String> iterator() {
486                     return MinimalCollection.of(deduped).iterator();
487                   }
488                 };
489               }
490             })
491         .named("AbstractSet")
492         .withFeatures(
493             CollectionFeature.NONE,
494             CollectionFeature.ALLOWS_NULL_VALUES,
495             CollectionFeature.KNOWN_ORDER, // in this case, anyway
496             CollectionSize.ANY)
497         .suppressing(suppressForAbstractSet())
498         .createTestSuite();
499   }
500 
501   public Test testsForBadlyCollidingHashSet() {
502     return SetTestSuiteBuilder.using(
503             new TestCollidingSetGenerator() {
504               @Override
505               public Set<Object> create(Object... elements) {
506                 return new HashSet<>(MinimalCollection.of(elements));
507               }
508             })
509         .named("badly colliding HashSet")
510         .withFeatures(
511             SetFeature.GENERAL_PURPOSE,
512             CollectionFeature.ALLOWS_NULL_VALUES,
513             CollectionSize.SEVERAL)
514         .suppressing(suppressForHashSet())
515         .createTestSuite();
516   }
517 
518   public Test testsForConcurrentSkipListSetNatural() {
519     return SetTestSuiteBuilder.using(
520             new TestStringSortedSetGenerator() {
521               @Override
522               public SortedSet<String> create(String[] elements) {
523                 return new ConcurrentSkipListSet<>(MinimalCollection.of(elements));
524               }
525             })
526         .named("ConcurrentSkipListSet, natural")
527         .withFeatures(
528             SetFeature.GENERAL_PURPOSE,
529             CollectionFeature.SERIALIZABLE,
530             CollectionFeature.KNOWN_ORDER,
531             CollectionSize.ANY)
532         .suppressing(suppressForConcurrentSkipListSetNatural())
533         .createTestSuite();
534   }
535 
536   public Test testsForConcurrentSkipListSetWithComparator() {
537     return SetTestSuiteBuilder.using(
538             new TestStringSortedSetGenerator() {
539               @Override
540               public SortedSet<String> create(String[] elements) {
541                 SortedSet<String> set =
542                     new ConcurrentSkipListSet<>(arbitraryNullFriendlyComparator());
543                 Collections.addAll(set, elements);
544                 return set;
545               }
546             })
547         .named("ConcurrentSkipListSet, with comparator")
548         .withFeatures(
549             SetFeature.GENERAL_PURPOSE,
550             CollectionFeature.SERIALIZABLE,
551             CollectionFeature.KNOWN_ORDER,
552             CollectionSize.ANY)
553         .suppressing(suppressForConcurrentSkipListSetWithComparator())
554         .createTestSuite();
555   }
556 
557   private static String[] dedupe(String[] elements) {
558     Set<String> tmp = new LinkedHashSet<>();
559     Collections.addAll(tmp, elements);
560     return tmp.toArray(new String[0]);
561   }
562 
563   static <T> Comparator<T> arbitraryNullFriendlyComparator() {
564     return new NullFriendlyComparator<T>();
565   }
566 
567   private static final class NullFriendlyComparator<T> implements Comparator<T>, Serializable {
568     @Override
569     public int compare(T left, T right) {
570       return String.valueOf(left).compareTo(String.valueOf(right));
571     }
572   }
573 }