ListSubListTester.java revision 0888a09821a98ac0680fad765217302858e70fa4
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.Helpers.getMethod;
20import static com.google.common.collect.testing.features.CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS;
21import static com.google.common.collect.testing.features.CollectionSize.ONE;
22import static com.google.common.collect.testing.features.CollectionSize.ZERO;
23import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_ADD_WITH_INDEX;
24import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_REMOVE_WITH_INDEX;
25import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_SET;
26import static java.util.Collections.emptyList;
27
28import com.google.common.annotations.GwtCompatible;
29import com.google.common.annotations.GwtIncompatible;
30import com.google.common.collect.testing.Helpers;
31import com.google.common.collect.testing.features.CollectionFeature;
32import com.google.common.collect.testing.features.CollectionSize;
33import com.google.common.collect.testing.features.ListFeature;
34import com.google.common.testing.SerializableTester;
35
36import java.lang.reflect.Method;
37import java.util.Arrays;
38import java.util.Collections;
39import java.util.List;
40import java.util.concurrent.CopyOnWriteArrayList;
41
42/**
43 * A generic JUnit test which tests {@code subList()} operations on a list.
44 * Can't be invoked directly; please see
45 * {@link com.google.common.collect.testing.ListTestSuiteBuilder}.
46 *
47 * @author Chris Povirk
48 */
49@SuppressWarnings("unchecked") // too many "unchecked generic array creations"
50@GwtCompatible(emulated = true)
51public class ListSubListTester<E> extends AbstractListTester<E> {
52  public void testSubList_startNegative() {
53    try {
54      getList().subList(-1, 0);
55      fail("subList(-1, 0) should throw");
56    } catch (IndexOutOfBoundsException expected) {
57    }
58  }
59
60  public void testSubList_endTooLarge() {
61    try {
62      getList().subList(0, getNumElements() + 1);
63      fail("subList(0, size + 1) should throw");
64    } catch (IndexOutOfBoundsException expected) {
65    }
66  }
67
68  public void testSubList_startGreaterThanEnd() {
69    try {
70      getList().subList(1, 0);
71      fail("subList(1, 0) should throw");
72    } catch (IndexOutOfBoundsException expected) {
73    } catch (IllegalArgumentException expected) {
74      /*
75       * The subList() docs claim that this should be an
76       * IndexOutOfBoundsException, but many JDK implementations throw
77       * IllegalArgumentException:
78       * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4506427
79       */
80    }
81  }
82
83  public void testSubList_empty() {
84    assertEquals("subList(0, 0) should be empty",
85        emptyList(), getList().subList(0, 0));
86  }
87
88  public void testSubList_entireList() {
89    assertEquals("subList(0, size) should be equal to the original list",
90        getList(), getList().subList(0, getNumElements()));
91  }
92
93  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
94  @CollectionSize.Require(absent = ZERO)
95  public void testSubList_subListRemoveAffectsOriginal() {
96    List<E> subList = getList().subList(0, 1);
97    subList.remove(0);
98    List<E> expected =
99        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 =
109        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(samples.e3);
117    expectAdded(0, samples.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, samples.e3);
125    List<E> expected = Helpers.copyToList(createSamplesArray());
126    expected.set(0, samples.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, samples.e3);
135    assertEquals("A set() call to a list after a sublist has been created "
136        + "should be reflected in the sublist",
137        Collections.singletonList(samples.e3), subList);
138  }
139
140  @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
141  @CollectionSize.Require(absent = {ZERO, ONE})
142  public void testSubList_subListRemoveAffectsOriginalLargeList() {
143    List<E> subList = getList().subList(1, 3);
144    subList.remove(samples.e2);
145    List<E> expected = Helpers.copyToList(createSamplesArray());
146    expected.remove(2);
147    expectContents(expected);
148  }
149
150  @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
151  @CollectionSize.Require(absent = {ZERO, ONE})
152  public void testSubList_subListAddAtIndexAffectsOriginalLargeList() {
153    List<E> subList = getList().subList(2, 3);
154    subList.add(0, samples.e3);
155    expectAdded(2, samples.e3);
156  }
157
158  @ListFeature.Require(SUPPORTS_SET)
159  @CollectionSize.Require(absent = {ZERO, ONE})
160  public void testSubList_subListSetAffectsOriginalLargeList() {
161    List<E> subList = getList().subList(1, 2);
162    subList.set(0, samples.e3);
163    List<E> expected = Helpers.copyToList(createSamplesArray());
164    expected.set(1, samples.e3);
165    expectContents(expected);
166  }
167
168  @ListFeature.Require(SUPPORTS_SET)
169  @CollectionSize.Require(absent = {ZERO, ONE})
170  public void testSubList_originalListSetAffectsSubListLargeList() {
171    List<E> subList = getList().subList(1, 3);
172    getList().set(1, samples.e3);
173    assertEquals("A set() call to a list after a sublist has been created "
174        + "should be reflected in the sublist",
175        Arrays.asList(samples.e3, samples.e2), subList);
176  }
177
178  public void testSubList_ofSubListEmpty() {
179    List<E> subList = getList().subList(0, 0).subList(0, 0);
180    assertEquals("subList(0, 0).subList(0, 0) should be an empty list",
181        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("subList(0, 2).subList(1, 2) "
188        + "should be a single-element list of the element at index 1",
189        Collections.singletonList(getOrderedElements().get(1)), subList);
190  }
191
192  @CollectionSize.Require(absent = {ZERO})
193  public void testSubList_size() {
194    List<E> list = getList();
195    int size = getNumElements();
196    assertEquals(list.subList(0, size).size(),
197                 size);
198    assertEquals(list.subList(0, size - 1).size(),
199                 size - 1);
200    assertEquals(list.subList(1, size).size(),
201                 size - 1);
202    assertEquals(list.subList(size, size).size(),
203                 0);
204    assertEquals(list.subList(0, 0).size(),
205                 0);
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 : 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.isEmpty(), subList.size() == 0);
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(copy.indexOf(list.get(0)),
272                 0);
273    assertEquals(head.indexOf(list.get(0)),
274                 0);
275    assertEquals(tail.indexOf(list.get(1)),
276                 0);
277    // The following assumes all elements are distinct.
278    assertEquals(copy.indexOf(list.get(size - 1)),
279                 size - 1);
280    assertEquals(head.indexOf(list.get(size - 2)),
281                 size - 2);
282    assertEquals(tail.indexOf(list.get(size - 1)),
283                 size - 2);
284    assertEquals(head.indexOf(list.get(size - 1)),
285                 -1);
286    assertEquals(tail.indexOf(list.get(0)),
287                 -1);
288  }
289
290  @CollectionSize.Require(absent = {ZERO, ONE})
291  public void testSubList_lastIndexOf() {
292    List<E> list = getList();
293    int size = list.size();
294    List<E> copy = list.subList(0, size);
295    List<E> head = list.subList(0, size - 1);
296    List<E> tail = list.subList(1, size);
297    assertEquals(copy.lastIndexOf(list.get(size - 1)),
298                 size - 1);
299    assertEquals(head.lastIndexOf(list.get(size - 2)),
300                 size - 2);
301    assertEquals(tail.lastIndexOf(list.get(size - 1)),
302                 size - 2);
303    // The following assumes all elements are distinct.
304    assertEquals(copy.lastIndexOf(list.get(0)),
305                 0);
306    assertEquals(head.lastIndexOf(list.get(0)),
307                 0);
308    assertEquals(tail.lastIndexOf(list.get(1)),
309                 0);
310    assertEquals(head.lastIndexOf(list.get(size - 1)),
311                 -1);
312    assertEquals(tail.lastIndexOf(list.get(0)),
313                 -1);
314  }
315
316  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
317  public void testReserializeWholeSubList() {
318    SerializableTester.reserializeAndAssert(getList().subList(0, getNumElements()));
319  }
320
321  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
322  public void testReserializeEmptySubList() {
323    SerializableTester.reserializeAndAssert(getList().subList(0, 0));
324  }
325
326  @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
327  @CollectionSize.Require(absent = {ZERO, ONE})
328  public void testReserializeSubList() {
329    SerializableTester.reserializeAndAssert(getList().subList(0, 2));
330  }
331
332  /**
333   * Returns the {@link Method} instance for
334   * {@link #testSubList_originalListSetAffectsSubList()} so that tests
335   * of {@link CopyOnWriteArrayList} can suppress them with
336   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
337   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
338   * 6570631</a> is fixed.
339   */
340  @GwtIncompatible("reflection")
341  public static Method getSubListOriginalListSetAffectsSubListMethod() {
342    return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubList");
343  }
344
345  /**
346   * Returns the {@link Method} instance for
347   * {@link #testSubList_originalListSetAffectsSubListLargeList()} ()} so that
348   * tests of {@link CopyOnWriteArrayList} can suppress them with
349   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
350   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
351   * 6570631</a> is fixed.
352   */
353  @GwtIncompatible("reflection")
354  public static Method getSubListOriginalListSetAffectsSubListLargeListMethod() {
355    return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubListLargeList");
356  }
357
358  /**
359   * Returns the {@link Method} instance for
360   * {@link #testSubList_subListRemoveAffectsOriginalLargeList()} so that tests
361   * of {@link CopyOnWriteArrayList} can suppress it with
362   * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
363   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570575">Sun bug
364   * 6570575</a> is fixed.
365   */
366  @GwtIncompatible("reflection")
367  public static Method getSubListSubListRemoveAffectsOriginalLargeListMethod() {
368    return getMethod(ListSubListTester.class, "testSubList_subListRemoveAffectsOriginalLargeList");
369  }
370
371  /*
372   * TODO: perform all List tests on subList(), but beware infinite recursion
373   */
374}
375