1 /* 2 * Copyright (C) 2017 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; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import com.google.common.annotations.GwtCompatible; 23 import com.google.common.annotations.GwtIncompatible; 24 import com.google.common.annotations.J2ktIncompatible; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collection; 28 import java.util.Collections; 29 import java.util.Enumeration; 30 import java.util.LinkedList; 31 import java.util.List; 32 import java.util.concurrent.CopyOnWriteArrayList; 33 import junit.framework.Test; 34 import junit.framework.TestCase; 35 import junit.framework.TestSuite; 36 import org.checkerframework.checker.nullness.qual.Nullable; 37 38 /** Tests the package level *impl methods directly using various types of lists. */ 39 @GwtCompatible(emulated = true) 40 @ElementTypesAreNonnullByDefault 41 public class ListsImplTest extends TestCase { 42 43 /** Describes how a list is modifiable */ 44 public enum Modifiability { 45 NONE, // immutable lists 46 BY_ELEMENT, // elements can change (set), but not structure 47 DIRECT_ONLY, // Element can be added and removed only via direct calls, not through iterators 48 ALL // Elements can be added and removed as well as modified. 49 } 50 51 /** Handles the creation of lists needed for the tests */ 52 public abstract static class ListExample { 53 54 private final String name; 55 private final Modifiability modifiability; 56 ListExample(String name, Modifiability modifiability)57 protected ListExample(String name, Modifiability modifiability) { 58 this.name = name; 59 this.modifiability = modifiability; 60 } 61 62 /** Gets the name of the example */ getName()63 public String getName() { 64 return name; 65 } 66 67 /** Creates a new list with the given contents. */ createList(Class<T> listType, Collection<? extends T> contents)68 public abstract <T> List<T> createList(Class<T> listType, Collection<? extends T> contents); 69 70 /** The modifiability of this list example. */ modifiability()71 public Modifiability modifiability() { 72 return modifiability; 73 } 74 } 75 76 @J2ktIncompatible 77 @GwtIncompatible // suite suite()78 public static Test suite() { 79 TestSuite suite = new TestSuite(); 80 suite.addTest(createExampleSuite(new ArrayListExample("ArrayList"))); 81 suite.addTest(createExampleSuite(new LinkedListExample("LinkedList"))); 82 suite.addTest(createExampleSuite(new ArraysAsListExample("Arrays.asList"))); 83 suite.addTest(createExampleSuite(new ImmutableListExample("ImmutableList"))); 84 suite.addTest(createExampleSuite(new CopyOnWriteListExample("CopyOnWriteArrayList"))); 85 suite.addTestSuite(ListsImplTest.class); 86 return suite; 87 } 88 89 @J2ktIncompatible 90 @GwtIncompatible // suite sub call createExampleSuite(ListExample example)91 private static TestSuite createExampleSuite(ListExample example) { 92 TestSuite resultSuite = new TestSuite(ListsImplTest.class); 93 for (Enumeration<Test> testEnum = resultSuite.tests(); testEnum.hasMoreElements(); ) { 94 ListsImplTest test = (ListsImplTest) testEnum.nextElement(); 95 test.example = example; 96 } 97 return resultSuite; 98 } 99 100 private @Nullable ListExample example; 101 getExample()102 private ListExample getExample() { 103 // because sometimes one version with a null example is created. 104 return example == null ? new ImmutableListExample("test") : example; 105 } 106 107 @J2ktIncompatible 108 @GwtIncompatible // not used under GWT, and super.getName() is not available under J2CL 109 @Override getName()110 public String getName() { 111 return example == null ? super.getName() : buildTestName(); 112 } 113 114 @J2ktIncompatible 115 @GwtIncompatible // not used under GWT, and super.getName() is not available under J2CL buildTestName()116 private String buildTestName() { 117 return super.getName() + ":" + example.getName(); 118 } 119 testHashCodeImpl()120 public void testHashCodeImpl() { 121 List<Integer> base = createList(Integer.class, 1, 2, 2); 122 List<Integer> copy = createList(Integer.class, 1, 2, 2); 123 List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); 124 List<Integer> diffValue = createList(Integer.class, 1, 2, 4); 125 List<Integer> diffLength = createList(Integer.class, 1, 2); 126 List<Integer> empty = createList(Integer.class); 127 128 assertThat(Lists.hashCodeImpl(base)).isEqualTo(Lists.hashCodeImpl(copy)); 129 130 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(outOfOrder)); 131 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffValue)); 132 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffLength)); 133 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(empty)); 134 } 135 testEqualsImpl()136 public void testEqualsImpl() { 137 List<Integer> base = createList(Integer.class, 1, 2, 2); 138 List<Integer> copy = createList(Integer.class, 1, 2, 2); 139 ImmutableList<Integer> otherType = ImmutableList.of(1, 2, 2); 140 List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); 141 List<Integer> diffValue = createList(Integer.class, 1, 2, 3); 142 List<Integer> diffLength = createList(Integer.class, 1, 2); 143 List<Integer> empty = createList(Integer.class); 144 145 assertThat(Lists.equalsImpl(base, copy)).isTrue(); 146 assertThat(Lists.equalsImpl(base, otherType)).isTrue(); 147 148 List<@Nullable Object> unEqualItems = 149 Arrays.asList(outOfOrder, diffValue, diffLength, empty, null, new Object()); 150 for (Object other : unEqualItems) { 151 assertWithMessage("%s", other).that(Lists.equalsImpl(base, other)).isFalse(); 152 } 153 } 154 testAddAllImpl()155 public void testAddAllImpl() { 156 if (getExample().modifiability() != Modifiability.ALL) { 157 return; 158 } 159 List<String> toTest = createList(String.class); 160 161 List<Iterable<String>> toAdd = 162 ImmutableList.of( 163 Collections.singleton("A"), 164 Collections.emptyList(), 165 ImmutableList.of("A", "B", "C"), 166 ImmutableList.of("D", "E")); 167 List<Integer> indexes = ImmutableList.of(0, 0, 1, 3); 168 List<List<String>> expected = 169 ImmutableList.of( 170 ImmutableList.of("A"), 171 ImmutableList.of("A"), 172 ImmutableList.of("A", "A", "B", "C"), 173 ImmutableList.of("A", "A", "D", "E", "B", "C")); 174 175 String format = "Adding %s at %s"; 176 for (int i = 0; i < toAdd.size(); i++) { 177 int index = indexes.get(i); 178 Iterable<String> iterableToAdd = toAdd.get(i); 179 boolean expectedChanged = iterableToAdd.iterator().hasNext(); 180 assertWithMessage(format, iterableToAdd, index) 181 .that(Lists.addAllImpl(toTest, index, iterableToAdd)) 182 .isEqualTo(expectedChanged); 183 assertWithMessage(format, iterableToAdd, index) 184 .that(toTest) 185 .containsExactlyElementsIn(expected.get(i)); 186 } 187 } 188 testIndexOfImpl_nonNull()189 public void testIndexOfImpl_nonNull() { 190 List<Integer> toTest = createList(Integer.class, 5, 2, -1, 2, 1, 10, 5); 191 int[] expected = {0, 1, 2, 1, 4, 5, 0}; 192 checkIndexOf(toTest, expected); 193 } 194 testIndexOfImpl_null()195 public void testIndexOfImpl_null() { 196 List<String> toTest; 197 try { 198 toTest = createList(String.class, null, "A", "B", null, "C", null); 199 } catch (NullPointerException e) { 200 // example cannot handle nulls, test invalid 201 return; 202 } 203 int[] expected = {0, 1, 2, 0, 4, 0}; 204 checkIndexOf(toTest, expected); 205 } 206 testLastIndexOfImpl_nonNull()207 public void testLastIndexOfImpl_nonNull() { 208 List<Integer> toTest = createList(Integer.class, 1, 5, 6, 10, 1, 3, 2, 1, 6); 209 int[] expected = {7, 1, 8, 3, 7, 5, 6, 7, 8}; 210 checkLastIndexOf(toTest, expected); 211 } 212 testLastIndexOfImpl_null()213 public void testLastIndexOfImpl_null() { 214 List<String> toTest; 215 try { 216 toTest = createList(String.class, null, "A", "B", null, "C", "B"); 217 } catch (NullPointerException e) { 218 // example cannot handle nulls, test invalid 219 return; 220 } 221 int[] expected = {3, 1, 5, 3, 4, 5}; 222 checkLastIndexOf(toTest, expected); 223 } 224 checkIndexOf(List<?> toTest, int[] expected)225 private void checkIndexOf(List<?> toTest, int[] expected) { 226 int index = 0; 227 for (Object obj : toTest) { 228 String name = "toTest[" + index + "] (" + obj + ")"; 229 assertWithMessage(name).that(Lists.indexOfImpl(toTest, obj)).isEqualTo(expected[index]); 230 index++; 231 } 232 } 233 checkLastIndexOf(List<?> toTest, int[] expected)234 private void checkLastIndexOf(List<?> toTest, int[] expected) { 235 int index = 0; 236 for (Object obj : toTest) { 237 String name = "toTest[" + index + "] (" + obj + ")"; 238 assertWithMessage(name).that(Lists.lastIndexOfImpl(toTest, obj)).isEqualTo(expected[index]); 239 index++; 240 } 241 } 242 243 @SafeVarargs 244 @SuppressWarnings("varargs") createList(Class<T> listType, T... contents)245 private final <T> List<T> createList(Class<T> listType, T... contents) { 246 return getExample().createList(listType, Arrays.asList(contents)); 247 } 248 249 private static final class ArrayListExample extends ListExample { 250 ArrayListExample(String name)251 protected ArrayListExample(String name) { 252 super(name, Modifiability.ALL); 253 } 254 255 @Override createList(Class<T> listType, Collection<? extends T> contents)256 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 257 return new ArrayList<>(contents); 258 } 259 } 260 261 private static final class LinkedListExample extends ListExample { 262 LinkedListExample(String name)263 protected LinkedListExample(String name) { 264 super(name, Modifiability.ALL); 265 } 266 267 @Override createList(Class<T> listType, Collection<? extends T> contents)268 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 269 return new LinkedList<>(contents); 270 } 271 } 272 273 @GwtIncompatible // Iterables.toArray 274 private static final class ArraysAsListExample extends ListExample { 275 ArraysAsListExample(String name)276 protected ArraysAsListExample(String name) { 277 super(name, Modifiability.BY_ELEMENT); 278 } 279 280 @Override createList(Class<T> listType, Collection<? extends T> contents)281 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 282 T[] array = Iterables.toArray(contents, listType); 283 return Arrays.asList(array); 284 } 285 } 286 287 private static final class ImmutableListExample extends ListExample { 288 ImmutableListExample(String name)289 protected ImmutableListExample(String name) { 290 super(name, Modifiability.NONE); 291 } 292 293 @Override createList(Class<T> listType, Collection<? extends T> contents)294 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 295 return ImmutableList.copyOf(contents); 296 } 297 } 298 299 @J2ktIncompatible 300 @GwtIncompatible // CopyOnWriteArrayList 301 private static final class CopyOnWriteListExample extends ListExample { 302 CopyOnWriteListExample(String name)303 protected CopyOnWriteListExample(String name) { 304 super(name, Modifiability.DIRECT_ONLY); 305 } 306 307 @Override createList(Class<T> listType, Collection<? extends T> contents)308 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 309 return new CopyOnWriteArrayList<>(contents); 310 } 311 } 312 } 313