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