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.collect.Iterables.getOnlyElement;
20 import static com.google.common.collect.Iterables.unmodifiableIterable;
21 import static com.google.common.collect.Sets.newHashSet;
22 import static java.lang.reflect.Proxy.newProxyInstance;
23 import static java.util.Arrays.asList;
24 
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.annotations.GwtIncompatible;
27 import com.google.common.collect.testing.Helpers;
28 import com.google.common.collect.testing.ListTestSuiteBuilder;
29 import com.google.common.collect.testing.MinimalCollection;
30 import com.google.common.collect.testing.MinimalIterable;
31 import com.google.common.collect.testing.features.CollectionFeature;
32 import com.google.common.collect.testing.features.CollectionSize;
33 import com.google.common.collect.testing.google.ListGenerators.BuilderAddAllListGenerator;
34 import com.google.common.collect.testing.google.ListGenerators.BuilderReversedListGenerator;
35 import com.google.common.collect.testing.google.ListGenerators.ImmutableListHeadSubListGenerator;
36 import com.google.common.collect.testing.google.ListGenerators.ImmutableListMiddleSubListGenerator;
37 import com.google.common.collect.testing.google.ListGenerators.ImmutableListOfGenerator;
38 import com.google.common.collect.testing.google.ListGenerators.ImmutableListTailSubListGenerator;
39 import com.google.common.collect.testing.google.ListGenerators.UnhashableElementsImmutableListGenerator;
40 import com.google.common.collect.testing.testers.ListHashCodeTester;
41 import com.google.common.testing.NullPointerTester;
42 import com.google.common.testing.SerializableTester;
43 
44 import junit.framework.Test;
45 import junit.framework.TestCase;
46 import junit.framework.TestSuite;
47 
48 import java.lang.reflect.InvocationHandler;
49 import java.lang.reflect.InvocationTargetException;
50 import java.lang.reflect.Method;
51 import java.util.Arrays;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Set;
57 import java.util.concurrent.CopyOnWriteArrayList;
58 
59 /**
60  * Unit test for {@link ImmutableList}.
61  *
62  * @author Kevin Bourrillion
63  * @author George van den Driessche
64  * @author Jared Levy
65  */
66 @GwtCompatible(emulated = true)
67 public class ImmutableListTest extends TestCase {
68 
69   @GwtIncompatible("suite")
70   public static Test suite() {
71     TestSuite suite = new TestSuite();
72     suite.addTest(ListTestSuiteBuilder.using(new ImmutableListOfGenerator())
73         .named("ImmutableList")
74         .withFeatures(CollectionSize.ANY,
75             CollectionFeature.SERIALIZABLE,
76             CollectionFeature.ALLOWS_NULL_QUERIES)
77         .createTestSuite());
78     suite.addTest(ListTestSuiteBuilder.using(new BuilderAddAllListGenerator())
79         .named("ImmutableList, built with Builder.add")
80         .withFeatures(CollectionSize.ANY,
81             CollectionFeature.SERIALIZABLE,
82             CollectionFeature.ALLOWS_NULL_QUERIES)
83         .createTestSuite());
84     suite.addTest(ListTestSuiteBuilder.using(new BuilderAddAllListGenerator())
85         .named("ImmutableList, built with Builder.addAll")
86         .withFeatures(CollectionSize.ANY,
87             CollectionFeature.SERIALIZABLE,
88             CollectionFeature.ALLOWS_NULL_QUERIES)
89         .createTestSuite());
90     suite.addTest(ListTestSuiteBuilder.using(new BuilderReversedListGenerator())
91         .named("ImmutableList, reversed")
92         .withFeatures(CollectionSize.ANY,
93             CollectionFeature.SERIALIZABLE,
94             CollectionFeature.ALLOWS_NULL_QUERIES)
95         .createTestSuite());
96     suite.addTest(ListTestSuiteBuilder.using(
97         new ImmutableListHeadSubListGenerator())
98         .named("ImmutableList, head subList")
99         .withFeatures(CollectionSize.ANY,
100             CollectionFeature.SERIALIZABLE,
101             CollectionFeature.ALLOWS_NULL_QUERIES)
102         .createTestSuite());
103     suite.addTest(ListTestSuiteBuilder.using(
104         new ImmutableListTailSubListGenerator())
105         .named("ImmutableList, tail subList")
106         .withFeatures(CollectionSize.ANY,
107             CollectionFeature.SERIALIZABLE,
108             CollectionFeature.ALLOWS_NULL_QUERIES)
109         .createTestSuite());
110     suite.addTest(ListTestSuiteBuilder.using(
111         new ImmutableListMiddleSubListGenerator())
112         .named("ImmutableList, middle subList")
113         .withFeatures(CollectionSize.ANY,
114             CollectionFeature.SERIALIZABLE,
115             CollectionFeature.ALLOWS_NULL_QUERIES)
116         .createTestSuite());
117     suite.addTest(ListTestSuiteBuilder.using(
118         new UnhashableElementsImmutableListGenerator())
119         .suppressing(ListHashCodeTester.getHashCodeMethod())
120         .named("ImmutableList, unhashable values")
121         .withFeatures(CollectionSize.ANY,
122             CollectionFeature.ALLOWS_NULL_QUERIES)
123         .createTestSuite());
124     return suite;
125   }
126 
127   public static class CreationTests extends TestCase {
128     public void testCreation_noArgs() {
129       List<String> list = ImmutableList.of();
130       assertEquals(Collections.emptyList(), list);
131     }
132 
133     public void testCreation_oneElement() {
134       List<String> list = ImmutableList.of("a");
135       assertEquals(Collections.singletonList("a"), list);
136     }
137 
138     public void testCreation_twoElements() {
139       List<String> list = ImmutableList.of("a", "b");
140       assertEquals(Lists.newArrayList("a", "b"), list);
141     }
142 
143     public void testCreation_threeElements() {
144       List<String> list = ImmutableList.of("a", "b", "c");
145       assertEquals(Lists.newArrayList("a", "b", "c"), list);
146     }
147 
148     public void testCreation_fourElements() {
149       List<String> list = ImmutableList.of("a", "b", "c", "d");
150       assertEquals(Lists.newArrayList("a", "b", "c", "d"), list);
151     }
152 
153     public void testCreation_fiveElements() {
154       List<String> list = ImmutableList.of("a", "b", "c", "d", "e");
155       assertEquals(Lists.newArrayList("a", "b", "c", "d", "e"), list);
156     }
157 
158     public void testCreation_sixElements() {
159       List<String> list = ImmutableList.of("a", "b", "c", "d", "e", "f");
160       assertEquals(Lists.newArrayList("a", "b", "c", "d", "e", "f"), list);
161     }
162 
163     public void testCreation_sevenElements() {
164       List<String> list = ImmutableList.of("a", "b", "c", "d", "e", "f", "g");
165       assertEquals(Lists.newArrayList("a", "b", "c", "d", "e", "f", "g"), list);
166     }
167 
168     public void testCreation_eightElements() {
169       List<String> list = ImmutableList.of(
170           "a", "b", "c", "d", "e", "f", "g", "h");
171       assertEquals(Lists.newArrayList(
172           "a", "b", "c", "d", "e", "f", "g", "h"), list);
173     }
174 
175     public void testCreation_nineElements() {
176       List<String> list = ImmutableList.of(
177           "a", "b", "c", "d", "e", "f", "g", "h", "i");
178       assertEquals(Lists.newArrayList(
179           "a", "b", "c", "d", "e", "f", "g", "h", "i"), list);
180     }
181 
182     public void testCreation_tenElements() {
183       List<String> list = ImmutableList.of(
184           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
185       assertEquals(Lists.newArrayList(
186           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), list);
187     }
188 
189     public void testCreation_elevenElements() {
190       List<String> list = ImmutableList.of(
191           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k");
192       assertEquals(Lists.newArrayList(
193           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"), list);
194     }
195 
196     // Varargs versions
197 
198     public void testCreation_twelveElements() {
199       List<String> list = ImmutableList.of(
200           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l");
201       assertEquals(Lists.newArrayList(
202           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"), list);
203     }
204 
205     public void testCreation_thirteenElements() {
206       List<String> list = ImmutableList.of(
207           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m");
208       assertEquals(Lists.newArrayList(
209           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"),
210           list);
211     }
212 
213     public void testCreation_fourteenElements() {
214       List<String> list = ImmutableList.of(
215           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n");
216       assertEquals(Lists.newArrayList(
217           "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"),
218           list);
219     }
220 
221     public void testCreation_singletonNull() {
222       try {
223         ImmutableList.of((String) null);
224         fail();
225       } catch (NullPointerException expected) {
226       }
227     }
228 
229     public void testCreation_withNull() {
230       try {
231         ImmutableList.of("a", null, "b");
232         fail();
233       } catch (NullPointerException expected) {
234       }
235     }
236 
237     public void testCreation_generic() {
238       List<String> a = ImmutableList.of("a");
239       // only verify that there is no compile warning
240       ImmutableList.of(a, a);
241     }
242 
243     public void testCreation_arrayOfArray() {
244       String[] array = new String[] { "a" };
245       List<String[]> list = ImmutableList.<String[]>of(array);
246       assertEquals(Collections.singletonList(array), list);
247     }
248 
249     public void testCopyOf_emptyArray() {
250       String[] array = new String[0];
251       List<String> list = ImmutableList.copyOf(array);
252       assertEquals(Collections.emptyList(), list);
253     }
254 
255     public void testCopyOf_arrayOfOneElement() {
256       String[] array = new String[] { "a" };
257       List<String> list = ImmutableList.copyOf(array);
258       assertEquals(Collections.singletonList("a"), list);
259     }
260 
261     public void testCopyOf_nullArray() {
262       try {
263         ImmutableList.copyOf((String[]) null);
264         fail();
265       } catch (NullPointerException expected) {
266       }
267     }
268 
269     public void testCopyOf_arrayContainingOnlyNull() {
270       String[] array = new String[] { null };
271       try {
272         ImmutableList.copyOf(array);
273         fail();
274       } catch (NullPointerException expected) {
275       }
276     }
277 
278     public void testCopyOf_collection_empty() {
279       // "<String>" is required to work around a javac 1.5 bug.
280       Collection<String> c = MinimalCollection.<String>of();
281       List<String> list = ImmutableList.copyOf(c);
282       assertEquals(Collections.emptyList(), list);
283     }
284 
285     public void testCopyOf_collection_oneElement() {
286       Collection<String> c = MinimalCollection.of("a");
287       List<String> list = ImmutableList.copyOf(c);
288       assertEquals(Collections.singletonList("a"), list);
289     }
290 
291     public void testCopyOf_collection_general() {
292       Collection<String> c = MinimalCollection.of("a", "b", "a");
293       List<String> list = ImmutableList.copyOf(c);
294       assertEquals(asList("a", "b", "a"), list);
295       List<String> mutableList = asList("a", "b");
296       list = ImmutableList.copyOf(mutableList);
297       mutableList.set(0, "c");
298       assertEquals(asList("a", "b"), list);
299     }
300 
301     public void testCopyOf_collectionContainingNull() {
302       Collection<String> c = MinimalCollection.of("a", null, "b");
303       try {
304         ImmutableList.copyOf(c);
305         fail();
306       } catch (NullPointerException expected) {
307       }
308     }
309 
310     public void testCopyOf_iterator_empty() {
311       Iterator<String> iterator = Iterators.emptyIterator();
312       List<String> list = ImmutableList.copyOf(iterator);
313       assertEquals(Collections.emptyList(), list);
314     }
315 
316     public void testCopyOf_iterator_oneElement() {
317       Iterator<String> iterator = Iterators.singletonIterator("a");
318       List<String> list = ImmutableList.copyOf(iterator);
319       assertEquals(Collections.singletonList("a"), list);
320     }
321 
322     public void testCopyOf_iterator_general() {
323       Iterator<String> iterator = asList("a", "b", "a").iterator();
324       List<String> list = ImmutableList.copyOf(iterator);
325       assertEquals(asList("a", "b", "a"), list);
326     }
327 
328     public void testCopyOf_iteratorContainingNull() {
329       Iterator<String> iterator = asList("a", null, "b").iterator();
330       try {
331         ImmutableList.copyOf(iterator);
332         fail();
333       } catch (NullPointerException expected) {
334       }
335     }
336 
337     public void testCopyOf_iteratorNull() {
338       try {
339         ImmutableList.copyOf((Iterator<String>) null);
340         fail();
341       } catch (NullPointerException expected) {
342       }
343     }
344 
345     public void testCopyOf_concurrentlyMutating() {
346       List<String> sample = Lists.newArrayList("a", "b", "c");
347       for (int delta : new int[] {-1, 0, 1}) {
348         for (int i = 0; i < sample.size(); i++) {
349           Collection<String> misleading =
350               Helpers.misleadingSizeCollection(delta);
351           List<String> expected = sample.subList(0, i);
352           misleading.addAll(expected);
353           assertEquals(expected, ImmutableList.copyOf(misleading));
354           assertEquals(expected,
355               ImmutableList.copyOf((Iterable<String>) misleading));
356         }
357       }
358     }
359 
360     private static class CountingIterable implements Iterable<String> {
361       int count = 0;
362       @Override
363       public Iterator<String> iterator() {
364         count++;
365         return asList("a", "b", "a").iterator();
366       }
367     }
368 
369     public void testCopyOf_plainIterable() {
370       CountingIterable iterable = new CountingIterable();
371       List<String> list = ImmutableList.copyOf(iterable);
372       assertEquals(asList("a", "b", "a"), list);
373     }
374 
375     public void testCopyOf_plainIterable_iteratesOnce() {
376       CountingIterable iterable = new CountingIterable();
377       ImmutableList.copyOf(iterable);
378       assertEquals(1, iterable.count);
379     }
380 
381     public void testCopyOf_shortcut_empty() {
382       Collection<String> c = ImmutableList.of();
383       assertSame(c, ImmutableList.copyOf(c));
384     }
385 
386     public void testCopyOf_shortcut_singleton() {
387       Collection<String> c = ImmutableList.of("a");
388       assertSame(c, ImmutableList.copyOf(c));
389     }
390 
391     public void testCopyOf_shortcut_immutableList() {
392       Collection<String> c = ImmutableList.of("a", "b", "c");
393       assertSame(c, ImmutableList.copyOf(c));
394     }
395 
396     public void testBuilderAddArrayHandlesNulls() {
397       String[] elements = {"a", null, "b"};
398       ImmutableList.Builder<String> builder = ImmutableList.builder();
399       try {
400         builder.add(elements);
401         fail ("Expected NullPointerException");
402       } catch (NullPointerException expected) {
403       }
404       ImmutableList<String> result = builder.build();
405 
406       /*
407        * Maybe it rejects all elements, or maybe it adds "a" before failing.
408        * Either way is fine with us.
409        */
410       if (result.isEmpty()) {
411         return;
412       }
413       assertTrue(ImmutableList.of("a").equals(result));
414       assertEquals(1, result.size());
415     }
416 
417     public void testBuilderAddCollectionHandlesNulls() {
418       List<String> elements = Arrays.asList("a", null, "b");
419       ImmutableList.Builder<String> builder = ImmutableList.builder();
420       try {
421         builder.addAll(elements);
422         fail ("Expected NullPointerException");
423       } catch (NullPointerException expected) {
424       }
425       ImmutableList<String> result = builder.build();
426       assertEquals(ImmutableList.of("a"), result);
427       assertEquals(1, result.size());
428     }
429   }
430 
431   @GwtIncompatible("reflection")
432   public static class ConcurrentTests extends TestCase {
433     enum WrapWithIterable { WRAP, NO_WRAP }
434 
435     private static void runConcurrentlyMutatedTest(
436         Collection<Integer> initialContents,
437         Iterable<ListFrobber> actionsToPerformConcurrently,
438         WrapWithIterable wrap) {
439       ConcurrentlyMutatedList<Integer> concurrentlyMutatedList =
440           newConcurrentlyMutatedList(
441               initialContents, actionsToPerformConcurrently);
442 
443       Iterable<Integer> iterableToCopy = wrap == WrapWithIterable.WRAP
444           ? unmodifiableIterable(concurrentlyMutatedList)
445           : concurrentlyMutatedList;
446 
447       ImmutableList<Integer> copyOfIterable =
448           ImmutableList.copyOf(iterableToCopy);
449 
450       assertTrue(concurrentlyMutatedList.getAllStates()
451           .contains(copyOfIterable));
452 
453       // Check that we didn't end up with a RegularImmutableList of size 1.
454       assertEquals(copyOfIterable.size() == 1,
455           copyOfIterable instanceof SingletonImmutableList);
456     }
457 
458     private static void runConcurrentlyMutatedTest(WrapWithIterable wrap) {
459       /*
460        * TODO: Iterate over many array sizes and all possible operation lists,
461        * performing adds and removes in different ways.
462        */
463       runConcurrentlyMutatedTest(
464           elements(),
465           ops(add(1), add(2)),
466           wrap);
467 
468       runConcurrentlyMutatedTest(
469           elements(),
470           ops(add(1), nop()),
471           wrap);
472 
473       runConcurrentlyMutatedTest(
474           elements(),
475           ops(add(1), remove()),
476           wrap);
477 
478       runConcurrentlyMutatedTest(
479           elements(),
480           ops(nop(), add(1)),
481           wrap);
482 
483       runConcurrentlyMutatedTest(
484           elements(1),
485           ops(remove(), nop()),
486           wrap);
487 
488       runConcurrentlyMutatedTest(
489           elements(1),
490           ops(remove(), add(2)),
491           wrap);
492 
493       runConcurrentlyMutatedTest(
494           elements(1, 2),
495           ops(remove(), remove()),
496           wrap);
497 
498       runConcurrentlyMutatedTest(
499           elements(1, 2),
500           ops(remove(), nop()),
501           wrap);
502 
503       runConcurrentlyMutatedTest(
504           elements(1, 2),
505           ops(remove(), add(3)),
506           wrap);
507 
508       runConcurrentlyMutatedTest(
509           elements(1, 2),
510           ops(nop(), remove()),
511           wrap);
512 
513       runConcurrentlyMutatedTest(
514           elements(1, 2, 3),
515           ops(remove(), remove()),
516           wrap);
517     }
518 
519     private static ImmutableList<Integer> elements(Integer... elements) {
520       return ImmutableList.copyOf(elements);
521     }
522 
523     private static ImmutableList<ListFrobber> ops(ListFrobber... elements) {
524       return ImmutableList.copyOf(elements);
525     }
526 
527     public void testCopyOf_concurrentlyMutatedList() {
528       runConcurrentlyMutatedTest(WrapWithIterable.NO_WRAP);
529     }
530 
531     public void testCopyOf_concurrentlyMutatedIterable() {
532       runConcurrentlyMutatedTest(WrapWithIterable.WRAP);
533     }
534 
535     /** An operation to perform on a list. */
536     interface ListFrobber {
537       void perform(List<Integer> list);
538     }
539 
540     static ListFrobber add(final int element) {
541       return new ListFrobber() {
542         @Override
543         public void perform(List<Integer> list) {
544           list.add(0, element);
545         }
546       };
547     }
548 
549     static ListFrobber remove() {
550       return new ListFrobber() {
551         @Override
552         public void perform(List<Integer> list) {
553           list.remove(0);
554         }
555       };
556     }
557 
558     static ListFrobber nop() {
559       return new ListFrobber() {
560         @Override
561         public void perform(List<Integer> list) {
562         }
563       };
564     }
565 
566     /**
567      * A list that mutates itself after every call to each of its {@link List}
568      * methods.
569      */
570     interface ConcurrentlyMutatedList<E> extends List<E> {
571       /**
572        * The elements of a {@link ConcurrentlyMutatedList} are added and removed
573        * over time. This method returns every state that the list has passed
574        * through at some point.
575        */
576       Set<List<E>> getAllStates();
577     }
578 
579     /**
580      * Returns a {@link ConcurrentlyMutatedList} that performs the given
581      * operations as its concurrent modifications. The mutations occur in the
582      * same thread as the triggering method call.
583      */
584     private static ConcurrentlyMutatedList<Integer> newConcurrentlyMutatedList(
585         final Collection<Integer> initialContents,
586         final Iterable<ListFrobber> actionsToPerformConcurrently) {
587       InvocationHandler invocationHandler = new InvocationHandler() {
588         final CopyOnWriteArrayList<Integer> delegate =
589             new CopyOnWriteArrayList<Integer>(initialContents);
590 
591         final Method getAllStatesMethod = getOnlyElement(asList(
592             ConcurrentlyMutatedList.class.getDeclaredMethods()));
593 
594         final Iterator<ListFrobber> remainingActions =
595             actionsToPerformConcurrently.iterator();
596 
597         final Set<List<Integer>> allStates = newHashSet();
598 
599         @Override
600         public Object invoke(Object proxy, Method method,
601             Object[] args) throws Throwable {
602           return method.equals(getAllStatesMethod)
603               ? getAllStates()
604               : invokeListMethod(method, args);
605         }
606 
607         private Set<List<Integer>> getAllStates() {
608           return allStates;
609         }
610 
611         private Object invokeListMethod(Method method, Object[] args)
612             throws Throwable {
613           try {
614             Object returnValue = method.invoke(delegate, args);
615             mutateDelegate();
616             return returnValue;
617           } catch (InvocationTargetException e) {
618             throw e.getCause();
619           } catch (IllegalAccessException e) {
620             throw new AssertionError(e);
621           }
622         }
623 
624         private void mutateDelegate() {
625           allStates.add(ImmutableList.copyOf(delegate));
626           remainingActions.next().perform(delegate);
627           allStates.add(ImmutableList.copyOf(delegate));
628         }
629       };
630 
631       @SuppressWarnings("unchecked")
632       ConcurrentlyMutatedList<Integer> list =
633           (ConcurrentlyMutatedList<Integer>) newProxyInstance(
634               ImmutableListTest.CreationTests.class.getClassLoader(),
635               new Class[] {ConcurrentlyMutatedList.class}, invocationHandler);
636       return list;
637     }
638   }
639 
640   public static class BasicTests extends TestCase {
641 
642     @GwtIncompatible("NullPointerTester")
643     public void testNullPointers() {
644       NullPointerTester tester = new NullPointerTester();
645       tester.testAllPublicStaticMethods(ImmutableList.class);
646       tester.testAllPublicInstanceMethods(ImmutableList.of(1, 2, 3));
647     }
648 
649     @GwtIncompatible("SerializableTester")
650     public void testSerialization_empty() {
651       Collection<String> c = ImmutableList.of();
652       assertSame(c, SerializableTester.reserialize(c));
653     }
654 
655     @GwtIncompatible("SerializableTester")
656     public void testSerialization_singleton() {
657       Collection<String> c = ImmutableList.of("a");
658       SerializableTester.reserializeAndAssert(c);
659     }
660 
661     @GwtIncompatible("SerializableTester")
662     public void testSerialization_multiple() {
663       Collection<String> c = ImmutableList.of("a", "b", "c");
664       SerializableTester.reserializeAndAssert(c);
665     }
666 
667     public void testEquals_immutableList() {
668       Collection<String> c = ImmutableList.of("a", "b", "c");
669       assertTrue(c.equals(ImmutableList.of("a", "b", "c")));
670       assertFalse(c.equals(ImmutableList.of("a", "c", "b")));
671       assertFalse(c.equals(ImmutableList.of("a", "b")));
672       assertFalse(c.equals(ImmutableList.of("a", "b", "c", "d")));
673     }
674 
675     public void testBuilderAdd() {
676       ImmutableList<String> list = new ImmutableList.Builder<String>()
677           .add("a")
678           .add("b")
679           .add("a")
680           .add("c")
681           .build();
682       assertEquals(asList("a", "b", "a", "c"), list);
683     }
684 
685     public void testBuilderAdd_varargs() {
686       ImmutableList<String> list = new ImmutableList.Builder<String>()
687           .add("a", "b", "a", "c")
688           .build();
689       assertEquals(asList("a", "b", "a", "c"), list);
690     }
691 
692     public void testBuilderAddAll_iterable() {
693       List<String> a = asList("a", "b");
694       List<String> b = asList("c", "d");
695       ImmutableList<String> list = new ImmutableList.Builder<String>()
696           .addAll(a)
697           .addAll(b)
698           .build();
699       assertEquals(asList( "a", "b", "c", "d"), list);
700       b.set(0, "f");
701       assertEquals(asList( "a", "b", "c", "d"), list);
702     }
703 
704     public void testBuilderAddAll_iterator() {
705       List<String> a = asList("a", "b");
706       List<String> b = asList("c", "d");
707       ImmutableList<String> list = new ImmutableList.Builder<String>()
708           .addAll(a.iterator())
709           .addAll(b.iterator())
710           .build();
711       assertEquals(asList( "a", "b", "c", "d"), list);
712       b.set(0, "f");
713       assertEquals(asList( "a", "b", "c", "d"), list);
714     }
715 
716     public void testComplexBuilder() {
717       List<Integer> colorElem = asList(0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF);
718       ImmutableList.Builder<Integer> webSafeColorsBuilder
719           = ImmutableList.builder();
720       for (Integer red : colorElem) {
721         for (Integer green : colorElem) {
722           for (Integer blue : colorElem) {
723             webSafeColorsBuilder.add((red << 16) + (green << 8) + blue);
724           }
725         }
726       }
727       ImmutableList<Integer> webSafeColors = webSafeColorsBuilder.build();
728       assertEquals(216, webSafeColors.size());
729       Integer[] webSafeColorArray =
730           webSafeColors.toArray(new Integer[webSafeColors.size()]);
731       assertEquals(0x000000, (int) webSafeColorArray[0]);
732       assertEquals(0x000033, (int) webSafeColorArray[1]);
733       assertEquals(0x000066, (int) webSafeColorArray[2]);
734       assertEquals(0x003300, (int) webSafeColorArray[6]);
735       assertEquals(0x330000, (int) webSafeColorArray[36]);
736       assertEquals(0x000066, (int) webSafeColors.get(2));
737       assertEquals(0x003300, (int) webSafeColors.get(6));
738       ImmutableList<Integer> addedColor
739           = webSafeColorsBuilder.add(0x00BFFF).build();
740       assertEquals("Modifying the builder should not have changed any already"
741           + " built sets", 216, webSafeColors.size());
742       assertEquals("the new array should be one bigger than webSafeColors",
743           217, addedColor.size());
744       Integer[] appendColorArray =
745           addedColor.toArray(new Integer[addedColor.size()]);
746       assertEquals(0x00BFFF, (int) appendColorArray[216]);
747     }
748 
749     public void testBuilderAddHandlesNullsCorrectly() {
750       ImmutableList.Builder<String> builder = ImmutableList.builder();
751       try {
752         builder.add((String) null);
753         fail("expected NullPointerException");
754       } catch (NullPointerException expected) {
755       }
756 
757       try {
758         builder.add((String[]) null);
759         fail("expected NullPointerException");
760       } catch (NullPointerException expected) {
761       }
762 
763       try {
764         builder.add("a", null, "b");
765         fail("expected NullPointerException");
766       } catch (NullPointerException expected) {
767       }
768     }
769 
770     public void testBuilderAddAllHandlesNullsCorrectly() {
771       ImmutableList.Builder<String> builder = ImmutableList.builder();
772       try {
773         builder.addAll((Iterable<String>) null);
774         fail("expected NullPointerException");
775       } catch (NullPointerException expected) {
776       }
777 
778       try {
779         builder.addAll((Iterator<String>) null);
780         fail("expected NullPointerException");
781       } catch (NullPointerException expected) {
782       }
783 
784       builder = ImmutableList.builder();
785       List<String> listWithNulls = asList("a", null, "b");
786       try {
787         builder.addAll(listWithNulls);
788         fail("expected NullPointerException");
789       } catch (NullPointerException expected) {
790       }
791 
792       builder = ImmutableList.builder();
793       Iterator<String> iteratorWithNulls = asList("a", null, "b").iterator();
794       try {
795         builder.addAll(iteratorWithNulls);
796         fail("expected NullPointerException");
797       } catch (NullPointerException expected) {
798       }
799 
800       Iterable<String> iterableWithNulls = MinimalIterable.of("a", null, "b");
801       try {
802         builder.addAll(iterableWithNulls);
803         fail("expected NullPointerException");
804       } catch (NullPointerException expected) {
805       }
806     }
807 
808     public void testAsList() {
809       ImmutableList<String> list = ImmutableList.of("a", "b");
810       assertSame(list, list.asList());
811     }
812   }
813 }
814