1 /*
2  * Copyright (C) 2007 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.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.testing.IteratorFeature.UNMODIFIABLE;
21 import static com.google.common.truth.Truth.assertThat;
22 import static java.util.Arrays.asList;
23 import static java.util.Collections.singletonList;
24 
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.annotations.GwtIncompatible;
27 import com.google.common.base.Function;
28 import com.google.common.base.Functions;
29 import com.google.common.collect.testing.IteratorTester;
30 import com.google.common.collect.testing.ListTestSuiteBuilder;
31 import com.google.common.collect.testing.TestStringListGenerator;
32 import com.google.common.collect.testing.features.CollectionFeature;
33 import com.google.common.collect.testing.features.CollectionSize;
34 import com.google.common.collect.testing.features.ListFeature;
35 import com.google.common.collect.testing.google.ListGenerators.CharactersOfCharSequenceGenerator;
36 import com.google.common.collect.testing.google.ListGenerators.CharactersOfStringGenerator;
37 import com.google.common.testing.NullPointerTester;
38 import com.google.common.testing.SerializableTester;
39 import java.io.Serializable;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.Iterator;
44 import java.util.LinkedList;
45 import java.util.List;
46 import java.util.ListIterator;
47 import java.util.NoSuchElementException;
48 import java.util.RandomAccess;
49 import java.util.concurrent.CopyOnWriteArrayList;
50 import junit.framework.Test;
51 import junit.framework.TestCase;
52 import junit.framework.TestSuite;
53 
54 /**
55  * Unit test for {@code Lists}.
56  *
57  * @author Kevin Bourrillion
58  * @author Mike Bostock
59  * @author Jared Levy
60  */
61 @GwtCompatible(emulated = true)
62 public class ListsTest extends TestCase {
63 
64   private static final Collection<Integer> SOME_COLLECTION = asList(0, 1, 1);
65 
66   private static final Iterable<Integer> SOME_ITERABLE = new SomeIterable();
67 
68   private static final class RemoveFirstFunction implements Function<String, String>, Serializable {
69     @Override
apply(String from)70     public String apply(String from) {
71       return (from.length() == 0) ? from : from.substring(1);
72     }
73   }
74 
75   private static class SomeIterable implements Iterable<Integer>, Serializable {
76     @Override
iterator()77     public Iterator<Integer> iterator() {
78       return SOME_COLLECTION.iterator();
79     }
80 
81     private static final long serialVersionUID = 0;
82   }
83 
84   private static final List<Integer> SOME_LIST = Lists.newArrayList(1, 2, 3, 4);
85 
86   private static final List<Integer> SOME_SEQUENTIAL_LIST = Lists.newLinkedList(asList(1, 2, 3, 4));
87 
88   private static final List<String> SOME_STRING_LIST = asList("1", "2", "3", "4");
89 
90   private static final Function<Number, String> SOME_FUNCTION = new SomeFunction();
91 
92   private static class SomeFunction implements Function<Number, String>, Serializable {
93     @Override
apply(Number n)94     public String apply(Number n) {
95       return String.valueOf(n);
96     }
97 
98     private static final long serialVersionUID = 0;
99   }
100 
101   @GwtIncompatible // suite
suite()102   public static Test suite() {
103     TestSuite suite = new TestSuite();
104     suite.addTestSuite(ListsTest.class);
105 
106     suite.addTest(
107         ListTestSuiteBuilder.using(
108                 new TestStringListGenerator() {
109                   @Override
110                   protected List<String> create(String[] elements) {
111                     String[] rest = new String[elements.length - 1];
112                     System.arraycopy(elements, 1, rest, 0, elements.length - 1);
113                     return Lists.asList(elements[0], rest);
114                   }
115                 })
116             .named("Lists.asList, 2 parameter")
117             .withFeatures(
118                 CollectionSize.SEVERAL,
119                 CollectionSize.ONE,
120                 CollectionFeature.SERIALIZABLE,
121                 CollectionFeature.ALLOWS_NULL_VALUES)
122             .createTestSuite());
123 
124     suite.addTest(
125         ListTestSuiteBuilder.using(
126                 new TestStringListGenerator() {
127                   @Override
128                   protected List<String> create(String[] elements) {
129                     String[] rest = new String[elements.length - 2];
130                     System.arraycopy(elements, 2, rest, 0, elements.length - 2);
131                     return Lists.asList(elements[0], elements[1], rest);
132                   }
133                 })
134             .named("Lists.asList, 3 parameter")
135             .withFeatures(
136                 CollectionSize.SEVERAL,
137                 CollectionFeature.SERIALIZABLE,
138                 CollectionFeature.ALLOWS_NULL_VALUES)
139             .createTestSuite());
140 
141     final Function<String, String> removeFirst = new RemoveFirstFunction();
142 
143     suite.addTest(
144         ListTestSuiteBuilder.using(
145                 new TestStringListGenerator() {
146                   @Override
147                   protected List<String> create(String[] elements) {
148                     List<String> fromList = Lists.newArrayList();
149                     for (String element : elements) {
150                       fromList.add("q" + checkNotNull(element));
151                     }
152                     return Lists.transform(fromList, removeFirst);
153                   }
154                 })
155             .named("Lists.transform, random access, no nulls")
156             .withFeatures(
157                 CollectionSize.ANY,
158                 ListFeature.REMOVE_OPERATIONS,
159                 CollectionFeature.SERIALIZABLE,
160                 CollectionFeature.ALLOWS_NULL_QUERIES)
161             .createTestSuite());
162 
163     suite.addTest(
164         ListTestSuiteBuilder.using(
165                 new TestStringListGenerator() {
166                   @Override
167                   protected List<String> create(String[] elements) {
168                     List<String> fromList = Lists.newLinkedList();
169                     for (String element : elements) {
170                       fromList.add("q" + checkNotNull(element));
171                     }
172                     return Lists.transform(fromList, removeFirst);
173                   }
174                 })
175             .named("Lists.transform, sequential access, no nulls")
176             .withFeatures(
177                 CollectionSize.ANY,
178                 ListFeature.REMOVE_OPERATIONS,
179                 CollectionFeature.SERIALIZABLE,
180                 CollectionFeature.ALLOWS_NULL_QUERIES)
181             .createTestSuite());
182 
183     suite.addTest(
184         ListTestSuiteBuilder.using(
185                 new TestStringListGenerator() {
186                   @Override
187                   protected List<String> create(String[] elements) {
188                     List<String> fromList = Lists.newArrayList(elements);
189                     return Lists.transform(fromList, Functions.<String>identity());
190                   }
191                 })
192             .named("Lists.transform, random access, nulls")
193             .withFeatures(
194                 CollectionSize.ANY,
195                 ListFeature.REMOVE_OPERATIONS,
196                 CollectionFeature.SERIALIZABLE,
197                 CollectionFeature.ALLOWS_NULL_VALUES)
198             .createTestSuite());
199 
200     suite.addTest(
201         ListTestSuiteBuilder.using(
202                 new TestStringListGenerator() {
203                   @Override
204                   protected List<String> create(String[] elements) {
205                     List<String> fromList = Lists.newLinkedList(asList(elements));
206                     return Lists.transform(fromList, Functions.<String>identity());
207                   }
208                 })
209             .named("Lists.transform, sequential access, nulls")
210             .withFeatures(
211                 CollectionSize.ANY,
212                 ListFeature.REMOVE_OPERATIONS,
213                 CollectionFeature.SERIALIZABLE,
214                 CollectionFeature.ALLOWS_NULL_VALUES)
215             .createTestSuite());
216 
217     suite.addTest(
218         ListTestSuiteBuilder.using(
219                 new TestStringListGenerator() {
220                   @Override
221                   protected List<String> create(String[] elements) {
222                     List<String> list = Lists.newArrayList();
223                     for (int i = elements.length - 1; i >= 0; i--) {
224                       list.add(elements[i]);
225                     }
226                     return Lists.reverse(list);
227                   }
228                 })
229             .named("Lists.reverse[ArrayList]")
230             .withFeatures(
231                 CollectionSize.ANY,
232                 CollectionFeature.ALLOWS_NULL_VALUES,
233                 ListFeature.GENERAL_PURPOSE)
234             .createTestSuite());
235 
236     suite.addTest(
237         ListTestSuiteBuilder.using(
238                 new TestStringListGenerator() {
239                   @Override
240                   protected List<String> create(String[] elements) {
241                     String[] reverseElements = new String[elements.length];
242                     for (int i = elements.length - 1, j = 0; i >= 0; i--, j++) {
243                       reverseElements[j] = elements[i];
244                     }
245                     return Lists.reverse(asList(reverseElements));
246                   }
247                 })
248             .named("Lists.reverse[Arrays.asList]")
249             .withFeatures(
250                 CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES, ListFeature.SUPPORTS_SET)
251             .createTestSuite());
252 
253     suite.addTest(
254         ListTestSuiteBuilder.using(
255                 new TestStringListGenerator() {
256                   @Override
257                   protected List<String> create(String[] elements) {
258                     List<String> list = Lists.newLinkedList();
259                     for (int i = elements.length - 1; i >= 0; i--) {
260                       list.add(elements[i]);
261                     }
262                     return Lists.reverse(list);
263                   }
264                 })
265             .named("Lists.reverse[LinkedList]")
266             .withFeatures(
267                 CollectionSize.ANY,
268                 CollectionFeature.ALLOWS_NULL_VALUES,
269                 ListFeature.GENERAL_PURPOSE)
270             .createTestSuite());
271 
272     suite.addTest(
273         ListTestSuiteBuilder.using(
274                 new TestStringListGenerator() {
275                   @Override
276                   protected List<String> create(String[] elements) {
277                     ImmutableList.Builder<String> builder = ImmutableList.builder();
278                     for (int i = elements.length - 1; i >= 0; i--) {
279                       builder.add(elements[i]);
280                     }
281                     return Lists.reverse(builder.build());
282                   }
283                 })
284             .named("Lists.reverse[ImmutableList]")
285             .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
286             .createTestSuite());
287 
288     suite.addTest(
289         ListTestSuiteBuilder.using(new CharactersOfStringGenerator())
290             .named("Lists.charactersOf[String]")
291             .withFeatures(
292                 CollectionSize.ANY,
293                 CollectionFeature.SERIALIZABLE,
294                 CollectionFeature.ALLOWS_NULL_QUERIES)
295             .createTestSuite());
296 
297     suite.addTest(
298         ListTestSuiteBuilder.using(new CharactersOfCharSequenceGenerator())
299             .named("Lists.charactersOf[CharSequence]")
300             .withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_QUERIES)
301             .createTestSuite());
302 
303     return suite;
304   }
305 
testCharactersOfIsView()306   public void testCharactersOfIsView() {
307     StringBuilder builder = new StringBuilder("abc");
308     List<Character> chars = Lists.charactersOf(builder);
309     assertEquals(asList('a', 'b', 'c'), chars);
310     builder.append("def");
311     assertEquals(asList('a', 'b', 'c', 'd', 'e', 'f'), chars);
312     builder.deleteCharAt(5);
313     assertEquals(asList('a', 'b', 'c', 'd', 'e'), chars);
314   }
315 
testNewArrayListEmpty()316   public void testNewArrayListEmpty() {
317     ArrayList<Integer> list = Lists.newArrayList();
318     assertEquals(Collections.emptyList(), list);
319   }
320 
testNewArrayListWithCapacity()321   public void testNewArrayListWithCapacity() {
322     ArrayList<Integer> list = Lists.newArrayListWithCapacity(0);
323     assertEquals(Collections.emptyList(), list);
324 
325     ArrayList<Integer> bigger = Lists.newArrayListWithCapacity(256);
326     assertEquals(Collections.emptyList(), bigger);
327   }
328 
testNewArrayListWithCapacity_negative()329   public void testNewArrayListWithCapacity_negative() {
330     try {
331       Lists.newArrayListWithCapacity(-1);
332       fail();
333     } catch (IllegalArgumentException expected) {
334     }
335   }
336 
testNewArrayListWithExpectedSize()337   public void testNewArrayListWithExpectedSize() {
338     ArrayList<Integer> list = Lists.newArrayListWithExpectedSize(0);
339     assertEquals(Collections.emptyList(), list);
340 
341     ArrayList<Integer> bigger = Lists.newArrayListWithExpectedSize(256);
342     assertEquals(Collections.emptyList(), bigger);
343   }
344 
testNewArrayListWithExpectedSize_negative()345   public void testNewArrayListWithExpectedSize_negative() {
346     try {
347       Lists.newArrayListWithExpectedSize(-1);
348       fail();
349     } catch (IllegalArgumentException expected) {
350     }
351   }
352 
testNewArrayListVarArgs()353   public void testNewArrayListVarArgs() {
354     ArrayList<Integer> list = Lists.newArrayList(0, 1, 1);
355     assertEquals(SOME_COLLECTION, list);
356   }
357 
testComputeArrayListCapacity()358   public void testComputeArrayListCapacity() {
359     assertEquals(5, Lists.computeArrayListCapacity(0));
360     assertEquals(13, Lists.computeArrayListCapacity(8));
361     assertEquals(89, Lists.computeArrayListCapacity(77));
362     assertEquals(22000005, Lists.computeArrayListCapacity(20000000));
363     assertEquals(Integer.MAX_VALUE, Lists.computeArrayListCapacity(Integer.MAX_VALUE - 1000));
364   }
365 
testNewArrayListFromCollection()366   public void testNewArrayListFromCollection() {
367     ArrayList<Integer> list = Lists.newArrayList(SOME_COLLECTION);
368     assertEquals(SOME_COLLECTION, list);
369   }
370 
testNewArrayListFromIterable()371   public void testNewArrayListFromIterable() {
372     ArrayList<Integer> list = Lists.newArrayList(SOME_ITERABLE);
373     assertEquals(SOME_COLLECTION, list);
374   }
375 
testNewArrayListFromIterator()376   public void testNewArrayListFromIterator() {
377     ArrayList<Integer> list = Lists.newArrayList(SOME_COLLECTION.iterator());
378     assertEquals(SOME_COLLECTION, list);
379   }
380 
testNewLinkedListEmpty()381   public void testNewLinkedListEmpty() {
382     LinkedList<Integer> list = Lists.newLinkedList();
383     assertEquals(Collections.emptyList(), list);
384   }
385 
testNewLinkedListFromCollection()386   public void testNewLinkedListFromCollection() {
387     LinkedList<Integer> list = Lists.newLinkedList(SOME_COLLECTION);
388     assertEquals(SOME_COLLECTION, list);
389   }
390 
testNewLinkedListFromIterable()391   public void testNewLinkedListFromIterable() {
392     LinkedList<Integer> list = Lists.newLinkedList(SOME_ITERABLE);
393     assertEquals(SOME_COLLECTION, list);
394   }
395 
396   @GwtIncompatible // CopyOnWriteArrayList
testNewCOWALEmpty()397   public void testNewCOWALEmpty() {
398     CopyOnWriteArrayList<Integer> list = Lists.newCopyOnWriteArrayList();
399     assertEquals(Collections.emptyList(), list);
400   }
401 
402   @GwtIncompatible // CopyOnWriteArrayList
testNewCOWALFromIterable()403   public void testNewCOWALFromIterable() {
404     CopyOnWriteArrayList<Integer> list = Lists.newCopyOnWriteArrayList(SOME_ITERABLE);
405     assertEquals(SOME_COLLECTION, list);
406   }
407 
408   @GwtIncompatible // NullPointerTester
testNullPointerExceptions()409   public void testNullPointerExceptions() {
410     NullPointerTester tester = new NullPointerTester();
411     tester.testAllPublicStaticMethods(Lists.class);
412   }
413 
414   /**
415    * This is just here to illustrate how {@code Arrays#asList} differs from {@code
416    * Lists#newArrayList}.
417    */
testArraysAsList()418   public void testArraysAsList() {
419     List<String> ourWay = Lists.newArrayList("foo", "bar", "baz");
420     List<String> otherWay = asList("foo", "bar", "baz");
421 
422     // They're logically equal
423     assertEquals(ourWay, otherWay);
424 
425     // The result of Arrays.asList() is mutable
426     otherWay.set(0, "FOO");
427     assertEquals("FOO", otherWay.get(0));
428 
429     // But it can't grow
430     try {
431       otherWay.add("nope");
432       fail("no exception thrown");
433     } catch (UnsupportedOperationException expected) {
434     }
435 
436     // And it can't shrink
437     try {
438       otherWay.remove(2);
439       fail("no exception thrown");
440     } catch (UnsupportedOperationException expected) {
441     }
442   }
443 
444   @GwtIncompatible // SerializableTester
testAsList1()445   public void testAsList1() {
446     List<String> list = Lists.asList("foo", new String[] {"bar", "baz"});
447     checkFooBarBazList(list);
448     SerializableTester.reserializeAndAssert(list);
449     assertTrue(list instanceof RandomAccess);
450 
451     new IteratorTester<String>(
452         5, UNMODIFIABLE, asList("foo", "bar", "baz"), IteratorTester.KnownOrder.KNOWN_ORDER) {
453       @Override
454       protected Iterator<String> newTargetIterator() {
455         return Lists.asList("foo", new String[] {"bar", "baz"}).iterator();
456       }
457     }.test();
458   }
459 
checkFooBarBazList(List<String> list)460   private void checkFooBarBazList(List<String> list) {
461     assertThat(list).containsExactly("foo", "bar", "baz").inOrder();
462     assertEquals(3, list.size());
463     assertIndexIsOutOfBounds(list, -1);
464     assertEquals("foo", list.get(0));
465     assertEquals("bar", list.get(1));
466     assertEquals("baz", list.get(2));
467     assertIndexIsOutOfBounds(list, 3);
468   }
469 
testAsList1Small()470   public void testAsList1Small() {
471     List<String> list = Lists.asList("foo", new String[0]);
472     assertThat(list).contains("foo");
473     assertEquals(1, list.size());
474     assertIndexIsOutOfBounds(list, -1);
475     assertEquals("foo", list.get(0));
476     assertIndexIsOutOfBounds(list, 1);
477     assertTrue(list instanceof RandomAccess);
478 
479     new IteratorTester<String>(
480         3, UNMODIFIABLE, singletonList("foo"), IteratorTester.KnownOrder.KNOWN_ORDER) {
481       @Override
482       protected Iterator<String> newTargetIterator() {
483         return Lists.asList("foo", new String[0]).iterator();
484       }
485     }.test();
486   }
487 
testAsList2()488   public void testAsList2() {
489     List<String> list = Lists.asList("foo", "bar", new String[] {"baz"});
490     checkFooBarBazList(list);
491     assertTrue(list instanceof RandomAccess);
492 
493     new IteratorTester<String>(
494         5, UNMODIFIABLE, asList("foo", "bar", "baz"), IteratorTester.KnownOrder.KNOWN_ORDER) {
495       @Override
496       protected Iterator<String> newTargetIterator() {
497         return Lists.asList("foo", "bar", new String[] {"baz"}).iterator();
498       }
499     }.test();
500   }
501 
502   @GwtIncompatible // SerializableTester
testAsList2Small()503   public void testAsList2Small() {
504     List<String> list = Lists.asList("foo", "bar", new String[0]);
505     assertThat(list).containsExactly("foo", "bar").inOrder();
506     assertEquals(2, list.size());
507     assertIndexIsOutOfBounds(list, -1);
508     assertEquals("foo", list.get(0));
509     assertEquals("bar", list.get(1));
510     assertIndexIsOutOfBounds(list, 2);
511     SerializableTester.reserializeAndAssert(list);
512     assertTrue(list instanceof RandomAccess);
513 
514     new IteratorTester<String>(
515         5, UNMODIFIABLE, asList("foo", "bar"), IteratorTester.KnownOrder.KNOWN_ORDER) {
516       @Override
517       protected Iterator<String> newTargetIterator() {
518         return Lists.asList("foo", "bar", new String[0]).iterator();
519       }
520     }.test();
521   }
522 
assertIndexIsOutOfBounds(List<String> list, int index)523   private static void assertIndexIsOutOfBounds(List<String> list, int index) {
524     try {
525       list.get(index);
526       fail();
527     } catch (IndexOutOfBoundsException expected) {
528     }
529   }
530 
testReverseViewRandomAccess()531   public void testReverseViewRandomAccess() {
532     List<Integer> fromList = Lists.newArrayList(SOME_LIST);
533     List<Integer> toList = Lists.reverse(fromList);
534     assertReverseView(fromList, toList);
535   }
536 
testReverseViewSequential()537   public void testReverseViewSequential() {
538     List<Integer> fromList = Lists.newLinkedList(SOME_SEQUENTIAL_LIST);
539     List<Integer> toList = Lists.reverse(fromList);
540     assertReverseView(fromList, toList);
541   }
542 
assertReverseView(List<Integer> fromList, List<Integer> toList)543   private static void assertReverseView(List<Integer> fromList, List<Integer> toList) {
544     /* fromList modifications reflected in toList */
545     fromList.set(0, 5);
546     assertEquals(asList(4, 3, 2, 5), toList);
547     fromList.add(6);
548     assertEquals(asList(6, 4, 3, 2, 5), toList);
549     fromList.add(2, 9);
550     assertEquals(asList(6, 4, 3, 9, 2, 5), toList);
551     fromList.remove(Integer.valueOf(2));
552     assertEquals(asList(6, 4, 3, 9, 5), toList);
553     fromList.remove(3);
554     assertEquals(asList(6, 3, 9, 5), toList);
555 
556     /* toList modifications reflected in fromList */
557     toList.remove(0);
558     assertEquals(asList(5, 9, 3), fromList);
559     toList.add(7);
560     assertEquals(asList(7, 5, 9, 3), fromList);
561     toList.add(5);
562     assertEquals(asList(5, 7, 5, 9, 3), fromList);
563     toList.remove(Integer.valueOf(5));
564     assertEquals(asList(5, 7, 9, 3), fromList);
565     toList.set(1, 8);
566     assertEquals(asList(5, 7, 8, 3), fromList);
567     toList.clear();
568     assertEquals(Collections.emptyList(), fromList);
569   }
570 
571   @SafeVarargs
list(E... elements)572   private static <E> List<E> list(E... elements) {
573     return ImmutableList.copyOf(elements);
574   }
575 
576   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_binary1x1()577   public void testCartesianProduct_binary1x1() {
578     assertThat(Lists.cartesianProduct(list(1), list(2))).contains(list(1, 2));
579   }
580 
581   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_binary1x2()582   public void testCartesianProduct_binary1x2() {
583     assertThat(Lists.cartesianProduct(list(1), list(2, 3)))
584         .containsExactly(list(1, 2), list(1, 3))
585         .inOrder();
586   }
587 
588   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_binary2x2()589   public void testCartesianProduct_binary2x2() {
590     assertThat(Lists.cartesianProduct(list(1, 2), list(3, 4)))
591         .containsExactly(list(1, 3), list(1, 4), list(2, 3), list(2, 4))
592         .inOrder();
593   }
594 
595   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_2x2x2()596   public void testCartesianProduct_2x2x2() {
597     assertThat(Lists.cartesianProduct(list(0, 1), list(0, 1), list(0, 1)))
598         .containsExactly(
599             list(0, 0, 0),
600             list(0, 0, 1),
601             list(0, 1, 0),
602             list(0, 1, 1),
603             list(1, 0, 0),
604             list(1, 0, 1),
605             list(1, 1, 0),
606             list(1, 1, 1))
607         .inOrder();
608   }
609 
610   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_contains()611   public void testCartesianProduct_contains() {
612     List<List<Integer>> actual = Lists.cartesianProduct(list(1, 2), list(3, 4));
613     assertTrue(actual.contains(list(1, 3)));
614     assertTrue(actual.contains(list(1, 4)));
615     assertTrue(actual.contains(list(2, 3)));
616     assertTrue(actual.contains(list(2, 4)));
617     assertFalse(actual.contains(list(3, 1)));
618   }
619 
testCartesianProduct_indexOf()620   public void testCartesianProduct_indexOf() {
621     List<List<Integer>> actual = Lists.cartesianProduct(list(1, 2), list(3, 4));
622     assertEquals(actual.indexOf(list(1, 3)), 0);
623     assertEquals(actual.indexOf(list(1, 4)), 1);
624     assertEquals(actual.indexOf(list(2, 3)), 2);
625     assertEquals(actual.indexOf(list(2, 4)), 3);
626     assertEquals(actual.indexOf(list(3, 1)), -1);
627 
628     assertEquals(actual.indexOf(list(1)), -1);
629     assertEquals(actual.indexOf(list(1, 1, 1)), -1);
630   }
631 
testCartesianProduct_lastIndexOf()632   public void testCartesianProduct_lastIndexOf() {
633     List<List<Integer>> actual = Lists.cartesianProduct(list(1, 1), list(2, 3));
634     assertThat(actual.lastIndexOf(list(1, 2))).isEqualTo(2);
635     assertThat(actual.lastIndexOf(list(1, 3))).isEqualTo(3);
636     assertThat(actual.lastIndexOf(list(1, 1))).isEqualTo(-1);
637 
638     assertThat(actual.lastIndexOf(list(1))).isEqualTo(-1);
639     assertThat(actual.lastIndexOf(list(1, 1, 1))).isEqualTo(-1);
640   }
641 
642   @SuppressWarnings("unchecked") // varargs!
testCartesianProduct_unrelatedTypes()643   public void testCartesianProduct_unrelatedTypes() {
644     List<Integer> x = list(1, 2);
645     List<String> y = list("3", "4");
646 
647     List<Object> exp1 = list((Object) 1, "3");
648     List<Object> exp2 = list((Object) 1, "4");
649     List<Object> exp3 = list((Object) 2, "3");
650     List<Object> exp4 = list((Object) 2, "4");
651 
652     assertThat(Lists.<Object>cartesianProduct(x, y))
653         .containsExactly(exp1, exp2, exp3, exp4)
654         .inOrder();
655   }
656 
657   @SuppressWarnings("unchecked") // varargs!
testCartesianProductTooBig()658   public void testCartesianProductTooBig() {
659     List<String> list = Collections.nCopies(10000, "foo");
660     try {
661       Lists.cartesianProduct(list, list, list, list, list);
662       fail("Expected IAE");
663     } catch (IllegalArgumentException expected) {
664     }
665   }
666 
testTransformHashCodeRandomAccess()667   public void testTransformHashCodeRandomAccess() {
668     List<String> list = Lists.transform(SOME_LIST, SOME_FUNCTION);
669     assertEquals(SOME_STRING_LIST.hashCode(), list.hashCode());
670   }
671 
testTransformHashCodeSequential()672   public void testTransformHashCodeSequential() {
673     List<String> list = Lists.transform(SOME_SEQUENTIAL_LIST, SOME_FUNCTION);
674     assertEquals(SOME_STRING_LIST.hashCode(), list.hashCode());
675   }
676 
testTransformModifiableRandomAccess()677   public void testTransformModifiableRandomAccess() {
678     List<Integer> fromList = Lists.newArrayList(SOME_LIST);
679     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
680     assertTransformModifiable(list);
681   }
682 
testTransformModifiableSequential()683   public void testTransformModifiableSequential() {
684     List<Integer> fromList = Lists.newLinkedList(SOME_SEQUENTIAL_LIST);
685     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
686     assertTransformModifiable(list);
687   }
688 
assertTransformModifiable(List<String> list)689   private static void assertTransformModifiable(List<String> list) {
690     try {
691       list.add("5");
692       fail("transformed list is addable");
693     } catch (UnsupportedOperationException expected) {
694     }
695     list.remove(0);
696     assertEquals(asList("2", "3", "4"), list);
697     list.remove("3");
698     assertEquals(asList("2", "4"), list);
699     try {
700       list.set(0, "5");
701       fail("transformed list is setable");
702     } catch (UnsupportedOperationException expected) {
703     }
704     list.clear();
705     assertEquals(Collections.emptyList(), list);
706   }
707 
testTransformViewRandomAccess()708   public void testTransformViewRandomAccess() {
709     List<Integer> fromList = Lists.newArrayList(SOME_LIST);
710     List<String> toList = Lists.transform(fromList, SOME_FUNCTION);
711     assertTransformView(fromList, toList);
712   }
713 
testTransformViewSequential()714   public void testTransformViewSequential() {
715     List<Integer> fromList = Lists.newLinkedList(SOME_SEQUENTIAL_LIST);
716     List<String> toList = Lists.transform(fromList, SOME_FUNCTION);
717     assertTransformView(fromList, toList);
718   }
719 
assertTransformView(List<Integer> fromList, List<String> toList)720   private static void assertTransformView(List<Integer> fromList, List<String> toList) {
721     /* fromList modifications reflected in toList */
722     fromList.set(0, 5);
723     assertEquals(asList("5", "2", "3", "4"), toList);
724     fromList.add(6);
725     assertEquals(asList("5", "2", "3", "4", "6"), toList);
726     fromList.remove(Integer.valueOf(2));
727     assertEquals(asList("5", "3", "4", "6"), toList);
728     fromList.remove(2);
729     assertEquals(asList("5", "3", "6"), toList);
730 
731     /* toList modifications reflected in fromList */
732     toList.remove(2);
733     assertEquals(asList(5, 3), fromList);
734     toList.remove("5");
735     assertEquals(asList(3), fromList);
736     toList.clear();
737     assertEquals(Collections.emptyList(), fromList);
738   }
739 
testTransformRandomAccess()740   public void testTransformRandomAccess() {
741     List<String> list = Lists.transform(SOME_LIST, SOME_FUNCTION);
742     assertTrue(list instanceof RandomAccess);
743   }
744 
testTransformSequential()745   public void testTransformSequential() {
746     List<String> list = Lists.transform(SOME_SEQUENTIAL_LIST, SOME_FUNCTION);
747     assertFalse(list instanceof RandomAccess);
748   }
749 
testTransformListIteratorRandomAccess()750   public void testTransformListIteratorRandomAccess() {
751     List<Integer> fromList = Lists.newArrayList(SOME_LIST);
752     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
753     assertTransformListIterator(list);
754   }
755 
testTransformListIteratorSequential()756   public void testTransformListIteratorSequential() {
757     List<Integer> fromList = Lists.newLinkedList(SOME_SEQUENTIAL_LIST);
758     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
759     assertTransformListIterator(list);
760   }
761 
testTransformPreservesIOOBEsThrownByFunction()762   public void testTransformPreservesIOOBEsThrownByFunction() {
763     try {
764       Lists.transform(
765               ImmutableList.of("foo", "bar"),
766               new Function<String, String>() {
767                 @Override
768                 public String apply(String input) {
769                   throw new IndexOutOfBoundsException();
770                 }
771               })
772           .toArray();
773       fail();
774     } catch (IndexOutOfBoundsException expected) {
775       // success
776     }
777   }
778 
assertTransformListIterator(List<String> list)779   private static void assertTransformListIterator(List<String> list) {
780     ListIterator<String> iterator = list.listIterator(1);
781     assertEquals(1, iterator.nextIndex());
782     assertEquals("2", iterator.next());
783     assertEquals("3", iterator.next());
784     assertEquals("4", iterator.next());
785     assertEquals(4, iterator.nextIndex());
786     try {
787       iterator.next();
788       fail("did not detect end of list");
789     } catch (NoSuchElementException expected) {
790     }
791     assertEquals(3, iterator.previousIndex());
792     assertEquals("4", iterator.previous());
793     assertEquals("3", iterator.previous());
794     assertEquals("2", iterator.previous());
795     assertTrue(iterator.hasPrevious());
796     assertEquals("1", iterator.previous());
797     assertFalse(iterator.hasPrevious());
798     assertEquals(-1, iterator.previousIndex());
799     try {
800       iterator.previous();
801       fail("did not detect beginning of list");
802     } catch (NoSuchElementException expected) {
803     }
804     iterator.remove();
805     assertEquals(asList("2", "3", "4"), list);
806     assertFalse(list.isEmpty());
807 
808     // An UnsupportedOperationException or IllegalStateException may occur.
809     try {
810       iterator.add("1");
811       fail("transformed list iterator is addable");
812     } catch (UnsupportedOperationException expected) {
813     } catch (IllegalStateException expected) {
814     }
815     try {
816       iterator.set("1");
817       fail("transformed list iterator is settable");
818     } catch (UnsupportedOperationException expected) {
819     } catch (IllegalStateException expected) {
820     }
821   }
822 
testTransformIteratorRandomAccess()823   public void testTransformIteratorRandomAccess() {
824     List<Integer> fromList = Lists.newArrayList(SOME_LIST);
825     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
826     assertTransformIterator(list);
827   }
828 
testTransformIteratorSequential()829   public void testTransformIteratorSequential() {
830     List<Integer> fromList = Lists.newLinkedList(SOME_SEQUENTIAL_LIST);
831     List<String> list = Lists.transform(fromList, SOME_FUNCTION);
832     assertTransformIterator(list);
833   }
834 
835   /**
836    * This test depends on the fact that {@code AbstractSequentialList.iterator} transforms the
837    * {@code iterator()} call into a call on {@code listIterator(int)}. This is fine because the
838    * behavior is clearly documented so it's not expected to change.
839    */
testTransformedSequentialIterationUsesBackingListIterationOnly()840   public void testTransformedSequentialIterationUsesBackingListIterationOnly() {
841     List<Integer> randomAccessList = Lists.newArrayList(SOME_SEQUENTIAL_LIST);
842     List<Integer> listIteratorOnlyList = new ListIterationOnlyList<>(randomAccessList);
843     List<String> transform = Lists.transform(listIteratorOnlyList, SOME_FUNCTION);
844     assertTrue(
845         Iterables.elementsEqual(transform, Lists.transform(randomAccessList, SOME_FUNCTION)));
846   }
847 
848   private static class ListIterationOnlyList<E> extends ForwardingList<E> {
849     private final List<E> realDelegate;
850 
ListIterationOnlyList(List<E> realDelegate)851     private ListIterationOnlyList(List<E> realDelegate) {
852       this.realDelegate = realDelegate;
853     }
854 
855     @Override
size()856     public int size() {
857       return realDelegate.size();
858     }
859 
860     @Override
listIterator(int index)861     public ListIterator<E> listIterator(int index) {
862       return realDelegate.listIterator(index);
863     }
864 
865     @Override
delegate()866     protected List<E> delegate() {
867       throw new UnsupportedOperationException("This list only supports ListIterator");
868     }
869   }
870 
assertTransformIterator(List<String> list)871   private static void assertTransformIterator(List<String> list) {
872     Iterator<String> iterator = list.iterator();
873     assertTrue(iterator.hasNext());
874     assertEquals("1", iterator.next());
875     assertTrue(iterator.hasNext());
876     assertEquals("2", iterator.next());
877     assertTrue(iterator.hasNext());
878     assertEquals("3", iterator.next());
879     assertTrue(iterator.hasNext());
880     assertEquals("4", iterator.next());
881     assertFalse(iterator.hasNext());
882     try {
883       iterator.next();
884       fail("did not detect end of list");
885     } catch (NoSuchElementException expected) {
886     }
887     iterator.remove();
888     assertEquals(asList("1", "2", "3"), list);
889     assertFalse(iterator.hasNext());
890   }
891 
testPartition_badSize()892   public void testPartition_badSize() {
893     List<Integer> source = Collections.singletonList(1);
894     try {
895       Lists.partition(source, 0);
896       fail();
897     } catch (IllegalArgumentException expected) {
898     }
899   }
900 
testPartition_empty()901   public void testPartition_empty() {
902     List<Integer> source = Collections.emptyList();
903     List<List<Integer>> partitions = Lists.partition(source, 1);
904     assertTrue(partitions.isEmpty());
905     assertEquals(0, partitions.size());
906   }
907 
testPartition_1_1()908   public void testPartition_1_1() {
909     List<Integer> source = Collections.singletonList(1);
910     List<List<Integer>> partitions = Lists.partition(source, 1);
911     assertEquals(1, partitions.size());
912     assertEquals(Collections.singletonList(1), partitions.get(0));
913   }
914 
testPartition_1_2()915   public void testPartition_1_2() {
916     List<Integer> source = Collections.singletonList(1);
917     List<List<Integer>> partitions = Lists.partition(source, 2);
918     assertEquals(1, partitions.size());
919     assertEquals(Collections.singletonList(1), partitions.get(0));
920   }
921 
testPartition_2_1()922   public void testPartition_2_1() {
923     List<Integer> source = asList(1, 2);
924     List<List<Integer>> partitions = Lists.partition(source, 1);
925     assertEquals(2, partitions.size());
926     assertEquals(Collections.singletonList(1), partitions.get(0));
927     assertEquals(Collections.singletonList(2), partitions.get(1));
928   }
929 
testPartition_3_2()930   public void testPartition_3_2() {
931     List<Integer> source = asList(1, 2, 3);
932     List<List<Integer>> partitions = Lists.partition(source, 2);
933     assertEquals(2, partitions.size());
934     assertEquals(asList(1, 2), partitions.get(0));
935     assertEquals(asList(3), partitions.get(1));
936   }
937 
938   @GwtIncompatible // ArrayList.subList doesn't implement RandomAccess in GWT.
testPartitionRandomAccessTrue()939   public void testPartitionRandomAccessTrue() {
940     List<Integer> source = asList(1, 2, 3);
941     List<List<Integer>> partitions = Lists.partition(source, 2);
942 
943     assertTrue(
944         "partition should be RandomAccess, but not: " + partitions.getClass(),
945         partitions instanceof RandomAccess);
946 
947     assertTrue(
948         "partition[0] should be RandomAccess, but not: " + partitions.get(0).getClass(),
949         partitions.get(0) instanceof RandomAccess);
950 
951     assertTrue(
952         "partition[1] should be RandomAccess, but not: " + partitions.get(1).getClass(),
953         partitions.get(1) instanceof RandomAccess);
954   }
955 
testPartitionRandomAccessFalse()956   public void testPartitionRandomAccessFalse() {
957     List<Integer> source = Lists.newLinkedList(asList(1, 2, 3));
958     List<List<Integer>> partitions = Lists.partition(source, 2);
959     assertFalse(partitions instanceof RandomAccess);
960     assertFalse(partitions.get(0) instanceof RandomAccess);
961     assertFalse(partitions.get(1) instanceof RandomAccess);
962   }
963 
964   // TODO: use the ListTestSuiteBuilder
965 
testPartition_view()966   public void testPartition_view() {
967     List<Integer> list = asList(1, 2, 3);
968     List<List<Integer>> partitions = Lists.partition(list, 3);
969 
970     // Changes before the partition is retrieved are reflected
971     list.set(0, 3);
972 
973     Iterator<List<Integer>> iterator = partitions.iterator();
974 
975     // Changes before the partition is retrieved are reflected
976     list.set(1, 4);
977 
978     List<Integer> first = iterator.next();
979 
980     // Changes after are too (unlike Iterables.partition)
981     list.set(2, 5);
982 
983     assertEquals(asList(3, 4, 5), first);
984 
985     // Changes to a sublist also write through to the original list
986     first.set(1, 6);
987     assertEquals(asList(3, 6, 5), list);
988   }
989 
testPartitionSize_1()990   public void testPartitionSize_1() {
991     List<Integer> list = asList(1, 2, 3);
992     assertEquals(1, Lists.partition(list, Integer.MAX_VALUE).size());
993     assertEquals(1, Lists.partition(list, Integer.MAX_VALUE - 1).size());
994   }
995 
996   @GwtIncompatible // cannot do such a big explicit copy
testPartitionSize_2()997   public void testPartitionSize_2() {
998     assertEquals(2, Lists.partition(Collections.nCopies(0x40000001, 1), 0x40000000).size());
999   }
1000 }
1001