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_QUERIES;
020import static com.google.common.collect.testing.features.CollectionFeature.ALLOWS_NULL_VALUES;
021import static com.google.common.collect.testing.features.CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION;
022import static com.google.common.collect.testing.features.CollectionFeature.SUPPORTS_REMOVE;
023import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
024import static com.google.common.collect.testing.features.CollectionSize.ZERO;
025import static java.util.Collections.singleton;
026import static org.junit.Assert.assertThrows;
027
028import com.google.common.annotations.GwtCompatible;
029import com.google.common.collect.testing.AbstractCollectionTester;
030import com.google.common.collect.testing.MinimalCollection;
031import com.google.common.collect.testing.WrongType;
032import com.google.common.collect.testing.features.CollectionFeature;
033import com.google.common.collect.testing.features.CollectionSize;
034import java.util.AbstractSet;
035import java.util.ConcurrentModificationException;
036import java.util.Iterator;
037
038/**
039 * A generic JUnit test which tests {@code removeAll} operations on a collection. Can't be invoked
040 * directly; please see {@link com.google.common.collect.testing.CollectionTestSuiteBuilder}.
041 *
042 * @author George van den Driessche
043 * @author Chris Povirk
044 */
045@GwtCompatible
046public class CollectionRemoveAllTester<E> extends AbstractCollectionTester<E> {
047  @CollectionFeature.Require(SUPPORTS_REMOVE)
048  public void testRemoveAll_emptyCollection() {
049    assertFalse(
050        "removeAll(emptyCollection) should return false",
051        collection.removeAll(MinimalCollection.of()));
052    expectUnchanged();
053  }
054
055  @CollectionFeature.Require(SUPPORTS_REMOVE)
056  public void testRemoveAll_nonePresent() {
057    assertFalse(
058        "removeAll(disjointCollection) should return false",
059        collection.removeAll(MinimalCollection.of(e3())));
060    expectUnchanged();
061  }
062
063  @CollectionFeature.Require(SUPPORTS_REMOVE)
064  @CollectionSize.Require(absent = ZERO)
065  public void testRemoveAll_allPresent() {
066    assertTrue(
067        "removeAll(intersectingCollection) should return true",
068        collection.removeAll(MinimalCollection.of(e0())));
069    expectMissing(e0());
070  }
071
072  @CollectionFeature.Require(SUPPORTS_REMOVE)
073  @CollectionSize.Require(absent = ZERO)
074  public void testRemoveAll_somePresent() {
075    assertTrue(
076        "removeAll(intersectingCollection) should return true",
077        collection.removeAll(MinimalCollection.of(e0(), e3())));
078    expectMissing(e0());
079  }
080
081  @CollectionFeature.Require({SUPPORTS_REMOVE, FAILS_FAST_ON_CONCURRENT_MODIFICATION})
082  @CollectionSize.Require(SEVERAL)
083  public void testRemoveAllSomePresentConcurrentWithIteration() {
084    Iterator<E> iterator = collection.iterator();
085    assertTrue(collection.removeAll(MinimalCollection.of(e0(), e3())));
086    assertThrows(ConcurrentModificationException.class, iterator::next);
087  }
088
089  /** Trigger the {@code other.size() >= this.size()} case in {@link AbstractSet#removeAll}. */
090  @CollectionFeature.Require(SUPPORTS_REMOVE)
091  @CollectionSize.Require(absent = ZERO)
092  public void testRemoveAll_somePresentLargeCollectionToRemove() {
093    assertTrue(
094        "removeAll(largeIntersectingCollection) should return true",
095        collection.removeAll(MinimalCollection.of(e0(), e0(), e0(), e3(), e3(), e3())));
096    expectMissing(e0());
097  }
098
099  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
100  public void testRemoveAll_unsupportedEmptyCollection() {
101    try {
102      assertFalse(
103          "removeAll(emptyCollection) should return false or throw "
104              + "UnsupportedOperationException",
105          collection.removeAll(MinimalCollection.of()));
106    } catch (UnsupportedOperationException tolerated) {
107    }
108    expectUnchanged();
109  }
110
111  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
112  public void testRemoveAll_unsupportedNonePresent() {
113    try {
114      assertFalse(
115          "removeAll(disjointCollection) should return false or throw "
116              + "UnsupportedOperationException",
117          collection.removeAll(MinimalCollection.of(e3())));
118    } catch (UnsupportedOperationException tolerated) {
119    }
120    expectUnchanged();
121  }
122
123  @CollectionFeature.Require(absent = SUPPORTS_REMOVE)
124  @CollectionSize.Require(absent = ZERO)
125  public void testRemoveAll_unsupportedPresent() {
126    assertThrows(
127        UnsupportedOperationException.class,
128        () -> collection.removeAll(MinimalCollection.of(e0())));
129    expectUnchanged();
130    assertTrue(collection.contains(e0()));
131  }
132
133  /*
134   * AbstractCollection fails the removeAll(null) test when the subject
135   * collection is empty, but we'd still like to test removeAll(null) when we
136   * can. We split the test into empty and non-empty cases. This allows us to
137   * suppress only the former.
138   */
139
140  @CollectionFeature.Require(SUPPORTS_REMOVE)
141  @CollectionSize.Require(ZERO)
142  public void testRemoveAll_nullCollectionReferenceEmptySubject() {
143    try {
144      collection.removeAll(null);
145      // Returning successfully is not ideal, but tolerated.
146    } catch (NullPointerException tolerated) {
147    }
148  }
149
150  @CollectionFeature.Require(SUPPORTS_REMOVE)
151  @CollectionSize.Require(absent = ZERO)
152  public void testRemoveAll_nullCollectionReferenceNonEmptySubject() {
153    assertThrows(NullPointerException.class, () -> collection.removeAll(null));
154  }
155
156  @CollectionFeature.Require(value = SUPPORTS_REMOVE, absent = ALLOWS_NULL_QUERIES)
157  public void testRemoveAll_containsNullNo() {
158    MinimalCollection<?> containsNull = MinimalCollection.of((Object) null);
159    try {
160      assertFalse(
161          "removeAll(containsNull) should return false or throw",
162          collection.removeAll(containsNull));
163    } catch (NullPointerException tolerated) {
164    }
165    expectUnchanged();
166  }
167
168  @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_QUERIES})
169  public void testRemoveAll_containsNullNoButAllowed() {
170    MinimalCollection<?> containsNull = MinimalCollection.of((Object) null);
171    assertFalse("removeAll(containsNull) should return false", collection.removeAll(containsNull));
172    expectUnchanged();
173  }
174
175  @CollectionFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_VALUES})
176  @CollectionSize.Require(absent = ZERO)
177  public void testRemoveAll_containsNullYes() {
178    initCollectionWithNullElement();
179    assertTrue("removeAll(containsNull) should return true", collection.removeAll(singleton(null)));
180    // TODO: make this work with MinimalCollection
181  }
182
183  @CollectionFeature.Require(SUPPORTS_REMOVE)
184  public void testRemoveAll_containsWrongType() {
185    try {
186      assertFalse(
187          "removeAll(containsWrongType) should return false or throw",
188          collection.removeAll(MinimalCollection.of(WrongType.VALUE)));
189    } catch (ClassCastException tolerated) {
190    }
191    expectUnchanged();
192  }
193}