• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.primitives;
16 
17 import static com.google.common.primitives.TestPlatform.reduceIterationsIfGwt;
18 import static com.google.common.testing.SerializableTester.reserialize;
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.annotations.J2ktIncompatible;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ObjectArrays;
26 import com.google.common.collect.testing.ListTestSuiteBuilder;
27 import com.google.common.collect.testing.SampleElements;
28 import com.google.common.collect.testing.TestListGenerator;
29 import com.google.common.collect.testing.features.CollectionFeature;
30 import com.google.common.collect.testing.features.CollectionSize;
31 import com.google.common.testing.EqualsTester;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Random;
39 import java.util.concurrent.atomic.AtomicInteger;
40 import junit.framework.Test;
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43 
44 /** @author Kevin Bourrillion */
45 @GwtCompatible(emulated = true)
46 public class ImmutableIntArrayTest extends TestCase {
47   // Test all creation paths very lazily: by assuming asList() works
48 
testOf0()49   public void testOf0() {
50     assertThat(ImmutableIntArray.of().asList()).isEmpty();
51   }
52 
testOf1()53   public void testOf1() {
54     assertThat(ImmutableIntArray.of(0).asList()).containsExactly(0);
55   }
56 
testOf2()57   public void testOf2() {
58     assertThat(ImmutableIntArray.of(0, 1).asList()).containsExactly(0, 1).inOrder();
59   }
60 
testOf3()61   public void testOf3() {
62     assertThat(ImmutableIntArray.of(0, 1, 3).asList()).containsExactly(0, 1, 3).inOrder();
63   }
64 
testOf4()65   public void testOf4() {
66     assertThat(ImmutableIntArray.of(0, 1, 3, 6).asList()).containsExactly(0, 1, 3, 6).inOrder();
67   }
68 
testOf5()69   public void testOf5() {
70     assertThat(ImmutableIntArray.of(0, 1, 3, 6, 10).asList())
71         .containsExactly(0, 1, 3, 6, 10)
72         .inOrder();
73   }
74 
testOf6()75   public void testOf6() {
76     assertThat(ImmutableIntArray.of(0, 1, 3, 6, 10, 15).asList())
77         .containsExactly(0, 1, 3, 6, 10, 15)
78         .inOrder();
79   }
80 
testOf7()81   public void testOf7() {
82     assertThat(ImmutableIntArray.of(0, 1, 3, 6, 10, 15, 21).asList())
83         .containsExactly(0, 1, 3, 6, 10, 15, 21)
84         .inOrder();
85   }
86 
testCopyOf_array_empty()87   public void testCopyOf_array_empty() {
88     /*
89      * We don't guarantee the same-as property, so we aren't obligated to test it. However, it's
90      * useful in testing - when two things are the same then one can't have bugs the other doesn't.
91      */
92     assertThat(ImmutableIntArray.copyOf(new int[0])).isSameInstanceAs(ImmutableIntArray.of());
93   }
94 
testCopyOf_array_nonempty()95   public void testCopyOf_array_nonempty() {
96     int[] array = new int[] {0, 1, 3};
97     ImmutableIntArray iia = ImmutableIntArray.copyOf(array);
98     array[2] = 2;
99     assertThat(iia.asList()).containsExactly(0, 1, 3).inOrder();
100   }
101 
testCopyOf_iterable_notCollection_empty()102   public void testCopyOf_iterable_notCollection_empty() {
103     Iterable<Integer> iterable = iterable(Collections.<Integer>emptySet());
104     assertThat(ImmutableIntArray.copyOf(iterable)).isSameInstanceAs(ImmutableIntArray.of());
105   }
106 
testCopyOf_iterable_notCollection_nonempty()107   public void testCopyOf_iterable_notCollection_nonempty() {
108     List<Integer> list = Arrays.asList(0, 1, 3);
109     ImmutableIntArray iia = ImmutableIntArray.copyOf(iterable(list));
110     list.set(2, 2);
111     assertThat(iia.asList()).containsExactly(0, 1, 3).inOrder();
112   }
113 
testCopyOf_iterable_collection_empty()114   public void testCopyOf_iterable_collection_empty() {
115     Iterable<Integer> iterable = Collections.emptySet();
116     assertThat(ImmutableIntArray.copyOf(iterable)).isSameInstanceAs(ImmutableIntArray.of());
117   }
118 
testCopyOf_iterable_collection_nonempty()119   public void testCopyOf_iterable_collection_nonempty() {
120     List<Integer> list = Arrays.asList(0, 1, 3);
121     ImmutableIntArray iia = ImmutableIntArray.copyOf((Iterable<Integer>) list);
122     list.set(2, 2);
123     assertThat(iia.asList()).containsExactly(0, 1, 3).inOrder();
124   }
125 
testCopyOf_collection_empty()126   public void testCopyOf_collection_empty() {
127     Collection<Integer> iterable = Collections.emptySet();
128     assertThat(ImmutableIntArray.copyOf(iterable)).isSameInstanceAs(ImmutableIntArray.of());
129   }
130 
testCopyOf_collection_nonempty()131   public void testCopyOf_collection_nonempty() {
132     List<Integer> list = Arrays.asList(0, 1, 3);
133     ImmutableIntArray iia = ImmutableIntArray.copyOf(list);
134     list.set(2, 2);
135     assertThat(iia.asList()).containsExactly(0, 1, 3).inOrder();
136   }
137 
testBuilder_presize_zero()138   public void testBuilder_presize_zero() {
139     ImmutableIntArray.Builder builder = ImmutableIntArray.builder(0);
140     builder.add(5);
141     ImmutableIntArray array = builder.build();
142     assertThat(array.asList()).containsExactly(5);
143   }
144 
testBuilder_presize_negative()145   public void testBuilder_presize_negative() {
146     try {
147       ImmutableIntArray.builder(-1);
148       fail();
149     } catch (IllegalArgumentException expected) {
150     }
151   }
152 
153   /**
154    * If there's a bug in builder growth, we wouldn't know how to expose it. So, brute force the hell
155    * out of it for a while and see what happens.
156    */
testBuilder_bruteForce()157   public void testBuilder_bruteForce() {
158     for (int i = 0; i < reduceIterationsIfGwt(100); i++) {
159       ImmutableIntArray.Builder builder = ImmutableIntArray.builder(RANDOM.nextInt(20));
160       AtomicInteger counter = new AtomicInteger(0);
161       while (counter.get() < 1000) {
162         BuilderOp op = BuilderOp.randomOp();
163         op.doIt(builder, counter);
164       }
165       ImmutableIntArray iia = builder.build();
166       for (int j = 0; j < iia.length(); j++) {
167         assertThat(iia.get(j)).isEqualTo(j);
168       }
169     }
170   }
171 
172   private enum BuilderOp {
173     ADD_ONE {
174       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)175       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
176         builder.add(counter.getAndIncrement());
177       }
178     },
179     ADD_ARRAY {
180       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)181       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
182         int[] array = new int[RANDOM.nextInt(10)];
183         for (int i = 0; i < array.length; i++) {
184           array[i] = counter.getAndIncrement();
185         }
186         builder.addAll(array);
187       }
188     },
189     ADD_COLLECTION {
190       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)191       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
192         List<Integer> list = new ArrayList<>();
193         int num = RANDOM.nextInt(10);
194         for (int i = 0; i < num; i++) {
195           list.add(counter.getAndIncrement());
196         }
197         builder.addAll(list);
198       }
199     },
200     ADD_ITERABLE {
201       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)202       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
203         List<Integer> list = new ArrayList<>();
204         int num = RANDOM.nextInt(10);
205         for (int i = 0; i < num; i++) {
206           list.add(counter.getAndIncrement());
207         }
208         builder.addAll(iterable(list));
209       }
210     },
211     ADD_IIA {
212       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)213       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
214         int[] array = new int[RANDOM.nextInt(10)];
215         for (int i = 0; i < array.length; i++) {
216           array[i] = counter.getAndIncrement();
217         }
218         builder.addAll(ImmutableIntArray.copyOf(array));
219       }
220     },
221     ADD_LARGER_ARRAY {
222       @Override
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)223       void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter) {
224         int[] array = new int[RANDOM.nextInt(200) + 200];
225         for (int i = 0; i < array.length; i++) {
226           array[i] = counter.getAndIncrement();
227         }
228         builder.addAll(array);
229       }
230     },
231     ;
232 
233     static final BuilderOp[] values = values();
234 
randomOp()235     static BuilderOp randomOp() {
236       return values[RANDOM.nextInt(values.length)];
237     }
238 
doIt(ImmutableIntArray.Builder builder, AtomicInteger counter)239     abstract void doIt(ImmutableIntArray.Builder builder, AtomicInteger counter);
240   }
241 
242   private static final Random RANDOM = new Random(42);
243 
testLength()244   public void testLength() {
245     assertThat(ImmutableIntArray.of().length()).isEqualTo(0);
246     assertThat(ImmutableIntArray.of(0).length()).isEqualTo(1);
247     assertThat(ImmutableIntArray.of(0, 1, 3).length()).isEqualTo(3);
248     assertThat(ImmutableIntArray.of(0, 1, 3).subArray(1, 1).length()).isEqualTo(0);
249     assertThat(ImmutableIntArray.of(0, 1, 3).subArray(1, 2).length()).isEqualTo(1);
250   }
251 
testIsEmpty()252   public void testIsEmpty() {
253     assertThat(ImmutableIntArray.of().isEmpty()).isTrue();
254     assertThat(ImmutableIntArray.of(0).isEmpty()).isFalse();
255     assertThat(ImmutableIntArray.of(0, 1, 3).isEmpty()).isFalse();
256     assertThat(ImmutableIntArray.of(0, 1, 3).subArray(1, 1).isEmpty()).isTrue();
257     assertThat(ImmutableIntArray.of(0, 1, 3).subArray(1, 2).isEmpty()).isFalse();
258   }
259 
testGet_good()260   public void testGet_good() {
261     ImmutableIntArray iia = ImmutableIntArray.of(0, 1, 3);
262     assertThat(iia.get(0)).isEqualTo(0);
263     assertThat(iia.get(2)).isEqualTo(3);
264     assertThat(iia.subArray(1, 3).get(1)).isEqualTo(3);
265   }
266 
testGet_bad()267   public void testGet_bad() {
268     ImmutableIntArray iia = ImmutableIntArray.of(0, 1, 3);
269     try {
270       iia.get(-1);
271       fail();
272     } catch (IndexOutOfBoundsException expected) {
273     }
274     try {
275       iia.get(3);
276       fail();
277     } catch (IndexOutOfBoundsException expected) {
278     }
279 
280     iia = iia.subArray(1, 2);
281     try {
282       iia.get(-1);
283       fail();
284     } catch (IndexOutOfBoundsException expected) {
285     }
286   }
287 
testIndexOf()288   public void testIndexOf() {
289     ImmutableIntArray iia = ImmutableIntArray.of(1, 1, 2, 3, 5, 8);
290     assertThat(iia.indexOf(1)).isEqualTo(0);
291     assertThat(iia.indexOf(8)).isEqualTo(5);
292     assertThat(iia.indexOf(4)).isEqualTo(-1);
293     assertThat(ImmutableIntArray.of(13).indexOf(13)).isEqualTo(0);
294     assertThat(ImmutableIntArray.of().indexOf(21)).isEqualTo(-1);
295     assertThat(iia.subArray(1, 5).indexOf(1)).isEqualTo(0);
296   }
297 
testLastIndexOf()298   public void testLastIndexOf() {
299     ImmutableIntArray iia = ImmutableIntArray.of(1, 1, 2, 3, 5, 8);
300     assertThat(iia.lastIndexOf(1)).isEqualTo(1);
301     assertThat(iia.lastIndexOf(8)).isEqualTo(5);
302     assertThat(iia.lastIndexOf(4)).isEqualTo(-1);
303     assertThat(ImmutableIntArray.of(13).lastIndexOf(13)).isEqualTo(0);
304     assertThat(ImmutableIntArray.of().lastIndexOf(21)).isEqualTo(-1);
305     assertThat(iia.subArray(1, 5).lastIndexOf(1)).isEqualTo(0);
306   }
307 
testContains()308   public void testContains() {
309     ImmutableIntArray iia = ImmutableIntArray.of(1, 1, 2, 3, 5, 8);
310     assertThat(iia.contains(1)).isTrue();
311     assertThat(iia.contains(8)).isTrue();
312     assertThat(iia.contains(4)).isFalse();
313     assertThat(ImmutableIntArray.of(13).contains(13)).isTrue();
314     assertThat(ImmutableIntArray.of().contains(21)).isFalse();
315     assertThat(iia.subArray(1, 5).contains(1)).isTrue();
316   }
317 
testSubArray()318   public void testSubArray() {
319     ImmutableIntArray iia0 = ImmutableIntArray.of();
320     ImmutableIntArray iia1 = ImmutableIntArray.of(5);
321     ImmutableIntArray iia3 = ImmutableIntArray.of(5, 25, 125);
322 
323     assertThat(iia0.subArray(0, 0)).isSameInstanceAs(ImmutableIntArray.of());
324     assertThat(iia1.subArray(0, 0)).isSameInstanceAs(ImmutableIntArray.of());
325     assertThat(iia1.subArray(1, 1)).isSameInstanceAs(ImmutableIntArray.of());
326     assertThat(iia1.subArray(0, 1).asList()).containsExactly(5);
327     assertThat(iia3.subArray(0, 2).asList()).containsExactly(5, 25).inOrder();
328     assertThat(iia3.subArray(1, 3).asList()).containsExactly(25, 125).inOrder();
329 
330     try {
331       iia3.subArray(-1, 1);
332       fail();
333     } catch (IndexOutOfBoundsException expected) {
334     }
335     try {
336       iia3.subArray(1, 4);
337       fail();
338     } catch (IndexOutOfBoundsException expected) {
339     }
340   }
341 
342   /*
343    * Whenever an implementation uses `instanceof` on a parameter instance, the test has to know that
344    * (so much for "black box") and try instances that both do and don't pass the check. The "don't"
345    * half of that is more awkward to arrange...
346    */
iterable(final Collection<T> collection)347   private static <T> Iterable<T> iterable(final Collection<T> collection) {
348     // return collection::iterator;
349     return new Iterable<T>() {
350       @Override
351       public Iterator<T> iterator() {
352         return collection.iterator();
353       }
354     };
355   }
356 
357   public void testEquals() {
358     new EqualsTester()
359         .addEqualityGroup(ImmutableIntArray.of())
360         .addEqualityGroup(
361             ImmutableIntArray.of(1, 2),
362             reserialize(ImmutableIntArray.of(1, 2)),
363             ImmutableIntArray.of(0, 1, 2, 3).subArray(1, 3))
364         .addEqualityGroup(ImmutableIntArray.of(1, 3))
365         .addEqualityGroup(ImmutableIntArray.of(1, 2, 3))
366         .testEquals();
367   }
368 
369   /**
370    * This is probably a weird and hacky way to test what we're really trying to test, but hey, it
371    * caught a bug.
372    */
373   public void testTrimmed() {
374     ImmutableIntArray iia = ImmutableIntArray.of(0, 1, 3);
375     assertDoesntActuallyTrim(iia);
376     assertDoesntActuallyTrim(iia.subArray(0, 3));
377     assertActuallyTrims(iia.subArray(0, 2));
378     assertActuallyTrims(iia.subArray(1, 3));
379 
380     ImmutableIntArray rightSized = ImmutableIntArray.builder(3).add(0).add(1).add(3).build();
381     assertDoesntActuallyTrim(rightSized);
382 
383     ImmutableIntArray overSized = ImmutableIntArray.builder(3).add(0).add(1).build();
384     assertActuallyTrims(overSized);
385 
386     ImmutableIntArray underSized = ImmutableIntArray.builder(2).add(0).add(1).add(3).build();
387     assertActuallyTrims(underSized);
388   }
389 
390   @J2ktIncompatible
391   @GwtIncompatible // SerializableTester
392   public void testSerialization() {
393     assertThat(reserialize(ImmutableIntArray.of())).isSameInstanceAs(ImmutableIntArray.of());
394     assertThat(reserialize(ImmutableIntArray.of(0, 1).subArray(1, 1)))
395         .isSameInstanceAs(ImmutableIntArray.of());
396 
397     ImmutableIntArray iia = ImmutableIntArray.of(0, 1, 3, 6).subArray(1, 3);
398     ImmutableIntArray iia2 = reserialize(iia);
399     assertThat(iia2).isEqualTo(iia);
400     assertDoesntActuallyTrim(iia2);
401   }
402 
403   private static void assertActuallyTrims(ImmutableIntArray iia) {
404     ImmutableIntArray trimmed = iia.trimmed();
405     assertThat(trimmed).isNotSameInstanceAs(iia);
406 
407     // Yes, this is apparently how you check array equality in Truth
408     assertThat(trimmed.toArray()).isEqualTo(iia.toArray());
409   }
410 
411   private static void assertDoesntActuallyTrim(ImmutableIntArray iia) {
412     assertThat(iia.trimmed()).isSameInstanceAs(iia);
413   }
414 
415   @J2ktIncompatible
416   @GwtIncompatible // suite
417   public static Test suite() {
418     List<ListTestSuiteBuilder<Integer>> builders =
419         ImmutableList.of(
420             ListTestSuiteBuilder.using(new ImmutableIntArrayAsListGenerator())
421                 .named("ImmutableIntArray.asList"),
422             ListTestSuiteBuilder.using(new ImmutableIntArrayHeadSubListAsListGenerator())
423                 .named("ImmutableIntArray.asList, head subList"),
424             ListTestSuiteBuilder.using(new ImmutableIntArrayTailSubListAsListGenerator())
425                 .named("ImmutableIntArray.asList, tail subList"),
426             ListTestSuiteBuilder.using(new ImmutableIntArrayMiddleSubListAsListGenerator())
427                 .named("ImmutableIntArray.asList, middle subList"));
428 
429     TestSuite suite = new TestSuite();
430     for (ListTestSuiteBuilder<Integer> builder : builders) {
431       suite.addTest(
432           builder
433               .withFeatures(
434                   CollectionSize.ZERO,
435                   CollectionSize.ONE,
436                   CollectionSize.SEVERAL,
437                   CollectionFeature.ALLOWS_NULL_QUERIES,
438                   CollectionFeature.RESTRICTS_ELEMENTS,
439                   CollectionFeature.KNOWN_ORDER,
440                   CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS)
441               .createTestSuite());
442     }
443     suite.addTestSuite(ImmutableIntArrayTest.class);
444     return suite;
445   }
446 
447   @J2ktIncompatible
448   @GwtIncompatible // used only from suite
449   private static ImmutableIntArray makeArray(Integer[] values) {
450     return ImmutableIntArray.copyOf(Arrays.asList(values));
451   }
452 
453   // Test generators.  To let the GWT test suite generator access them, they need to be public named
454   // classes with a public default constructor (not that we run these suites under GWT yet).
455 
456   @J2ktIncompatible
457   @GwtIncompatible // used only from suite
458   public static final class ImmutableIntArrayAsListGenerator extends TestIntegerListGenerator {
459     @Override
460     protected List<Integer> create(Integer[] elements) {
461       return makeArray(elements).asList();
462     }
463   }
464 
465   @J2ktIncompatible
466   @GwtIncompatible // used only from suite
467   public static final class ImmutableIntArrayHeadSubListAsListGenerator
468       extends TestIntegerListGenerator {
469     @Override
470     protected List<Integer> create(Integer[] elements) {
471       Integer[] suffix = {Integer.MIN_VALUE, Integer.MAX_VALUE};
472       Integer[] all = concat(elements, suffix);
473       return makeArray(all).subArray(0, elements.length).asList();
474     }
475   }
476 
477   @J2ktIncompatible
478   @GwtIncompatible // used only from suite
479   public static final class ImmutableIntArrayTailSubListAsListGenerator
480       extends TestIntegerListGenerator {
481     @Override
482     protected List<Integer> create(Integer[] elements) {
483       Integer[] prefix = {86, 99};
484       Integer[] all = concat(prefix, elements);
485       return makeArray(all).subArray(2, elements.length + 2).asList();
486     }
487   }
488 
489   @J2ktIncompatible
490   @GwtIncompatible // used only from suite
491   public static final class ImmutableIntArrayMiddleSubListAsListGenerator
492       extends TestIntegerListGenerator {
493     @Override
494     protected List<Integer> create(Integer[] elements) {
495       Integer[] prefix = {Integer.MIN_VALUE, Integer.MAX_VALUE};
496       Integer[] suffix = {86, 99};
497       Integer[] all = concat(concat(prefix, elements), suffix);
498       return makeArray(all).subArray(2, elements.length + 2).asList();
499     }
500   }
501 
502   @J2ktIncompatible
503   @GwtIncompatible // used only from suite
504   private static Integer[] concat(Integer[] a, Integer[] b) {
505     return ObjectArrays.concat(a, b, Integer.class);
506   }
507 
508   @J2ktIncompatible
509   @GwtIncompatible // used only from suite
510   public abstract static class TestIntegerListGenerator implements TestListGenerator<Integer> {
511     @Override
512     public SampleElements<Integer> samples() {
513       return new SampleIntegers();
514     }
515 
516     @Override
517     public List<Integer> create(Object... elements) {
518       Integer[] array = new Integer[elements.length];
519       int i = 0;
520       for (Object e : elements) {
521         array[i++] = (Integer) e;
522       }
523       return create(array);
524     }
525 
526     /**
527      * Creates a new collection containing the given elements; implement this method instead of
528      * {@link #create(Object...)}.
529      */
530     protected abstract List<Integer> create(Integer[] elements);
531 
532     @Override
533     public Integer[] createArray(int length) {
534       return new Integer[length];
535     }
536 
537     /** Returns the original element list, unchanged. */
538     @Override
539     public List<Integer> order(List<Integer> insertionOrder) {
540       return insertionOrder;
541     }
542   }
543 
544   @J2ktIncompatible
545   @GwtIncompatible // used only from suite
546   public static class SampleIntegers extends SampleElements<Integer> {
547     public SampleIntegers() {
548       super(1, 3, 6, 10, 15);
549     }
550   }
551 }
552