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