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