1 /*
2  * Copyright (C) 2008 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.testers;
18 
19 import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
20 import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
21 import static com.google.common.collect.testing.features.CollectionSize.ONE;
22 import static com.google.common.collect.testing.features.CollectionSize.ZERO;
23 
24 import com.google.common.annotations.GwtCompatible;
25 import com.google.common.collect.testing.AbstractCollectionTester;
26 import com.google.common.collect.testing.MinimalCollection;
27 import com.google.common.collect.testing.features.CollectionFeature;
28 import com.google.common.collect.testing.features.CollectionSize;
29 
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.List;
34 
35 /**
36  * A generic JUnit test which tests {@code retainAll} operations on a
37  * collection. Can't be invoked directly; please see
38  * {@link com.google.common.collect.testing.CollectionTestSuiteBuilder}.
39  *
40  * @author Chris Povirk
41  */
42 @SuppressWarnings("unchecked") // too many "unchecked generic array creations"
43 @GwtCompatible
44 public class CollectionRetainAllTester<E> extends AbstractCollectionTester<E> {
45 
46   /**
47    * A collection of elements to retain, along with a description for use in
48    * failure messages.
49    */
50   private class Target {
51     private final Collection<E> toRetain;
52     private final String description;
53 
Target(Collection<E> toRetain, String description)54     private Target(Collection<E> toRetain, String description) {
55       this.toRetain = toRetain;
56       this.description = description;
57     }
58 
toString()59     @Override public String toString() {
60       return description;
61     }
62   }
63 
64   private Target empty;
65   private Target disjoint;
66   private Target superset;
67   private Target nonEmptyProperSubset;
68   private Target sameElements;
69   private Target partialOverlap;
70   private Target containsDuplicates;
71   private Target nullSingleton;
72 
setUp()73   @Override public void setUp() throws Exception {
74     super.setUp();
75 
76     empty = new Target(emptyCollection(), "empty");
77     /*
78      * We test that nullSingleton.retainAll(disjointList) does NOT throw a
79      * NullPointerException when disjointList does not, so we can't use
80      * MinimalCollection, which throws NullPointerException on calls to
81      * contains(null).
82      */
83     List<E> disjointList = Arrays.asList(samples.e3, samples.e4);
84     disjoint
85         = new Target(disjointList, "disjoint");
86     superset
87         = new Target(MinimalCollection.of(
88             samples.e0, samples.e1, samples.e2, samples.e3, samples.e4),
89             "superset");
90     nonEmptyProperSubset
91         = new Target(MinimalCollection.of(samples.e1), "subset");
92     sameElements
93         = new Target(Arrays.asList(createSamplesArray()), "sameElements");
94     containsDuplicates = new Target(
95         MinimalCollection.of(samples.e0, samples.e0, samples.e3, samples.e3),
96         "containsDuplicates");
97     partialOverlap
98         = new Target(MinimalCollection.of(samples.e2, samples.e3),
99             "partialOverlap");
100     nullSingleton
101         = new Target(Collections.<E>singleton(null), "nullSingleton");
102   }
103 
104   // retainAll(empty)
105 
106   @CollectionFeature.Require(SUPPORTS_REMOVE)
107   @CollectionSize.Require(ZERO)
testRetainAll_emptyPreviouslyEmpty()108   public void testRetainAll_emptyPreviouslyEmpty() {
109     expectReturnsFalse(empty);
110     expectUnchanged();
111   }
112 
113   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
114   @CollectionSize.Require(ZERO)
testRetainAll_emptyPreviouslyEmptyUnsupported()115   public void testRetainAll_emptyPreviouslyEmptyUnsupported() {
116     expectReturnsFalseOrThrows(empty);
117     expectUnchanged();
118   }
119 
120   @CollectionFeature.Require(SUPPORTS_REMOVE)
121   @CollectionSize.Require(absent = ZERO)
testRetainAll_emptyPreviouslyNonEmpty()122   public void testRetainAll_emptyPreviouslyNonEmpty() {
123     expectReturnsTrue(empty);
124     expectContents();
125     expectMissing(samples.e0, samples.e1, samples.e2);
126   }
127 
128   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
129   @CollectionSize.Require(absent = ZERO)
testRetainAll_emptyPreviouslyNonEmptyUnsupported()130   public void testRetainAll_emptyPreviouslyNonEmptyUnsupported() {
131     expectThrows(empty);
132     expectUnchanged();
133   }
134 
135   // retainAll(disjoint)
136 
137   @CollectionFeature.Require(SUPPORTS_REMOVE)
138   @CollectionSize.Require(ZERO)
testRetainAll_disjointPreviouslyEmpty()139   public void testRetainAll_disjointPreviouslyEmpty() {
140     expectReturnsFalse(disjoint);
141     expectUnchanged();
142   }
143 
144   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
145   @CollectionSize.Require(ZERO)
testRetainAll_disjointPreviouslyEmptyUnsupported()146   public void testRetainAll_disjointPreviouslyEmptyUnsupported() {
147     expectReturnsFalseOrThrows(disjoint);
148     expectUnchanged();
149   }
150 
151   @CollectionFeature.Require(SUPPORTS_REMOVE)
152   @CollectionSize.Require(absent = ZERO)
testRetainAll_disjointPreviouslyNonEmpty()153   public void testRetainAll_disjointPreviouslyNonEmpty() {
154     expectReturnsTrue(disjoint);
155     expectContents();
156     expectMissing(samples.e0, samples.e1, samples.e2);
157   }
158 
159   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
160   @CollectionSize.Require(absent = ZERO)
testRetainAll_disjointPreviouslyNonEmptyUnsupported()161   public void testRetainAll_disjointPreviouslyNonEmptyUnsupported() {
162     expectThrows(disjoint);
163     expectUnchanged();
164   }
165 
166   // retainAll(superset)
167 
168   @CollectionFeature.Require(SUPPORTS_REMOVE)
testRetainAll_superset()169   public void testRetainAll_superset() {
170     expectReturnsFalse(superset);
171     expectUnchanged();
172   }
173 
174   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testRetainAll_supersetUnsupported()175   public void testRetainAll_supersetUnsupported() {
176     expectReturnsFalseOrThrows(superset);
177     expectUnchanged();
178   }
179 
180   // retainAll(subset)
181 
182   @CollectionFeature.Require(SUPPORTS_REMOVE)
183   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_subset()184   public void testRetainAll_subset() {
185     expectReturnsTrue(nonEmptyProperSubset);
186     expectContents(nonEmptyProperSubset.toRetain);
187   }
188 
189   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
190   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_subsetUnsupported()191   public void testRetainAll_subsetUnsupported() {
192     expectThrows(nonEmptyProperSubset);
193     expectUnchanged();
194   }
195 
196   // retainAll(sameElements)
197 
198   @CollectionFeature.Require(SUPPORTS_REMOVE)
testRetainAll_sameElements()199   public void testRetainAll_sameElements() {
200     expectReturnsFalse(sameElements);
201     expectUnchanged();
202   }
203 
204   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
testRetainAll_sameElementsUnsupported()205   public void testRetainAll_sameElementsUnsupported() {
206     expectReturnsFalseOrThrows(sameElements);
207     expectUnchanged();
208   }
209 
210   // retainAll(partialOverlap)
211 
212   @CollectionFeature.Require(SUPPORTS_REMOVE)
213   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_partialOverlap()214   public void testRetainAll_partialOverlap() {
215     expectReturnsTrue(partialOverlap);
216     expectContents(samples.e2);
217   }
218 
219   @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
220   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_partialOverlapUnsupported()221   public void testRetainAll_partialOverlapUnsupported() {
222     expectThrows(partialOverlap);
223     expectUnchanged();
224   }
225 
226   // retainAll(containsDuplicates)
227 
228   @CollectionFeature.Require(SUPPORTS_REMOVE)
229   @CollectionSize.Require(ONE)
testRetainAll_containsDuplicatesSizeOne()230   public void testRetainAll_containsDuplicatesSizeOne() {
231     expectReturnsFalse(containsDuplicates);
232     expectContents(samples.e0);
233   }
234 
235   @CollectionFeature.Require(SUPPORTS_REMOVE)
236   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_containsDuplicatesSizeSeveral()237   public void testRetainAll_containsDuplicatesSizeSeveral() {
238     expectReturnsTrue(containsDuplicates);
239     expectContents(samples.e0);
240   }
241 
242   // retainAll(nullSingleton)
243 
244   @CollectionFeature.Require(SUPPORTS_REMOVE)
245   @CollectionSize.Require(ZERO)
testRetainAll_nullSingletonPreviouslyEmpty()246   public void testRetainAll_nullSingletonPreviouslyEmpty() {
247     expectReturnsFalse(nullSingleton);
248     expectUnchanged();
249   }
250 
251   @CollectionFeature.Require(SUPPORTS_REMOVE)
252   @CollectionSize.Require(absent = ZERO)
testRetainAll_nullSingletonPreviouslyNonEmpty()253   public void testRetainAll_nullSingletonPreviouslyNonEmpty() {
254     expectReturnsTrue(nullSingleton);
255     expectContents();
256   }
257 
258   @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
259   @CollectionSize.Require(ONE)
testRetainAll_nullSingletonPreviouslySingletonWithNull()260   public void testRetainAll_nullSingletonPreviouslySingletonWithNull() {
261     initCollectionWithNullElement();
262     expectReturnsFalse(nullSingleton);
263     expectContents(createArrayWithNullElement());
264   }
265 
266   @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
267   @CollectionSize.Require(absent = {ZERO, ONE})
testRetainAll_nullSingletonPreviouslySeveralWithNull()268   public void testRetainAll_nullSingletonPreviouslySeveralWithNull() {
269     initCollectionWithNullElement();
270     expectReturnsTrue(nullSingleton);
271     expectContents(nullSingleton.toRetain);
272   }
273 
274   // nullSingleton.retainAll()
275 
276   @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
277   @CollectionSize.Require(absent = ZERO)
testRetainAll_containsNonNullWithNull()278   public void testRetainAll_containsNonNullWithNull() {
279     initCollectionWithNullElement();
280     expectReturnsTrue(disjoint);
281     expectContents();
282   }
283 
284   // retainAll(null)
285 
286   /*
287    * AbstractCollection fails the retainAll(null) test when the subject
288    * collection is empty, but we'd still like to test retainAll(null) when we
289    * can. We split the test into empty and non-empty cases. This allows us to
290    * suppress only the former.
291    */
292 
293   @CollectionFeature.Require(SUPPORTS_REMOVE)
294   @CollectionSize.Require(ZERO)
testRetainAll_nullCollectionReferenceEmptySubject()295   public void testRetainAll_nullCollectionReferenceEmptySubject() {
296     try {
297       collection.retainAll(null);
298       // Returning successfully is not ideal, but tolerated.
299     } catch (NullPointerException expected) {
300     }
301   }
302 
303   @CollectionFeature.Require(SUPPORTS_REMOVE)
304   @CollectionSize.Require(absent = ZERO)
testRetainAll_nullCollectionReferenceNonEmptySubject()305   public void testRetainAll_nullCollectionReferenceNonEmptySubject() {
306     try {
307       collection.retainAll(null);
308       fail("retainAll(null) should throw NullPointerException");
309     } catch (NullPointerException expected) {
310     }
311   }
312 
expectReturnsTrue(Target target)313   private void expectReturnsTrue(Target target) {
314     String message
315         = Platform.format("retainAll(%s) should return true", target);
316     assertTrue(message, collection.retainAll(target.toRetain));
317   }
318 
expectReturnsFalse(Target target)319   private void expectReturnsFalse(Target target) {
320     String message
321         = Platform.format("retainAll(%s) should return false", target);
322     assertFalse(message, collection.retainAll(target.toRetain));
323   }
324 
expectThrows(Target target)325   private void expectThrows(Target target) {
326     try {
327       collection.retainAll(target.toRetain);
328       String message = Platform.format("retainAll(%s) should throw", target);
329       fail(message);
330     } catch (UnsupportedOperationException expected) {
331     }
332   }
333 
expectReturnsFalseOrThrows(Target target)334   private void expectReturnsFalseOrThrows(Target target) {
335     String message
336         = Platform.format("retainAll(%s) should return false or throw", target);
337     try {
338       assertFalse(message, collection.retainAll(target.toRetain));
339     } catch (UnsupportedOperationException tolerated) {
340     }
341   }
342 }
343