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