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