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