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