View Javadoc
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  
17  package com.google.common.collect.testing.testers;
18  
19  import static com.google.common.collect.testing.Helpers.getMethod;
20  import static com.google.common.collect.testing.features.CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS;
21  import static com.google.common.collect.testing.features.CollectionSize.ONE;
22  import static com.google.common.collect.testing.features.CollectionSize.ZERO;
23  import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_ADD_WITH_INDEX;
24  import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_REMOVE_WITH_INDEX;
25  import static com.google.common.collect.testing.features.ListFeature.SUPPORTS_SET;
26  import static java.util.Collections.emptyList;
27  
28  import com.google.common.annotations.GwtCompatible;
29  import com.google.common.annotations.GwtIncompatible;
30  import com.google.common.collect.testing.Helpers;
31  import com.google.common.collect.testing.features.CollectionFeature;
32  import com.google.common.collect.testing.features.CollectionSize;
33  import com.google.common.collect.testing.features.ListFeature;
34  import com.google.common.testing.SerializableTester;
35  import java.lang.reflect.Method;
36  import java.util.Arrays;
37  import java.util.Collections;
38  import java.util.List;
39  import java.util.concurrent.CopyOnWriteArrayList;
40  
41  /**
42   * A generic JUnit test which tests {@code subList()} operations on a list.
43   * Can't be invoked directly; please see
44   * {@link com.google.common.collect.testing.ListTestSuiteBuilder}.
45   *
46   * @author Chris Povirk
47   */
48  @SuppressWarnings("unchecked") // too many "unchecked generic array creations"
49  @GwtCompatible(emulated = true)
50  public class ListSubListTester<E> extends AbstractListTester<E> {
51    public void testSubList_startNegative() {
52      try {
53        getList().subList(-1, 0);
54        fail("subList(-1, 0) should throw");
55      } catch (IndexOutOfBoundsException expected) {
56      }
57    }
58  
59    public void testSubList_endTooLarge() {
60      try {
61        getList().subList(0, getNumElements() + 1);
62        fail("subList(0, size + 1) should throw");
63      } catch (IndexOutOfBoundsException expected) {
64      }
65    }
66  
67    public void testSubList_startGreaterThanEnd() {
68      try {
69        getList().subList(1, 0);
70        fail("subList(1, 0) should throw");
71      } catch (IndexOutOfBoundsException expected) {
72      } catch (IllegalArgumentException expected) {
73        /*
74         * The subList() docs claim that this should be an
75         * IndexOutOfBoundsException, but many JDK implementations throw
76         * IllegalArgumentException:
77         * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4506427
78         */
79      }
80    }
81  
82    public void testSubList_empty() {
83      assertEquals("subList(0, 0) should be empty", emptyList(), getList().subList(0, 0));
84    }
85  
86    public void testSubList_entireList() {
87      assertEquals(
88          "subList(0, size) should be equal to the original list",
89          getList(),
90          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 = Arrays.asList(createSamplesArray()).subList(1, getNumElements());
99      expectContents(expected);
100   }
101 
102   @ListFeature.Require(SUPPORTS_REMOVE_WITH_INDEX)
103   @CollectionSize.Require(absent = ZERO)
104   public void testSubList_subListClearAffectsOriginal() {
105     List<E> subList = getList().subList(0, 1);
106     subList.clear();
107     List<E> expected = Arrays.asList(createSamplesArray()).subList(1, getNumElements());
108     expectContents(expected);
109   }
110 
111   @ListFeature.Require(SUPPORTS_ADD_WITH_INDEX)
112   public void testSubList_subListAddAffectsOriginal() {
113     List<E> subList = getList().subList(0, 0);
114     subList.add(e3());
115     expectAdded(0, e3());
116   }
117 
118   @ListFeature.Require(SUPPORTS_SET)
119   @CollectionSize.Require(absent = ZERO)
120   public void testSubList_subListSetAffectsOriginal() {
121     List<E> subList = getList().subList(0, 1);
122     subList.set(0, e3());
123     List<E> expected = Helpers.copyToList(createSamplesArray());
124     expected.set(0, e3());
125     expectContents(expected);
126   }
127 
128   @ListFeature.Require(SUPPORTS_SET)
129   @CollectionSize.Require(absent = ZERO)
130   public void testSubList_originalListSetAffectsSubList() {
131     List<E> subList = getList().subList(0, 1);
132     getList().set(0, e3());
133     assertEquals(
134         "A set() call to a list after a sublist has been created "
135             + "should be reflected in the sublist",
136         Collections.singletonList(e3()),
137         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(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, e3());
155     expectAdded(2, 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, e3());
163     List<E> expected = Helpers.copyToList(createSamplesArray());
164     expected.set(1, 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, e3());
173     assertEquals(
174         "A set() call to a list after a sublist has been created "
175             + "should be reflected in the sublist",
176         Arrays.asList(e3(), e2()),
177         subList);
178   }
179 
180   public void testSubList_ofSubListEmpty() {
181     List<E> subList = getList().subList(0, 0).subList(0, 0);
182     assertEquals("subList(0, 0).subList(0, 0) should be an empty list", emptyList(), subList);
183   }
184 
185   @CollectionSize.Require(absent = {ZERO, ONE})
186   public void testSubList_ofSubListNonEmpty() {
187     List<E> subList = getList().subList(0, 2).subList(1, 2);
188     assertEquals(
189         "subList(0, 2).subList(1, 2) "
190             + "should be a single-element list of the element at index 1",
191         Collections.singletonList(getOrderedElements().get(1)),
192         subList);
193   }
194 
195   @CollectionSize.Require(absent = {ZERO})
196   public void testSubList_size() {
197     List<E> list = getList();
198     int size = getNumElements();
199     assertEquals(size, list.subList(0, size).size());
200     assertEquals(size - 1, list.subList(0, size - 1).size());
201     assertEquals(size - 1, list.subList(1, size).size());
202     assertEquals(0, list.subList(size, size).size());
203     assertEquals(0, list.subList(0, 0).size());
204   }
205 
206   @CollectionSize.Require(absent = {ZERO})
207   public void testSubList_isEmpty() {
208     List<E> list = getList();
209     int size = getNumElements();
210     for (List<E> subList :
211         Arrays.asList(
212             list.subList(0, size),
213             list.subList(0, size - 1),
214             list.subList(1, size),
215             list.subList(0, 0),
216             list.subList(size, size))) {
217       assertEquals(subList.size() == 0, subList.isEmpty());
218     }
219   }
220 
221   @CollectionSize.Require(absent = {ZERO, ONE})
222   public void testSubList_get() {
223     List<E> list = getList();
224     int size = getNumElements();
225     List<E> copy = list.subList(0, size);
226     List<E> head = list.subList(0, size - 1);
227     List<E> tail = list.subList(1, size);
228     assertEquals(list.get(0), copy.get(0));
229     assertEquals(list.get(size - 1), copy.get(size - 1));
230     assertEquals(list.get(1), tail.get(0));
231     assertEquals(list.get(size - 1), tail.get(size - 2));
232     assertEquals(list.get(0), head.get(0));
233     assertEquals(list.get(size - 2), head.get(size - 2));
234     for (List<E> subList : Arrays.asList(copy, head, tail)) {
235       for (int index : Arrays.asList(-1, subList.size())) {
236         try {
237           subList.get(index);
238           fail("expected IndexOutOfBoundsException");
239         } catch (IndexOutOfBoundsException expected) {
240         }
241       }
242     }
243   }
244 
245   @CollectionSize.Require(absent = {ZERO, ONE})
246   public void testSubList_contains() {
247     List<E> list = getList();
248     int size = getNumElements();
249     List<E> copy = list.subList(0, size);
250     List<E> head = list.subList(0, size - 1);
251     List<E> tail = list.subList(1, size);
252     assertTrue(copy.contains(list.get(0)));
253     assertTrue(head.contains(list.get(0)));
254     assertTrue(tail.contains(list.get(1)));
255     // The following assumes all elements are distinct.
256     assertTrue(copy.contains(list.get(size - 1)));
257     assertTrue(head.contains(list.get(size - 2)));
258     assertTrue(tail.contains(list.get(size - 1)));
259     assertFalse(head.contains(list.get(size - 1)));
260     assertFalse(tail.contains(list.get(0)));
261   }
262 
263   @CollectionSize.Require(absent = {ZERO, ONE})
264   public void testSubList_indexOf() {
265     List<E> list = getList();
266     int size = getNumElements();
267     List<E> copy = list.subList(0, size);
268     List<E> head = list.subList(0, size - 1);
269     List<E> tail = list.subList(1, size);
270     assertEquals(0, copy.indexOf(list.get(0)));
271     assertEquals(0, head.indexOf(list.get(0)));
272     assertEquals(0, tail.indexOf(list.get(1)));
273     // The following assumes all elements are distinct.
274     assertEquals(size - 1, copy.indexOf(list.get(size - 1)));
275     assertEquals(size - 2, head.indexOf(list.get(size - 2)));
276     assertEquals(size - 2, tail.indexOf(list.get(size - 1)));
277     assertEquals(-1, head.indexOf(list.get(size - 1)));
278     assertEquals(-1, tail.indexOf(list.get(0)));
279   }
280 
281   @CollectionSize.Require(absent = {ZERO, ONE})
282   public void testSubList_lastIndexOf() {
283     List<E> list = getList();
284     int size = list.size();
285     List<E> copy = list.subList(0, size);
286     List<E> head = list.subList(0, size - 1);
287     List<E> tail = list.subList(1, size);
288     assertEquals(size - 1, copy.lastIndexOf(list.get(size - 1)));
289     assertEquals(size - 2, head.lastIndexOf(list.get(size - 2)));
290     assertEquals(size - 2, tail.lastIndexOf(list.get(size - 1)));
291     // The following assumes all elements are distinct.
292     assertEquals(0, copy.lastIndexOf(list.get(0)));
293     assertEquals(0, head.lastIndexOf(list.get(0)));
294     assertEquals(0, tail.lastIndexOf(list.get(1)));
295     assertEquals(-1, head.lastIndexOf(list.get(size - 1)));
296     assertEquals(-1, tail.lastIndexOf(list.get(0)));
297   }
298 
299   @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
300   public void testReserializeWholeSubList() {
301     SerializableTester.reserializeAndAssert(getList().subList(0, getNumElements()));
302   }
303 
304   @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
305   public void testReserializeEmptySubList() {
306     SerializableTester.reserializeAndAssert(getList().subList(0, 0));
307   }
308 
309   @CollectionFeature.Require(SERIALIZABLE_INCLUDING_VIEWS)
310   @CollectionSize.Require(absent = {ZERO, ONE})
311   public void testReserializeSubList() {
312     SerializableTester.reserializeAndAssert(getList().subList(0, 2));
313   }
314 
315   /**
316    * Returns the {@link Method} instance for
317    * {@link #testSubList_originalListSetAffectsSubList()} so that tests
318    * of {@link CopyOnWriteArrayList} can suppress them with
319    * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
320    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
321    * 6570631</a> is fixed.
322    */
323   @GwtIncompatible // reflection
324   public static Method getSubListOriginalListSetAffectsSubListMethod() {
325     return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubList");
326   }
327 
328   /**
329    * Returns the {@link Method} instance for
330    * {@link #testSubList_originalListSetAffectsSubListLargeList()} ()} so that
331    * tests of {@link CopyOnWriteArrayList} can suppress them with
332    * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
333    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570631">Sun bug
334    * 6570631</a> is fixed.
335    */
336   @GwtIncompatible // reflection
337   public static Method getSubListOriginalListSetAffectsSubListLargeListMethod() {
338     return getMethod(ListSubListTester.class, "testSubList_originalListSetAffectsSubListLargeList");
339   }
340 
341   /**
342    * Returns the {@link Method} instance for
343    * {@link #testSubList_subListRemoveAffectsOriginalLargeList()} so that tests
344    * of {@link CopyOnWriteArrayList} can suppress it with
345    * {@code FeatureSpecificTestSuiteBuilder.suppressing()} until <a
346    * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570575">Sun bug
347    * 6570575</a> is fixed.
348    */
349   @GwtIncompatible // reflection
350   public static Method getSubListSubListRemoveAffectsOriginalLargeListMethod() {
351     return getMethod(ListSubListTester.class, "testSubList_subListRemoveAffectsOriginalLargeList");
352   }
353 
354   /*
355    * TODO: perform all List tests on subList(), but beware infinite recursion
356    */
357 }