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
17package com.google.common.collect;
18
19import static com.google.common.collect.Iterables.getOnlyElement;
20import static com.google.common.collect.Iterables.unmodifiableIterable;
21import static com.google.common.collect.Sets.newHashSet;
22import static java.lang.reflect.Proxy.newProxyInstance;
23import static java.util.Arrays.asList;
24
25import com.google.common.annotations.GwtCompatible;
26import com.google.common.annotations.GwtIncompatible;
27import com.google.common.collect.testing.Helpers;
28import com.google.common.collect.testing.ListTestSuiteBuilder;
29import com.google.common.collect.testing.MinimalCollection;
30import com.google.common.collect.testing.MinimalIterable;
31import com.google.common.collect.testing.features.CollectionFeature;
32import com.google.common.collect.testing.features.CollectionSize;
33import com.google.common.collect.testing.google.ListGenerators.BuilderAddAllListGenerator;
34import com.google.common.collect.testing.google.ListGenerators.BuilderReversedListGenerator;
35import com.google.common.collect.testing.google.ListGenerators.ImmutableListHeadSubListGenerator;
36import com.google.common.collect.testing.google.ListGenerators.ImmutableListMiddleSubListGenerator;
37import com.google.common.collect.testing.google.ListGenerators.ImmutableListOfGenerator;
38import com.google.common.collect.testing.google.ListGenerators.ImmutableListTailSubListGenerator;
39import com.google.common.collect.testing.google.ListGenerators.UnhashableElementsImmutableListGenerator;
40import com.google.common.collect.testing.testers.ListHashCodeTester;
41import com.google.common.testing.NullPointerTester;
42import com.google.common.testing.SerializableTester;
43
44import junit.framework.Test;
45import junit.framework.TestCase;
46import junit.framework.TestSuite;
47
48import java.lang.reflect.InvocationHandler;
49import java.lang.reflect.InvocationTargetException;
50import java.lang.reflect.Method;
51import java.util.Arrays;
52import java.util.Collection;
53import java.util.Collections;
54import java.util.Iterator;
55import java.util.List;
56import java.util.Set;
57import 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)
67public 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