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 modifiablity 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 @Override getName()103 public String getName() { 104 return example == null ? super.getName() : buildTestName(); 105 } 106 buildTestName()107 private String buildTestName() { 108 return super.getName() + ":" + example.getName(); 109 } 110 testHashCodeImpl()111 public void testHashCodeImpl() { 112 List<Integer> base = createList(Integer.class, 1, 2, 2); 113 List<Integer> copy = createList(Integer.class, 1, 2, 2); 114 List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); 115 List<Integer> diffValue = createList(Integer.class, 1, 2, 4); 116 List<Integer> diffLength = createList(Integer.class, 1, 2); 117 List<Integer> empty = createList(Integer.class); 118 119 assertThat(Lists.hashCodeImpl(base)).isEqualTo(Lists.hashCodeImpl(copy)); 120 121 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(outOfOrder)); 122 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffValue)); 123 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(diffLength)); 124 assertThat(Lists.hashCodeImpl(base)).isNotEqualTo(Lists.hashCodeImpl(empty)); 125 } 126 testEqualsImpl()127 public void testEqualsImpl() { 128 List<Integer> base = createList(Integer.class, 1, 2, 2); 129 List<Integer> copy = createList(Integer.class, 1, 2, 2); 130 ImmutableList<Integer> otherType = ImmutableList.of(1, 2, 2); 131 List<Integer> outOfOrder = createList(Integer.class, 2, 2, 1); 132 List<Integer> diffValue = createList(Integer.class, 1, 2, 3); 133 List<Integer> diffLength = createList(Integer.class, 1, 2); 134 List<Integer> empty = createList(Integer.class); 135 136 assertThat(Lists.equalsImpl(base, copy)).isTrue(); 137 assertThat(Lists.equalsImpl(base, otherType)).isTrue(); 138 139 List<Object> unEqualItems = 140 Arrays.asList(outOfOrder, diffValue, diffLength, empty, null, new Object()); 141 for (Object other : unEqualItems) { 142 assertWithMessage("%s", other).that(Lists.equalsImpl(base, other)).isFalse(); 143 } 144 } 145 testAddAllImpl()146 public void testAddAllImpl() { 147 if (getExample().modifiability() != Modifiability.ALL) { 148 return; 149 } 150 List<String> toTest = createList(String.class); 151 152 List<Iterable<String>> toAdd = 153 ImmutableList.of( 154 Collections.singleton("A"), 155 Collections.emptyList(), 156 ImmutableList.of("A", "B", "C"), 157 ImmutableList.of("D", "E")); 158 List<Integer> indexes = ImmutableList.of(0, 0, 1, 3); 159 List<List<String>> expected = 160 ImmutableList.of( 161 ImmutableList.of("A"), 162 ImmutableList.of("A"), 163 ImmutableList.of("A", "A", "B", "C"), 164 ImmutableList.of("A", "A", "D", "E", "B", "C")); 165 166 String format = "Adding %s at %s"; 167 for (int i = 0; i < toAdd.size(); i++) { 168 int index = indexes.get(i); 169 Iterable<String> iterableToAdd = toAdd.get(i); 170 boolean expectedChanged = iterableToAdd.iterator().hasNext(); 171 assertWithMessage(format, iterableToAdd, index) 172 .that(Lists.addAllImpl(toTest, index, iterableToAdd)) 173 .isEqualTo(expectedChanged); 174 assertWithMessage(format, iterableToAdd, index) 175 .that(toTest) 176 .containsExactlyElementsIn(expected.get(i)); 177 } 178 } 179 testIndexOfImpl_nonNull()180 public void testIndexOfImpl_nonNull() { 181 List<Integer> toTest = createList(Integer.class, 5, 2, -1, 2, 1, 10, 5); 182 int[] expected = {0, 1, 2, 1, 4, 5, 0}; 183 checkIndexOf(toTest, expected); 184 } 185 testIndexOfImpl_null()186 public void testIndexOfImpl_null() { 187 List<String> toTest; 188 try { 189 toTest = createList(String.class, null, "A", "B", null, "C", null); 190 } catch (NullPointerException e) { 191 // example cannot handle nulls, test invalid 192 return; 193 } 194 int[] expected = {0, 1, 2, 0, 4, 0}; 195 checkIndexOf(toTest, expected); 196 } 197 testLastIndexOfImpl_nonNull()198 public void testLastIndexOfImpl_nonNull() { 199 List<Integer> toTest = createList(Integer.class, 1, 5, 6, 10, 1, 3, 2, 1, 6); 200 int[] expected = {7, 1, 8, 3, 7, 5, 6, 7, 8}; 201 checkLastIndexOf(toTest, expected); 202 } 203 testLastIndexOfImpl_null()204 public void testLastIndexOfImpl_null() { 205 List<String> toTest; 206 try { 207 toTest = createList(String.class, null, "A", "B", null, "C", "B"); 208 } catch (NullPointerException e) { 209 // example cannot handle nulls, test invalid 210 return; 211 } 212 int[] expected = {3, 1, 5, 3, 4, 5}; 213 checkLastIndexOf(toTest, expected); 214 } 215 checkIndexOf(List<?> toTest, int[] expected)216 private void checkIndexOf(List<?> toTest, int[] expected) { 217 int index = 0; 218 for (Object obj : toTest) { 219 String name = "toTest[" + index + "] (" + obj + ")"; 220 assertWithMessage(name).that(Lists.indexOfImpl(toTest, obj)).isEqualTo(expected[index]); 221 index++; 222 } 223 } 224 checkLastIndexOf(List<?> toTest, int[] expected)225 private void checkLastIndexOf(List<?> toTest, int[] expected) { 226 int index = 0; 227 for (Object obj : toTest) { 228 String name = "toTest[" + index + "] (" + obj + ")"; 229 assertWithMessage(name).that(Lists.lastIndexOfImpl(toTest, obj)).isEqualTo(expected[index]); 230 index++; 231 } 232 } 233 234 @SafeVarargs 235 @SuppressWarnings("varargs") createList(Class<T> listType, T... contents)236 private final <T> List<T> createList(Class<T> listType, T... contents) { 237 return getExample().createList(listType, Arrays.asList(contents)); 238 } 239 240 private static final class ArrayListExample extends ListExample { 241 ArrayListExample(String name)242 protected ArrayListExample(String name) { 243 super(name, Modifiability.ALL); 244 } 245 246 @Override createList(Class<T> listType, Collection<? extends T> contents)247 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 248 return new ArrayList<>(contents); 249 } 250 } 251 252 private static final class LinkedListExample extends ListExample { 253 LinkedListExample(String name)254 protected LinkedListExample(String name) { 255 super(name, Modifiability.ALL); 256 } 257 258 @Override createList(Class<T> listType, Collection<? extends T> contents)259 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 260 return new LinkedList<>(contents); 261 } 262 } 263 264 @GwtIncompatible // Iterables.toArray 265 private static final class ArraysAsListExample extends ListExample { 266 ArraysAsListExample(String name)267 protected ArraysAsListExample(String name) { 268 super(name, Modifiability.BY_ELEMENT); 269 } 270 271 @Override createList(Class<T> listType, Collection<? extends T> contents)272 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 273 @SuppressWarnings("unchecked") // safe by contract 274 T[] array = Iterables.toArray(contents, listType); 275 return Arrays.asList(array); 276 } 277 } 278 279 private static final class ImmutableListExample extends ListExample { 280 ImmutableListExample(String name)281 protected ImmutableListExample(String name) { 282 super(name, Modifiability.NONE); 283 } 284 285 @Override createList(Class<T> listType, Collection<? extends T> contents)286 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 287 return ImmutableList.copyOf(contents); 288 } 289 } 290 291 @GwtIncompatible // CopyOnWriteArrayList 292 private static final class CopyOnWriteListExample extends ListExample { 293 CopyOnWriteListExample(String name)294 protected CopyOnWriteListExample(String name) { 295 super(name, Modifiability.DIRECT_ONLY); 296 } 297 298 @Override createList(Class<T> listType, Collection<? extends T> contents)299 public <T> List<T> createList(Class<T> listType, Collection<? extends T> contents) { 300 return new CopyOnWriteArrayList<>(contents); 301 } 302 } 303 } 304