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