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