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.Helpers.copyToList;
020import static com.google.common.collect.testing.Helpers.getMethod;
021import static com.google.common.collect.testing.features.CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS;
022import static com.google.common.collect.testing.features.CollectionSize.ONE;
023import static com.google.common.collect.testing.features.CollectionSize.ZERO;
024import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_ADD_WITH_INDEX;
025import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_REMOVE_WITH_INDEX;
026import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_SET;
027import static com.google.common.collect.testing.testers.ReflectionFreeAssertThrows.assertThrows;
028import static java.util.Arrays.asList;
029import static java.util.Collections.emptyList;
030import static java.util.Collections.singletonList;
031
032import com.google.common.annotations.GwtCompatible;
033import com.google.common.annotations.GwtIncompatible;
034import com.google.common.annotations.J2ktIncompatible;
035import com.google.common.collect.testing.features.CollectionFeature;
036import com.google.common.collect.testing.features.CollectionSize;
037import com.google.common.collect.testing.features.ListFeature;
038import com.google.common.testing.SerializableTester;
039import java.lang.reflect.Method;
040import java.util.List;
041import java.util.concurrent.CopyOnWriteArrayList;
042import org.junit.Ignore;
043
044/**
045 * A generic JUnit test which tests {@code subList()} operations on a list. Can't be invoked
046 * directly; please see {@link com.google.common.collect.testing.ListTestSuiteBuilder}.
047 *
048 * @author Chris Povirk
049 */
050@GwtCompatible(emulated = true)
051@Ignore("test runners must not instantiate and run this directly, only via suites we build")
052// @Ignore affects the Android test runner, which respects JUnit 4 annotations on JUnit 3 tests.
053@SuppressWarnings("JUnit4ClassUsedInJUnit3")
054public class ListSubListTester<E> extends AbstractListTester<E> {
055  public void testSubList_startNegative() {
056    assertThrows(IndexOutOfBoundsException.class, () -> getList().subList(-1, 0));
057  }
058
059  public void testSubList_endTooLarge() {
060    assertThrows(IndexOutOfBoundsException.class, () -> getList().subList(0, getNumElements() + 1));
061  }
062
063  public void testSubList_startGreaterThanEnd() {
064    try {
065      getList().subList(1, 0);
066      fail("subList(1, 0) should throw");
067    } catch (IndexOutOfBoundsException expected) {
068    } catch (IllegalArgumentException expected) {
069      /*
070       * The subList() docs claim that this should be an
071       * IndexOutOfBoundsException, but many JDK implementations throw
072       * IllegalArgumentException:
073       * https://bugs.openjdk.org/browse/JDK-4506427
074       */
075    }
076  }
077
078  public void testSubList_empty() {
079    assertEquals("subList(0, 0) should be empty", emptyList(), getList().subList(0, 0));
080  }
081
082  public void testSubList_entireList() {
083    assertEquals(
084        "subList(0, size) should be equal to the original list",
085        getList(),
086        getList().subList(0, getNumElements()));
087  }
088
089  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
090  @CollectionSize.Require(absent = ZERO)
091  public void testSubList_subListRemoveAffectsOriginal() {
092    List<E> subList = getList().subList(0, 1);
093    subList.remove(0);
094    List<E> expected = asList(createSamplesArray()).subList(1, getNumElements());
095    expectContents(expected);
096  }
097
098  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
099  @CollectionSize.Require(absent = ZERO)
100  public void testSubList_subListClearAffectsOriginal() {
101    List<E> subList = getList().subList(0, 1);
102    subList.clear();
103    List<E> expected = asList(createSamplesArray()).subList(1, getNumElements());
104    expectContents(expected);
105  }
106
107  @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
108  public void testSubList_subListAddAffectsOriginal() {
109    List<E> subList = getList().subList(0, 0);
110    subList.add(e3());
111    expectAdded(0, e3());
112  }
113
114  @ListFeature.Require(SUPPORTS_SET)
115  @CollectionSize.Require(absent = ZERO)
116  public void testSubList_subListSetAffectsOriginal() {
117    List<E> subList = getList().subList(0, 1);
118    subList.set(0, e3());
119    List<E> expected = copyToList(createSamplesArray());
120    expected.set(0, e3());
121    expectContents(expected);
122  }
123
124  @ListFeature.Require(SUPPORTS_SET)
125  @CollectionSize.Require(absent = ZERO)
126  public void testSubList_originalListSetAffectsSubList() {
127    List<E> subList = getList().subList(0, 1);
128    getList().set(0, e3());
129    assertEquals(
130        "A set() call to a list after a sublist has been created "
131            + "should be reflected in the sublist",
132        singletonList(e3()),
133        subList);
134  }
135
136  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
137  @CollectionSize.Require(absent = {ZERO, ONE})
138  public void testSubList_subListRemoveAffectsOriginalLargeList() {
139    List<E> subList = getList().subList(1, 3);
140    subList.remove(e2());
141    List<E> expected = copyToList(createSamplesArray());
142    expected.remove(2);
143    expectContents(expected);
144  }
145
146  @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
147  @CollectionSize.Require(absent = {ZERO, ONE})
148  public void testSubList_subListAddAtIndexAffectsOriginalLargeList() {
149    List<E> subList = getList().subList(2, 3);
150    subList.add(0, e3());
151    expectAdded(2, e3());
152  }
153
154  @ListFeature.Require(SUPPORTS_SET)
155  @CollectionSize.Require(absent = {ZERO, ONE})
156  public void testSubList_subListSetAffectsOriginalLargeList() {
157    List<E> subList = getList().subList(1, 2);
158    subList.set(0, e3());
159    List<E> expected = copyToList(createSamplesArray());
160    expected.set(1, e3());
161    expectContents(expected);
162  }
163
164  @ListFeature.Require(SUPPORTS_SET)
165  @CollectionSize.Require(absent = {ZERO, ONE})
166  public void testSubList_originalListSetAffectsSubListLargeList() {
167    List<E> subList = getList().subList(1, 3);
168    getList().set(1, e3());
169    assertEquals(
170        "A set() call to a list after a sublist has been created "
171            + "should be reflected in the sublist",
172        asList(e3(), e2()),
173        subList);
174  }
175
176  public void testSubList_ofSubListEmpty() {
177    List<E> subList = getList().subList(0, 0).subList(0, 0);
178    assertEquals("subList(0, 0).subList(0, 0) should be an empty list", emptyList(), subList);
179  }
180
181  @CollectionSize.Require(absent = {ZERO, ONE})
182  public void testSubList_ofSubListNonEmpty() {
183    List<E> subList = getList().subList(0, 2).subList(1, 2);
184    assertEquals(
185        "subList(0, 2).subList(1, 2) "
186            + "should be a single-element list of the element at index 1",
187        singletonList(getOrderedElements().get(1)),
188        subList);
189  }
190
191  @CollectionSize.Require(absent = {ZERO})
192  public void testSubList_size() {
193    List<E> list = getList();
194    int size = getNumElements();
195    assertEquals(size, list.subList(0, size).size());
196    assertEquals(size - 1, list.subList(0, size - 1).size());
197    assertEquals(size - 1, list.subList(1, size).size());
198    assertEquals(0, list.subList(size, size).size());
199    assertEquals(0, list.subList(0, 0).size());
200  }
201
202  @CollectionSize.Require(absent = {ZERO})
203  public void testSubList_isEmpty() {
204    List<E> list = getList();
205    int size = getNumElements();
206    for (List<E> subList :
207        asList(
208            list.subList(0, size),
209            list.subList(0, size - 1),
210            list.subList(1, size),
211            list.subList(0, 0),
212            list.subList(size, size))) {
213      assertEquals(subList.size() == 0, subList.isEmpty());
214    }
215  }
216
217  @CollectionSize.Require(absent = {ZERO, ONE})
218  public void testSubList_get() {
219    List<E> list = getList();
220    int size = getNumElements();
221    List<E> copy = list.subList(0, size);
222    List<E> head = list.subList(0, size - 1);
223    List<E> tail = list.subList(1, size);
224    assertEquals(list.get(0), copy.get(0));
225    assertEquals(list.get(size - 1), copy.get(size - 1));
226    assertEquals(list.get(1), tail.get(0));
227    assertEquals(list.get(size - 1), tail.get(size - 2));
228    assertEquals(list.get(0), head.get(0));
229    assertEquals(list.get(size - 2), head.get(size - 2));
230    for (List<E> subList : asList(copy, head, tail)) {
231      for (int index : asList(-1, subList.size())) {
232        assertThrows(IndexOutOfBoundsException.class, () -> subList.get(index));
233      }
234    }
235  }
236
237  @CollectionSize.Require(absent = {ZERO, ONE})
238  public void testSubList_contains() {
239    List<E> list = getList();
240    int size = getNumElements();
241    List<E> copy = list.subList(0, size);
242    List<E> head = list.subList(0, size - 1);
243    List<E> tail = list.subList(1, size);
244    assertTrue(copy.contains(list.get(0)));
245    assertTrue(head.contains(list.get(0)));
246    assertTrue(tail.contains(list.get(1)));
247    // The following assumes all elements are distinct.
248    assertTrue(copy.contains(list.get(size - 1)));
249    assertTrue(head.contains(list.get(size - 2)));
250    assertTrue(tail.contains(list.get(size - 1)));
251    assertFalse(head.contains(list.get(size - 1)));
252    assertFalse(tail.contains(list.get(0)));
253  }
254
255  @CollectionSize.Require(absent = {ZERO, ONE})
256  public void testSubList_indexOf() {
257    List<E> list = getList();
258    int size = getNumElements();
259    List<E> copy = list.subList(0, size);
260    List<E> head = list.subList(0, size - 1);
261    List<E> tail = list.subList(1, size);
262    assertEquals(0, copy.indexOf(list.get(0)));
263    assertEquals(0, head.indexOf(list.get(0)));
264    assertEquals(0, tail.indexOf(list.get(1)));
265    // The following assumes all elements are distinct.
266    assertEquals(size - 1, copy.indexOf(list.get(size - 1)));
267    assertEquals(size - 2, head.indexOf(list.get(size - 2)));
268    assertEquals(size - 2, tail.indexOf(list.get(size - 1)));
269    assertEquals(-1, head.indexOf(list.get(size - 1)));
270    assertEquals(-1, tail.indexOf(list.get(0)));
271  }
272
273  @CollectionSize.Require(absent = {ZERO, ONE})
274  public void testSubList_lastIndexOf() {
275    List<E> list = getList();
276    int size = list.size();
277    List<E> copy = list.subList(0, size);
278    List<E> head = list.subList(0, size - 1);
279    List<E> tail = list.subList(1, size);
280    assertEquals(size - 1, copy.lastIndexOf(list.get(size - 1)));
281    assertEquals(size - 2, head.lastIndexOf(list.get(size - 2)));
282    assertEquals(size - 2, tail.lastIndexOf(list.get(size - 1)));
283    // The following assumes all elements are distinct.
284    assertEquals(0, copy.lastIndexOf(list.get(0)));
285    assertEquals(0, head.lastIndexOf(list.get(0)));
286    assertEquals(0, tail.lastIndexOf(list.get(1)));
287    assertEquals(-1, head.lastIndexOf(list.get(size - 1)));
288    assertEquals(-1, tail.lastIndexOf(list.get(0)));
289  }
290
291  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
292  public void testReserializeWholeSubList() {
293    SerializableTester.reserializeAndAssert(getList().subList(0, getNumElements()));
294  }
295
296  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
297  public void testReserializeEmptySubList() {
298    SerializableTester.reserializeAndAssert(getList().subList(0, 0));
299  }
300
301  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
302  @CollectionSize.Require(absent = {ZERO, ONE})
303  public void testReserializeSubList() {
304    SerializableTester.reserializeAndAssert(getList().subList(0, 2));
305  }
306
307  /**
308   * Returns the {@link Method} instance for {@link #testSubList_originalListSetAffectsSubList()} so
309   * that tests of {@link CopyOnWriteArrayList} can suppress them with {@code
310   * FeatureSpecificTestSuiteBuilder.suppressing()} until <a
311   * href="https://bugs.openjdk.org/browse/JDK-6570631">JDK-6570631</a> is fixed.
312   */
313  @J2ktIncompatible
314  @GwtIncompatible // reflection
315  public static Method getSubListOriginalListSetAffectsSubListMethod() {
316    return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubList");
317  }
318
319  /**
320   * Returns the {@link Method} instance for {@link
321   * #testSubList_originalListSetAffectsSubListLargeList()} so that tests of {@link
322   * CopyOnWriteArrayList} can suppress them with {@code
323   * FeatureSpecificTestSuiteBuilder.suppressing()} until <a
324   * href="https://bugs.openjdk.org/browse/JDK-6570631">JDK-6570631</a> is fixed.
325   */
326  @J2ktIncompatible
327  @GwtIncompatible // reflection
328  public static Method getSubListOriginalListSetAffectsSubListLargeListMethod() {
329    return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubListLargeList");
330  }
331
332  /**
333   * Returns the {@link Method} instance for {@link
334   * #testSubList_subListRemoveAffectsOriginalLargeList()} so that tests of {@link
335   * CopyOnWriteArrayList} can suppress it with {@code
336   * FeatureSpecificTestSuiteBuilder.suppressing()} until <a
337   * href="https://bugs.openjdk.org/browse/JDK-6570575">JDK-6570575</a> is fixed.
338   */
339  @J2ktIncompatible
340  @GwtIncompatible // reflection
341  public static Method getSubListSubListRemoveAffectsOriginalLargeListMethod() {
342    return getMethod(ListSubListTester.class, "testSubList_subListRemoveAffectsOriginalLargeList");
343  }
344
345  /*
346   * TODO: perform all List tests on subList(), but beware infinite recursion
347   */
348}