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