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