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