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