1/*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect.testing.testers;
18
19import static com.google.common.collect.testing.features.CollectionSize.ONE;
20import static com.google.common.collect.testing.features.CollectionSize.ZERO;
21import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_ADD_WITH_INDEX;
22import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_REMOVE_WITH_INDEX;
23import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_SET;
24import static java.util.Collections.emptyList;
25
26import com.google.common.collect.testing.Helpers;
27import com.google.common.collect.testing.features.CollectionSize;
28import com.google.common.collect.testing.features.ListFeature;
29
30import java.lang.reflect.Method;
31import java.util.Arrays;
32import java.util.Collections;
33import java.util.List;
34import java.util.concurrent.CopyOnWriteArrayList;
35
36/**
37 * A generic JUnit test which tests {@code subList()} operations on a list.
38 * Can't be invoked directly; please see
39 * {@link com.google.common.collect.testing.ListTestSuiteBuilder}.
40 *
41 * <p>This class is GWT compatible.
42 *
43 * @author Chris Povirk
44 */
45@SuppressWarnings("unchecked") // too many "unchecked generic array creations"
46public class ListSubListTester<E> extends AbstractListTester<E> {
47  public void testSubList_startNegative() {
48    try {
49      getList().subList(-1, 0);
50      fail("subList(-1, 0) should throw");
51    } catch (IndexOutOfBoundsException expected) {
52    }
53  }
54
55  public void testSubList_endTooLarge() {
56    try {
57      getList().subList(0, getNumElements() + 1);
58      fail("subList(0, size + 1) should throw");
59    } catch (IndexOutOfBoundsException expected) {
60    }
61  }
62
63  public void testSubList_startGreaterThanEnd() {
64    try {
65      getList().subList(1, 0);
66      fail("subList(1, 0) should throw");
67    } catch (IndexOutOfBoundsException expected) {
68    } catch (IllegalArgumentException expected) {
69      /*
70       * The subList() docs claim that this should be an
71       * IndexOutOfBoundsException, but many JDK implementations throw
72       * IllegalArgumentException:
73       * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4506427
74       */
75    }
76  }
77
78  public void testSubList_empty() {
79    assertEquals("subList(0, 0) should be empty",
80        emptyList(), getList().subList(0, 0));
81  }
82
83  public void testSubList_entireList() {
84    assertEquals("subList(0, size) should be equal to the original list",
85        getList(), getList().subList(0, getNumElements()));
86  }
87
88  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
89  @CollectionSize.Require(absent = ZERO)
90  public void testSubList_subListRemoveAffectsOriginal() {
91    List<E> subList = getList().subList(0, 1);
92    subList.remove(0);
93    List<E> expected =
94        Arrays.asList(createSamplesArray()).subList(1, getNumElements());
95    expectContents(expected);
96  }
97
98  @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
99  public void testSubList_subListAddAffectsOriginal() {
100    List<E> subList = getList().subList(0, 0);
101    subList.add(samples.e3);
102    expectAdded(0, samples.e3);
103  }
104
105  @ListFeature.Require(SUPPORTS_SET)
106  @CollectionSize.Require(absent = ZERO)
107  public void testSubList_subListSetAffectsOriginal() {
108    List<E> subList = getList().subList(0, 1);
109    subList.set(0, samples.e3);
110    List<E> expected = Helpers.copyToList(createSamplesArray());
111    expected.set(0, samples.e3);
112    expectContents(expected);
113  }
114
115  @ListFeature.Require(SUPPORTS_SET)
116  @CollectionSize.Require(absent = ZERO)
117  public void testSubList_originalListSetAffectsSubList() {
118    List<E> subList = getList().subList(0, 1);
119    getList().set(0, samples.e3);
120    assertEquals("A set() call to a list after a sublist has been created "
121        + "should be reflected in the sublist",
122        Collections.singletonList(samples.e3), subList);
123  }
124
125  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
126  @CollectionSize.Require(absent = {ZERO, ONE})
127  public void testSubList_subListRemoveAffectsOriginalLargeList() {
128    List<E> subList = getList().subList(1, 3);
129    subList.remove(samples.e2);
130    List<E> expected = Helpers.copyToList(createSamplesArray());
131    expected.remove(2);
132    expectContents(expected);
133  }
134
135  @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
136  @CollectionSize.Require(absent = {ZERO, ONE})
137  public void testSubList_subListAddAtIndexAffectsOriginalLargeList() {
138    List<E> subList = getList().subList(2, 3);
139    subList.add(0, samples.e3);
140    expectAdded(2, samples.e3);
141  }
142
143  @ListFeature.Require(SUPPORTS_SET)
144  @CollectionSize.Require(absent = {ZERO, ONE})
145  public void testSubList_subListSetAffectsOriginalLargeList() {
146    List<E> subList = getList().subList(1, 2);
147    subList.set(0, samples.e3);
148    List<E> expected = Helpers.copyToList(createSamplesArray());
149    expected.set(1, samples.e3);
150    expectContents(expected);
151  }
152
153  @ListFeature.Require(SUPPORTS_SET)
154  @CollectionSize.Require(absent = {ZERO, ONE})
155  public void testSubList_originalListSetAffectsSubListLargeList() {
156    List<E> subList = getList().subList(1, 3);
157    getList().set(1, samples.e3);
158    assertEquals("A set() call to a list after a sublist has been created "
159        + "should be reflected in the sublist",
160        Arrays.asList(samples.e3, samples.e2), subList);
161  }
162
163  public void testSubList_ofSubListEmpty() {
164    List<E> subList = getList().subList(0, 0).subList(0, 0);
165    assertEquals("subList(0, 0).subList(0, 0) should be an empty list",
166        emptyList(), subList);
167  }
168
169  @CollectionSize.Require(absent = {ZERO, ONE})
170  public void testSubList_ofSubListNonEmpty() {
171    List<E> subList = getList().subList(0, 2).subList(1, 2);
172    assertEquals("subList(0, 2).subList(1, 2) "
173        + "should be a single-element list of the element at index 1",
174        Collections.singletonList(samples.e1), subList);
175  }
176
177  @CollectionSize.Require(absent = {ZERO})
178  public void testSubList_size() {
179    List<E> list = getList();
180    int size = getNumElements();
181    assertEquals(list.subList(0, size).size(),
182                 size);
183    assertEquals(list.subList(0, size - 1).size(),
184                 size - 1);
185    assertEquals(list.subList(1, size).size(),
186                 size - 1);
187    assertEquals(list.subList(size, size).size(),
188                 0);
189    assertEquals(list.subList(0, 0).size(),
190                 0);
191  }
192
193  @CollectionSize.Require(absent = {ZERO})
194  public void testSubList_isEmpty() {
195    List<E> list = getList();
196    int size = getNumElements();
197    for (List<E> subList : Arrays.asList(
198        list.subList(0, size),
199        list.subList(0, size - 1),
200        list.subList(1, size),
201        list.subList(0, 0),
202        list.subList(size, size))) {
203      assertEquals(subList.isEmpty(), subList.size() == 0);
204    }
205  }
206
207  @CollectionSize.Require(absent = {ZERO, ONE})
208  public void testSubList_get() {
209    List<E> list = getList();
210    int size = getNumElements();
211    List<E> copy = list.subList(0, size);
212    List<E> head = list.subList(0, size - 1);
213    List<E> tail = list.subList(1, size);
214    assertEquals(list.get(0), copy.get(0));
215    assertEquals(list.get(size - 1), copy.get(size - 1));
216    assertEquals(list.get(1), tail.get(0));
217    assertEquals(list.get(size - 1), tail.get(size - 2));
218    assertEquals(list.get(0), head.get(0));
219    assertEquals(list.get(size - 2), head.get(size - 2));
220    for (List<E> subList : Arrays.asList(copy, head, tail)) {
221      for (int index : Arrays.asList(-1, subList.size())) {
222        try {
223          subList.get(index);
224          fail("expected IndexOutOfBoundsException");
225        } catch (IndexOutOfBoundsException expected) {
226        }
227      }
228    }
229  }
230
231  @CollectionSize.Require(absent = {ZERO, ONE})
232  public void testSubList_contains() {
233    List<E> list = getList();
234    int size = getNumElements();
235    List<E> copy = list.subList(0, size);
236    List<E> head = list.subList(0, size - 1);
237    List<E> tail = list.subList(1, size);
238    assertTrue(copy.contains(list.get(0)));
239    assertTrue(head.contains(list.get(0)));
240    assertTrue(tail.contains(list.get(1)));
241    // The following assumes all elements are distinct.
242    assertTrue(copy.contains(list.get(size - 1)));
243    assertTrue(head.contains(list.get(size - 2)));
244    assertTrue(tail.contains(list.get(size - 1)));
245    assertFalse(head.contains(list.get(size - 1)));
246    assertFalse(tail.contains(list.get(0)));
247  }
248
249  @CollectionSize.Require(absent = {ZERO, ONE})
250  public void testSubList_indexOf() {
251    List<E> list = getList();
252    int size = getNumElements();
253    List<E> copy = list.subList(0, size);
254    List<E> head = list.subList(0, size - 1);
255    List<E> tail = list.subList(1, size);
256    assertEquals(copy.indexOf(list.get(0)),
257                 0);
258    assertEquals(head.indexOf(list.get(0)),
259                 0);
260    assertEquals(tail.indexOf(list.get(1)),
261                 0);
262    // The following assumes all elements are distinct.
263    assertEquals(copy.indexOf(list.get(size - 1)),
264                 size - 1);
265    assertEquals(head.indexOf(list.get(size - 2)),
266                 size - 2);
267    assertEquals(tail.indexOf(list.get(size - 1)),
268                 size - 2);
269    assertEquals(head.indexOf(list.get(size - 1)),
270                 -1);
271    assertEquals(tail.indexOf(list.get(0)),
272                 -1);
273  }
274
275  @CollectionSize.Require(absent = {ZERO, ONE})
276  public void testSubList_lastIndexOf() {
277    List<E> list = getList();
278    int size = list.size();
279    List<E> copy = list.subList(0, size);
280    List<E> head = list.subList(0, size - 1);
281    List<E> tail = list.subList(1, size);
282    assertEquals(copy.lastIndexOf(list.get(size - 1)),
283                 size - 1);
284    assertEquals(head.lastIndexOf(list.get(size - 2)),
285                 size - 2);
286    assertEquals(tail.lastIndexOf(list.get(size - 1)),
287                 size - 2);
288    // The following assumes all elements are distinct.
289    assertEquals(copy.lastIndexOf(list.get(0)),
290                 0);
291    assertEquals(head.lastIndexOf(list.get(0)),
292                 0);
293    assertEquals(tail.lastIndexOf(list.get(1)),
294                 0);
295    assertEquals(head.lastIndexOf(list.get(size - 1)),
296                 -1);
297    assertEquals(tail.lastIndexOf(list.get(0)),
298                 -1);
299  }
300
301  /**
302   * Returns the {@link Method} instance for
303   * {@link #testSubList_originalListSetAffectsSubList()} so that tests
304   * of {@link CopyOnWriteArrayList} can suppress them with
305   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
306   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
307   * 6570631</a> is fixed.
308   */
309  public static Method getSubListOriginalListSetAffectsSubListMethod() {
310    return Platform
311        .getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubList");
312  }
313
314  /**
315   * Returns the {@link Method} instance for
316   * {@link #testSubList_originalListSetAffectsSubListLargeList()} ()} so that
317   * tests of {@link CopyOnWriteArrayList} can suppress them with
318   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
319   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
320   * 6570631</a> is fixed.
321   */
322  public static Method
323      getSubListOriginalListSetAffectsSubListLargeListMethod() {
324    return Platform
325        .getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubListLargeList");
326  }
327
328  /**
329   * Returns the {@link Method} instance for
330   * {@link #testSubList_subListRemoveAffectsOriginalLargeList()} so that tests
331   * of {@link CopyOnWriteArrayList} can suppress it with
332   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
333   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570575">Sun bug
334   * 6570575</a> is fixed.
335   */
336  public static Method getSubListSubListRemoveAffectsOriginalLargeListMethod() {
337    return Platform.getMethod(
338        ListSubListTester.class, "testSubList_subListRemoveAffectsOriginalLargeList");
339  }
340
341  /*
342   * TODO: perform all List tests on subList(), but beware infinite recursion
343   */
344}
345