001/*
002 * Copyright (C) 2008 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.testers;
018
019import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
020import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
021import static com.google.common.collect.testing.features.CollectionSize.ONE;
022import static com.google.common.collect.testing.features.CollectionSize.ZERO;
023import static com.google.common.collect.testing.testers.ReflectionFreeAssertThrows.assertThrows;
024import static java.util.Arrays.asList;
025
026import com.google.common.annotations.GwtCompatible;
027import com.google.common.collect.testing.AbstractCollectionTester;
028import com.google.common.collect.testing.MinimalCollection;
029import com.google.common.collect.testing.features.CollectionFeature;
030import com.google.common.collect.testing.features.CollectionSize;
031import java.util.Collection;
032import java.util.Collections;
033import java.util.List;
034import org.junit.Ignore;
035
036/**
037 * A generic JUnit test which tests {@code retainAll} operations on a collection. Can't be invoked
038 * directly; please see {@link com.google.common.collect.testing.CollectionTestSuiteBuilder}.
039 *
040 * @author Chris Povirk
041 */
042@GwtCompatible
043@Ignore("test runners must not instantiate and run this directly, only via suites we build")
044// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
045@SuppressWarnings("JUnit4ClassUsedInJUnit3")
046public class CollectionRetainAllTester<E> extends AbstractCollectionTester<E> {
047
048  /** A collection of elements to retain, along with a description for use in failure messages. */
049  private class Target {
050    private final Collection<E> toRetain;
051    private final String description;
052
053    private Target(Collection<E> toRetain, String description) {
054      this.toRetain = toRetain;
055      this.description = description;
056    }
057
058    @Override
059    public String toString() {
060      return description;
061    }
062  }
063
064  private Target empty;
065  private Target disjoint;
066  private Target superset;
067  private Target nonEmptyProperSubset;
068  private Target sameElements;
069  private Target partialOverlap;
070  private Target containsDuplicates;
071  private Target nullSingleton;
072
073  @Override
074  public void setUp() throws Exception {
075    super.setUp();
076
077    empty = new Target(emptyCollection(), "empty");
078    /*
079     * We test that nullSingleton.retainAll(disjointList) does NOT throw a
080     * NullPointerException when disjointList does not, so we can't use
081     * MinimalCollection, which throws NullPointerException on calls to
082     * contains(null).
083     */
084    List<E> disjointList = asList(e3(), e4());
085    disjoint = new Target(disjointList, "disjoint");
086    superset = new Target(MinimalCollection.of(e0(), e1(), e2(), e3(), e4()), "superset");
087    nonEmptyProperSubset = new Target(MinimalCollection.of(e1()), "subset");
088    sameElements = new Target(asList(createSamplesArray()), "sameElements");
089    containsDuplicates =
090        new Target(MinimalCollection.of(e0(), e0(), e3(), e3()), "containsDuplicates");
091    partialOverlap = new Target(MinimalCollection.of(e2(), e3()), "partialOverlap");
092    nullSingleton = new Target(Collections.<E>singleton(null), "nullSingleton");
093  }
094
095  // retainAll(empty)
096
097  @CollectionFeature.Require(SUPPORTS_REMOVE)
098  @CollectionSize.Require(ZERO)
099  public void testRetainAll_emptyPreviouslyEmpty() {
100    expectReturnsFalse(empty);
101    expectUnchanged();
102  }
103
104  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
105  @CollectionSize.Require(ZERO)
106  public void testRetainAll_emptyPreviouslyEmptyUnsupported() {
107    expectReturnsFalseOrThrows(empty);
108    expectUnchanged();
109  }
110
111  @CollectionFeature.Require(SUPPORTS_REMOVE)
112  @CollectionSize.Require(absent = ZERO)
113  public void testRetainAll_emptyPreviouslyNonEmpty() {
114    expectReturnsTrue(empty);
115    expectContents();
116    expectMissing(e0(), e1(), e2());
117  }
118
119  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
120  @CollectionSize.Require(absent = ZERO)
121  public void testRetainAll_emptyPreviouslyNonEmptyUnsupported() {
122    expectThrows(empty);
123    expectUnchanged();
124  }
125
126  // retainAll(disjoint)
127
128  @CollectionFeature.Require(SUPPORTS_REMOVE)
129  @CollectionSize.Require(ZERO)
130  public void testRetainAll_disjointPreviouslyEmpty() {
131    expectReturnsFalse(disjoint);
132    expectUnchanged();
133  }
134
135  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
136  @CollectionSize.Require(ZERO)
137  public void testRetainAll_disjointPreviouslyEmptyUnsupported() {
138    expectReturnsFalseOrThrows(disjoint);
139    expectUnchanged();
140  }
141
142  @CollectionFeature.Require(SUPPORTS_REMOVE)
143  @CollectionSize.Require(absent = ZERO)
144  public void testRetainAll_disjointPreviouslyNonEmpty() {
145    expectReturnsTrue(disjoint);
146    expectContents();
147    expectMissing(e0(), e1(), e2());
148  }
149
150  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
151  @CollectionSize.Require(absent = ZERO)
152  public void testRetainAll_disjointPreviouslyNonEmptyUnsupported() {
153    expectThrows(disjoint);
154    expectUnchanged();
155  }
156
157  // retainAll(superset)
158
159  @CollectionFeature.Require(SUPPORTS_REMOVE)
160  public void testRetainAll_superset() {
161    expectReturnsFalse(superset);
162    expectUnchanged();
163  }
164
165  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
166  public void testRetainAll_supersetUnsupported() {
167    expectReturnsFalseOrThrows(superset);
168    expectUnchanged();
169  }
170
171  // retainAll(subset)
172
173  @CollectionFeature.Require(SUPPORTS_REMOVE)
174  @CollectionSize.Require(absent = {ZERO, ONE})
175  public void testRetainAll_subset() {
176    expectReturnsTrue(nonEmptyProperSubset);
177    expectContents(nonEmptyProperSubset.toRetain);
178  }
179
180  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
181  @CollectionSize.Require(absent = {ZERO, ONE})
182  public void testRetainAll_subsetUnsupported() {
183    expectThrows(nonEmptyProperSubset);
184    expectUnchanged();
185  }
186
187  // retainAll(sameElements)
188
189  @CollectionFeature.Require(SUPPORTS_REMOVE)
190  public void testRetainAll_sameElements() {
191    expectReturnsFalse(sameElements);
192    expectUnchanged();
193  }
194
195  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
196  public void testRetainAll_sameElementsUnsupported() {
197    expectReturnsFalseOrThrows(sameElements);
198    expectUnchanged();
199  }
200
201  // retainAll(partialOverlap)
202
203  @CollectionFeature.Require(SUPPORTS_REMOVE)
204  @CollectionSize.Require(absent = {ZERO, ONE})
205  public void testRetainAll_partialOverlap() {
206    expectReturnsTrue(partialOverlap);
207    expectContents(e2());
208  }
209
210  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
211  @CollectionSize.Require(absent = {ZERO, ONE})
212  public void testRetainAll_partialOverlapUnsupported() {
213    expectThrows(partialOverlap);
214    expectUnchanged();
215  }
216
217  // retainAll(containsDuplicates)
218
219  @CollectionFeature.Require(SUPPORTS_REMOVE)
220  @CollectionSize.Require(ONE)
221  public void testRetainAll_containsDuplicatesSizeOne() {
222    expectReturnsFalse(containsDuplicates);
223    expectContents(e0());
224  }
225
226  @CollectionFeature.Require(SUPPORTS_REMOVE)
227  @CollectionSize.Require(absent = {ZERO, ONE})
228  public void testRetainAll_containsDuplicatesSizeSeveral() {
229    expectReturnsTrue(containsDuplicates);
230    expectContents(e0());
231  }
232
233  // retainAll(nullSingleton)
234
235  @CollectionFeature.Require(SUPPORTS_REMOVE)
236  @CollectionSize.Require(ZERO)
237  public void testRetainAll_nullSingletonPreviouslyEmpty() {
238    expectReturnsFalse(nullSingleton);
239    expectUnchanged();
240  }
241
242  @CollectionFeature.Require(SUPPORTS_REMOVE)
243  @CollectionSize.Require(absent = ZERO)
244  public void testRetainAll_nullSingletonPreviouslyNonEmpty() {
245    expectReturnsTrue(nullSingleton);
246    expectContents();
247  }
248
249  @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
250  @CollectionSize.Require(ONE)
251  public void testRetainAll_nullSingletonPreviouslySingletonWithNull() {
252    initCollectionWithNullElement();
253    expectReturnsFalse(nullSingleton);
254    expectContents(createArrayWithNullElement());
255  }
256
257  @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
258  @CollectionSize.Require(absent = {ZERO, ONE})
259  public void testRetainAll_nullSingletonPreviouslySeveralWithNull() {
260    initCollectionWithNullElement();
261    expectReturnsTrue(nullSingleton);
262    expectContents(nullSingleton.toRetain);
263  }
264
265  // nullSingleton.retainAll()
266
267  @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
268  @CollectionSize.Require(absent = ZERO)
269  public void testRetainAll_containsNonNullWithNull() {
270    initCollectionWithNullElement();
271    expectReturnsTrue(disjoint);
272    expectContents();
273  }
274
275  // retainAll(null)
276
277  /*
278   * AbstractCollection fails the retainAll(null) test when the subject
279   * collection is empty, but we'd still like to test retainAll(null) when we
280   * can. We split the test into empty and non-empty cases. This allows us to
281   * suppress only the former.
282   */
283
284  @CollectionFeature.Require(SUPPORTS_REMOVE)
285  @CollectionSize.Require(ZERO)
286  public void testRetainAll_nullCollectionReferenceEmptySubject() {
287    try {
288      collection.retainAll(null);
289      // Returning successfully is not ideal, but tolerated.
290    } catch (NullPointerException tolerated) {
291    }
292  }
293
294  @CollectionFeature.Require(SUPPORTS_REMOVE)
295  @CollectionSize.Require(absent = ZERO)
296  public void testRetainAll_nullCollectionReferenceNonEmptySubject() {
297    assertThrows(NullPointerException.class, () -> collection.retainAll(null));
298  }
299
300  private void expectReturnsTrue(Target target) {
301    String message = Platform.format("retainAll(%s) should return true", target);
302    assertTrue(message, collection.retainAll(target.toRetain));
303  }
304
305  private void expectReturnsFalse(Target target) {
306    String message = Platform.format("retainAll(%s) should return false", target);
307    assertFalse(message, collection.retainAll(target.toRetain));
308  }
309
310  private void expectThrows(Target target) {
311    try {
312      collection.retainAll(target.toRetain);
313      String message = Platform.format("retainAll(%s) should throw", target);
314      fail(message);
315    } catch (UnsupportedOperationException expected) {
316    }
317  }
318
319  private void expectReturnsFalseOrThrows(Target target) {
320    String message = Platform.format("retainAll(%s) should return false or throw", target);
321    try {
322      assertFalse(message, collection.retainAll(target.toRetain));
323    } catch (UnsupportedOperationException tolerated) {
324    }
325  }
326}