• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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