1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package test.java.util.Arrays; 24 25 /* 26 * @test 27 * @bug 8033148 8141409 28 * @summary tests for array equals and compare 29 * @run testng ArraysEqCmpTest 30 */ 31 32 import android.platform.test.annotations.LargeTest; 33 34 import org.testng.Assert; 35 import org.testng.annotations.DataProvider; 36 import org.testng.annotations.Test; 37 38 import java.lang.invoke.MethodHandle; 39 import java.lang.invoke.MethodHandles; 40 import java.lang.invoke.MethodType; 41 import java.lang.reflect.Array; 42 import java.util.Arrays; 43 import java.util.Comparator; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Objects; 48 import java.util.function.BiFunction; 49 import java.util.function.LongFunction; 50 import java.util.stream.IntStream; 51 52 public class ArraysEqCmpTest { 53 54 // Maximum width in bits 55 static final int MAX_WIDTH = 512; 56 57 static final Map<Class, Integer> typeToWidth; 58 59 static { 60 typeToWidth = new HashMap<>(); typeToWidth.put(boolean.class, Byte.SIZE)61 typeToWidth.put(boolean.class, Byte.SIZE); typeToWidth.put(byte.class, Byte.SIZE)62 typeToWidth.put(byte.class, Byte.SIZE); typeToWidth.put(short.class, Short.SIZE)63 typeToWidth.put(short.class, Short.SIZE); typeToWidth.put(char.class, Character.SIZE)64 typeToWidth.put(char.class, Character.SIZE); typeToWidth.put(int.class, Integer.SIZE)65 typeToWidth.put(int.class, Integer.SIZE); typeToWidth.put(long.class, Long.SIZE)66 typeToWidth.put(long.class, Long.SIZE); typeToWidth.put(float.class, Float.SIZE)67 typeToWidth.put(float.class, Float.SIZE); typeToWidth.put(double.class, Double.SIZE)68 typeToWidth.put(double.class, Double.SIZE); typeToWidth.put(Object.class, Integer.SIZE)69 typeToWidth.put(Object.class, Integer.SIZE); // @@@ 32 or 64? 70 } 71 arraySizeFor(Class<?> type)72 static int arraySizeFor(Class<?> type) { 73 type = type.isPrimitive() ? type : Object.class; 74 return 4 * MAX_WIDTH / typeToWidth.get(type); 75 } 76 77 static abstract class ArrayType<T> { 78 final Class<?> arrayType; 79 final Class<?> componentType; 80 final boolean unsigned; 81 82 final MethodHandle cpy; 83 84 final MethodHandle eq; 85 final MethodHandle eqr; 86 final MethodHandle cmp; 87 final MethodHandle cmpr; 88 final MethodHandle mm; 89 final MethodHandle mmr; 90 91 final MethodHandle getter; 92 93 final MethodHandle toString; 94 ArrayType(Class<T> arrayType)95 public ArrayType(Class<T> arrayType) { 96 this(arrayType, false); 97 } 98 ArrayType(Class<T> arrayType, boolean unsigned)99 public ArrayType(Class<T> arrayType, boolean unsigned) { 100 this.arrayType = arrayType; 101 this.componentType = arrayType.getComponentType(); 102 this.unsigned = unsigned; 103 104 try { 105 MethodHandles.Lookup l = MethodHandles.lookup(); 106 107 getter = MethodHandles.arrayElementGetter(arrayType); 108 109 if (componentType.isPrimitive()) { 110 cpy = l.findStatic(Arrays.class, "copyOfRange", 111 MethodType.methodType(arrayType, arrayType, int.class, int.class)); 112 113 MethodType eqt = MethodType.methodType( 114 boolean.class, arrayType, arrayType); 115 MethodType eqrt = MethodType.methodType( 116 boolean.class, arrayType, int.class, int.class, arrayType, int.class, int.class); 117 118 eq = l.findStatic(Arrays.class, "equals", eqt); 119 eqr = l.findStatic(Arrays.class, "equals", eqrt); 120 121 String compareName = unsigned ? "compareUnsigned" : "compare"; 122 cmp = l.findStatic(Arrays.class, compareName, 123 eqt.changeReturnType(int.class)); 124 cmpr = l.findStatic(Arrays.class, compareName, 125 eqrt.changeReturnType(int.class)); 126 127 mm = l.findStatic(Arrays.class, "mismatch", 128 eqt.changeReturnType(int.class)); 129 mmr = l.findStatic(Arrays.class, "mismatch", 130 eqrt.changeReturnType(int.class)); 131 132 toString = l.findStatic(Arrays.class, "toString", 133 MethodType.methodType(String.class, arrayType)); 134 } 135 else { 136 cpy = l.findStatic(Arrays.class, "copyOfRange", 137 MethodType.methodType(Object[].class, Object[].class, int.class, int.class)); 138 139 MethodType eqt = MethodType.methodType( 140 boolean.class, Object[].class, Object[].class); 141 MethodType eqrt = MethodType.methodType( 142 boolean.class, Object[].class, int.class, int.class, Object[].class, int.class, int.class); 143 144 eq = l.findStatic(Arrays.class, "equals", eqt); 145 eqr = l.findStatic(Arrays.class, "equals", eqrt); 146 147 MethodType cmpt = MethodType.methodType( 148 int.class, Comparable[].class, Comparable[].class); 149 MethodType cmprt = MethodType.methodType( 150 int.class, Comparable[].class, int.class, int.class, Comparable[].class, int.class, int.class); 151 152 cmp = l.findStatic(Arrays.class, "compare", cmpt); 153 cmpr = l.findStatic(Arrays.class, "compare", cmprt); 154 155 mm = l.findStatic(Arrays.class, "mismatch", 156 eqt.changeReturnType(int.class)); 157 mmr = l.findStatic(Arrays.class, "mismatch", 158 eqrt.changeReturnType(int.class)); 159 160 toString = l.findStatic(Arrays.class, "toString", 161 MethodType.methodType(String.class, Object[].class)); 162 } 163 164 } 165 catch (Exception e) { 166 throw new Error(e); 167 } 168 } 169 170 @Override toString()171 public String toString() { 172 String s = arrayType.getCanonicalName(); 173 return unsigned ? "unsigned " + s : s; 174 } 175 construct(int length)176 Object construct(int length) { 177 return Array.newInstance(componentType, length); 178 } 179 copyOf(Object a)180 Object copyOf(Object a) { 181 return copyOf(a, 0, Array.getLength(a)); 182 } 183 copyOf(Object a, int from, int to)184 Object copyOf(Object a, int from, int to) { 185 try { 186 return (Object) cpy.invoke(a, from, to); 187 } 188 catch (RuntimeException | Error e) { 189 throw e; 190 } 191 catch (Throwable t) { 192 throw new Error(t); 193 } 194 } 195 get(Object a, int i)196 Object get(Object a, int i) { 197 try { 198 return (Object) getter.invoke(a, i); 199 } 200 catch (RuntimeException | Error e) { 201 throw e; 202 } 203 catch (Throwable t) { 204 throw new Error(t); 205 } 206 } 207 set(Object a, int i, Object v)208 abstract void set(Object a, int i, Object v); 209 equals(Object a, Object b)210 boolean equals(Object a, Object b) { 211 try { 212 return (boolean) eq.invoke(a, b); 213 } 214 catch (RuntimeException | Error e) { 215 throw e; 216 } 217 catch (Throwable t) { 218 throw new Error(t); 219 } 220 } 221 equals(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)222 boolean equals(Object a, int aFromIndex, int aToIndex, 223 Object b, int bFromIndex, int bToIndex) { 224 try { 225 return (boolean) eqr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex); 226 } 227 catch (RuntimeException | Error e) { 228 throw e; 229 } 230 catch (Throwable t) { 231 throw new Error(t); 232 } 233 } 234 compare(Object a, Object b)235 int compare(Object a, Object b) { 236 try { 237 return (int) cmp.invoke(a, b); 238 } 239 catch (RuntimeException | Error e) { 240 throw e; 241 } 242 catch (Throwable t) { 243 throw new Error(t); 244 } 245 } 246 compare(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)247 int compare(Object a, int aFromIndex, int aToIndex, 248 Object b, int bFromIndex, int bToIndex) { 249 try { 250 return (int) cmpr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex); 251 } 252 catch (RuntimeException | Error e) { 253 throw e; 254 } 255 catch (Throwable t) { 256 throw new Error(t); 257 } 258 } 259 mismatch(Object a, Object b)260 int mismatch(Object a, Object b) { 261 try { 262 return (int) mm.invoke(a, b); 263 } 264 catch (RuntimeException | Error e) { 265 throw e; 266 } 267 catch (Throwable t) { 268 throw new Error(t); 269 } 270 } 271 mismatch(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)272 int mismatch(Object a, int aFromIndex, int aToIndex, 273 Object b, int bFromIndex, int bToIndex) { 274 try { 275 return (int) mmr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex); 276 } 277 catch (RuntimeException | Error e) { 278 throw e; 279 } 280 catch (Throwable t) { 281 throw new Error(t); 282 } 283 } 284 toString(Object a)285 String toString(Object a) { 286 try { 287 return (String) toString.invoke(a); 288 } 289 catch (RuntimeException | Error e) { 290 throw e; 291 } 292 catch (Throwable t) { 293 throw new Error(t); 294 } 295 } 296 297 static class BoxedIntegers extends ArrayType<Integer[]> { BoxedIntegers()298 public BoxedIntegers() { 299 super(Integer[].class); 300 } 301 302 @Override set(Object a, int i, Object v)303 void set(Object a, int i, Object v) { 304 // Ensure unique reference 305 ((Integer[]) a)[i] = v != null ? new Integer((Integer) v) : null; 306 } 307 } 308 309 static class BoxedIntegersWithReverseComparator extends BoxedIntegers { 310 final Comparator<Integer> c = (a, b) -> { 311 // Nulls sort after non-nulls 312 if (a == null || b == null) 313 return a == null ? b == null ? 0 : 1 : -1; 314 315 return Integer.compare(b, a); 316 }; 317 318 final MethodHandle eqc; 319 final MethodHandle eqcr; 320 final MethodHandle cmpc; 321 final MethodHandle cmpcr; 322 final MethodHandle mismatchc; 323 final MethodHandle mismatchcr; 324 BoxedIntegersWithReverseComparator()325 public BoxedIntegersWithReverseComparator() { 326 try { 327 MethodHandles.Lookup l = MethodHandles.lookup(); 328 329 MethodType cmpt = MethodType.methodType( 330 int.class, Object[].class, Object[].class, Comparator.class); 331 MethodType cmprt = MethodType.methodType( 332 int.class, Object[].class, int.class, int.class, 333 Object[].class, int.class, int.class, Comparator.class); 334 335 eqc = l.findStatic(Arrays.class, "equals", cmpt.changeReturnType(boolean.class)); 336 eqcr = l.findStatic(Arrays.class, "equals", cmprt.changeReturnType(boolean.class)); 337 cmpc = l.findStatic(Arrays.class, "compare", cmpt); 338 cmpcr = l.findStatic(Arrays.class, "compare", cmprt); 339 mismatchc = l.findStatic(Arrays.class, "mismatch", cmpt); 340 mismatchcr = l.findStatic(Arrays.class, "mismatch", cmprt); 341 } 342 catch (Exception e) { 343 throw new Error(e); 344 } 345 } 346 347 @Override equals(Object a, Object b)348 boolean equals(Object a, Object b) { 349 try { 350 return (boolean) eqc.invoke(a, b, c); 351 } 352 catch (RuntimeException | Error e) { 353 throw e; 354 } 355 catch (Throwable t) { 356 throw new Error(t); 357 } 358 } 359 360 @Override equals(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)361 boolean equals(Object a, int aFromIndex, int aToIndex, 362 Object b, int bFromIndex, int bToIndex) { 363 try { 364 return (boolean) eqcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c); 365 } 366 catch (RuntimeException | Error e) { 367 throw e; 368 } 369 catch (Throwable t) { 370 throw new Error(t); 371 } 372 } 373 374 @Override compare(Object a, Object b)375 int compare(Object a, Object b) { 376 try { 377 return (int) cmpc.invoke(a, b, c); 378 } 379 catch (RuntimeException | Error e) { 380 throw e; 381 } 382 catch (Throwable t) { 383 throw new Error(t); 384 } 385 } 386 387 @Override compare(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)388 int compare(Object a, int aFromIndex, int aToIndex, 389 Object b, int bFromIndex, int bToIndex) { 390 try { 391 return (int) cmpcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c); 392 } 393 catch (RuntimeException | Error e) { 394 throw e; 395 } 396 catch (Throwable t) { 397 throw new Error(t); 398 } 399 } 400 401 @Override mismatch(Object a, Object b)402 int mismatch(Object a, Object b) { 403 try { 404 return (int) mismatchc.invoke(a, b, c); 405 } 406 catch (RuntimeException | Error e) { 407 throw e; 408 } 409 catch (Throwable t) { 410 throw new Error(t); 411 } 412 } 413 414 @Override mismatch(Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)415 int mismatch(Object a, int aFromIndex, int aToIndex, 416 Object b, int bFromIndex, int bToIndex) { 417 try { 418 return (int) mismatchcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c); 419 } 420 catch (RuntimeException | Error e) { 421 throw e; 422 } 423 catch (Throwable t) { 424 throw new Error(t); 425 } 426 } 427 428 @Override toString()429 public String toString() { 430 return arrayType.getCanonicalName() + " with Comparator"; 431 } 432 } 433 434 static class Booleans extends ArrayType<boolean[]> { Booleans()435 public Booleans() { 436 super(boolean[].class); 437 } 438 439 @Override set(Object a, int i, Object v)440 void set(Object a, int i, Object v) { 441 boolean pv; 442 if (v instanceof Boolean) { 443 pv = (Boolean) v; 444 } 445 else if (v instanceof Integer) { 446 pv = ((Integer) v) >= 0; 447 } 448 else throw new IllegalStateException(); 449 450 ((boolean[]) a)[i] = pv; 451 } 452 } 453 454 static class Bytes extends ArrayType<byte[]> { Bytes(boolean unsigned)455 public Bytes(boolean unsigned) { 456 super(byte[].class, unsigned); 457 } 458 459 @Override set(Object a, int i, Object v)460 void set(Object a, int i, Object v) { 461 byte pv; 462 if (v instanceof Byte) { 463 pv = (Byte) v; 464 } 465 else if (v instanceof Integer) { 466 pv = ((Integer) v).byteValue(); 467 } 468 else throw new IllegalStateException(); 469 470 ((byte[]) a)[i] = pv; 471 } 472 } 473 474 static class Characters extends ArrayType<char[]> { Characters()475 public Characters() { 476 super(char[].class); 477 } 478 479 @Override set(Object a, int i, Object v)480 void set(Object a, int i, Object v) { 481 char pv; 482 if (v instanceof Character) { 483 pv = (Character) v; 484 } 485 else if (v instanceof Integer) { 486 pv = (char) ((Integer) v).intValue(); 487 } 488 else throw new IllegalStateException(); 489 490 ((char[]) a)[i] = pv; 491 } 492 } 493 494 static class Shorts extends ArrayType<short[]> { Shorts(boolean unsigned)495 public Shorts(boolean unsigned) { 496 super(short[].class, unsigned); 497 } 498 499 @Override set(Object a, int i, Object v)500 void set(Object a, int i, Object v) { 501 short pv; 502 if (v instanceof Short) { 503 pv = (Short) v; 504 } 505 else if (v instanceof Integer) { 506 pv = ((Integer) v).shortValue(); 507 } 508 else throw new IllegalStateException(); 509 510 ((short[]) a)[i] = pv; 511 } 512 } 513 514 static class Integers extends ArrayType<int[]> { Integers(boolean unsigned)515 public Integers(boolean unsigned) { 516 super(int[].class, unsigned); 517 } 518 519 @Override set(Object a, int i, Object v)520 void set(Object a, int i, Object v) { 521 int pv; 522 if (v instanceof Integer) { 523 pv = ((Integer) v).shortValue(); 524 } 525 else throw new IllegalStateException(); 526 527 ((int[]) a)[i] = pv; 528 } 529 } 530 531 static class Longs extends ArrayType<long[]> { Longs(boolean unsigned)532 public Longs(boolean unsigned) { 533 super(long[].class, unsigned); 534 } 535 536 @Override set(Object a, int i, Object v)537 void set(Object a, int i, Object v) { 538 long pv; 539 if (v instanceof Long) { 540 pv = (Long) v; 541 } 542 else if (v instanceof Integer) { 543 pv = ((Integer) v).longValue(); 544 } 545 else throw new IllegalStateException(); 546 547 ((long[]) a)[i] = pv; 548 } 549 } 550 551 static class Floats extends ArrayType<float[]> { Floats()552 public Floats() { 553 super(float[].class); 554 } 555 556 @Override set(Object a, int i, Object v)557 void set(Object a, int i, Object v) { 558 float pv; 559 if (v instanceof Float) { 560 pv = (Float) v; 561 } 562 else if (v instanceof Integer) { 563 pv = ((Integer) v).floatValue(); 564 } 565 else throw new IllegalStateException(); 566 567 ((float[]) a)[i] = pv; 568 } 569 } 570 571 static class Doubles extends ArrayType<double[]> { Doubles()572 public Doubles() { 573 super(double[].class); 574 } 575 576 @Override set(Object a, int i, Object v)577 void set(Object a, int i, Object v) { 578 double pv; 579 if (v instanceof Double) { 580 pv = (Double) v; 581 } 582 else if (v instanceof Integer) { 583 pv = ((Integer) v).doubleValue(); 584 } 585 else throw new IllegalStateException(); 586 587 ((double[]) a)[i] = pv; 588 } 589 } 590 } 591 592 static Object[][] arrayTypes; 593 594 @DataProvider arrayTypesProvider()595 public static Object[][] arrayTypesProvider() { 596 if (arrayTypes == null) { 597 arrayTypes = new Object[][]{ 598 new Object[]{new ArrayType.BoxedIntegers()}, 599 new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()}, 600 new Object[]{new ArrayType.Booleans()}, 601 new Object[]{new ArrayType.Bytes(false)}, 602 new Object[]{new ArrayType.Bytes(true)}, 603 new Object[]{new ArrayType.Characters()}, 604 new Object[]{new ArrayType.Shorts(false)}, 605 new Object[]{new ArrayType.Shorts(true)}, 606 new Object[]{new ArrayType.Integers(false)}, 607 new Object[]{new ArrayType.Integers(true)}, 608 new Object[]{new ArrayType.Longs(false)}, 609 new Object[]{new ArrayType.Longs(true)}, 610 new Object[]{new ArrayType.Floats()}, 611 new Object[]{new ArrayType.Doubles()}, 612 }; 613 } 614 return arrayTypes; 615 } 616 617 static Object[][] floatArrayTypes; 618 619 @DataProvider floatArrayTypesProvider()620 public static Object[][] floatArrayTypesProvider() { 621 if (floatArrayTypes == null) { 622 LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb); 623 LongFunction<Object> bToD = Double::longBitsToDouble; 624 625 floatArrayTypes = new Object[][]{ 626 new Object[]{new ArrayType.Floats(), 0x7fc00000L, 0x7f800001L, bTof}, 627 new Object[]{new ArrayType.Doubles(), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD}, 628 }; 629 } 630 return floatArrayTypes; 631 } 632 633 static Object[][] objectArrayTypes; 634 635 @DataProvider objectArrayTypesProvider()636 public static Object[][] objectArrayTypesProvider() { 637 if (objectArrayTypes == null) { 638 LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb); 639 LongFunction<Object> bToD = Double::longBitsToDouble; 640 641 objectArrayTypes = new Object[][]{ 642 new Object[]{new ArrayType.BoxedIntegers()}, 643 new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()}, 644 }; 645 } 646 return objectArrayTypes; 647 } 648 649 650 static Object[][] signedUnsignedArrayTypes; 651 652 @DataProvider signedUnsignedArrayTypes()653 public static Object[][] signedUnsignedArrayTypes() { 654 if (signedUnsignedArrayTypes == null) { 655 signedUnsignedArrayTypes = new Object[][]{ 656 new Object[]{new ArrayType.Bytes(false), new ArrayType.Bytes(true)}, 657 new Object[]{new ArrayType.Shorts(false), new ArrayType.Shorts(true)}, 658 new Object[]{new ArrayType.Integers(false), new ArrayType.Integers(true)}, 659 new Object[]{new ArrayType.Longs(false), new ArrayType.Longs(true)}, 660 }; 661 } 662 return signedUnsignedArrayTypes; 663 } 664 665 // Equality and comparison tests 666 667 @LargeTest 668 @Test(dataProvider = "arrayTypesProvider") testArray(ArrayType<?> arrayType)669 public void testArray(ArrayType<?> arrayType) { 670 BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> { 671 Object a = at.construct(s); 672 for (int x = 0; x < s; x++) { 673 at.set(a, x, x % 8); 674 } 675 return a; 676 }; 677 678 BiFunction<ArrayType<?>, Object, Object> cloner = (at, a) -> 679 constructor.apply(at, Array.getLength(a)); 680 681 testArrayType(arrayType, constructor, cloner); 682 } 683 684 @LargeTest 685 @Test(dataProvider = "floatArrayTypesProvider") testPrimitiveFloatArray( ArrayType<?> arrayType, long canonicalNanRawBits, long nonCanonicalNanRawBits, LongFunction<Object> bitsToFloat)686 public void testPrimitiveFloatArray( 687 ArrayType<?> arrayType, 688 long canonicalNanRawBits, long nonCanonicalNanRawBits, 689 LongFunction<Object> bitsToFloat) { 690 Object canonicalNan = bitsToFloat.apply(canonicalNanRawBits); 691 // If conversion is a signalling NaN it may be subject to conversion to a 692 // quiet NaN on some processors, even if a copy is performed 693 // The tests assume that if conversion occurs it does not convert to the 694 // canonical NaN 695 Object nonCanonicalNan = bitsToFloat.apply(nonCanonicalNanRawBits); 696 697 BiFunction<ArrayType<?>, Integer, Object> canonicalNaNs = (at, s) -> { 698 Object a = at.construct(s); 699 for (int x = 0; x < s; x++) { 700 at.set(a, x, canonicalNan); 701 } 702 return a; 703 }; 704 705 BiFunction<ArrayType<?>, Object, Object> nonCanonicalNaNs = (at, a) -> { 706 int s = Array.getLength(a); 707 Object ac = at.construct(s); 708 for (int x = 0; x < s; x++) { 709 at.set(ac, x, nonCanonicalNan); 710 } 711 return ac; 712 }; 713 714 BiFunction<ArrayType<?>, Object, Object> halfNonCanonicalNaNs = (at, a) -> { 715 int s = Array.getLength(a); 716 Object ac = at.construct(s); 717 for (int x = 0; x < s / 2; x++) { 718 at.set(ac, x, nonCanonicalNan); 719 } 720 for (int x = s / 2; x < s; x++) { 721 at.set(ac, x, 1); 722 } 723 return ac; 724 }; 725 726 testArrayType(arrayType, canonicalNaNs, nonCanonicalNaNs); 727 testArrayType(arrayType, canonicalNaNs, halfNonCanonicalNaNs); 728 } 729 730 @LargeTest 731 @Test(dataProvider = "objectArrayTypesProvider") testNullElementsInObjectArray(ArrayType<?> arrayType)732 public void testNullElementsInObjectArray(ArrayType<?> arrayType) { 733 BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf; 734 735 // All nulls 736 testArrayType(arrayType, 737 (at, s) -> { 738 Object a = at.construct(s); 739 for (int x = 0; x < s; x++) { 740 at.set(a, x, null); 741 } 742 return a; 743 }, 744 cloner); 745 746 747 // Some nulls 748 testArrayType(arrayType, 749 (at, s) -> { 750 Object a = at.construct(s); 751 for (int x = 0; x < s; x++) { 752 int v = x % 8; 753 at.set(a, x, v == 0 ? null : v); 754 } 755 return a; 756 }, 757 cloner); 758 759 Integer[] a = new Integer[]{null, 0}; 760 Integer[] b = new Integer[]{0, 0}; 761 Assert.assertTrue(Arrays.compare(a, b) < 0); 762 Assert.assertTrue(Arrays.compare(b, a) > 0); 763 } 764 765 @LargeTest 766 @Test(dataProvider = "objectArrayTypesProvider") testSameRefElementsInObjectArray(ArrayType<?> arrayType)767 public void testSameRefElementsInObjectArray(ArrayType<?> arrayType) { 768 BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf; 769 770 // One ref 771 Integer one = 1; 772 testArrayType(arrayType, 773 (at, s) -> { 774 Integer[] a = (Integer[]) at.construct(s); 775 for (int x = 0; x < s; x++) { 776 a[x] = one; 777 } 778 return a; 779 }, 780 cloner); 781 782 // All ref 783 testArrayType(arrayType, 784 (at, s) -> { 785 Integer[] a = (Integer[]) at.construct(s); 786 for (int x = 0; x < s; x++) { 787 a[x] = Integer.valueOf(s); 788 } 789 return a; 790 }, 791 cloner); 792 793 // Some same ref 794 testArrayType(arrayType, 795 (at, s) -> { 796 Integer[] a = (Integer[]) at.construct(s); 797 for (int x = 0; x < s; x++) { 798 int v = x % 8; 799 a[x] = v == 1 ? one : new Integer(v); 800 } 801 return a; 802 }, 803 cloner); 804 } 805 806 @Test(dataProvider = "signedUnsignedArrayTypes") testSignedUnsignedArray(ArrayType<?> sat, ArrayType<?> uat)807 public void testSignedUnsignedArray(ArrayType<?> sat, ArrayType<?> uat) { 808 BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> { 809 Object a = at.construct(s); 810 for (int x = 0; x < s; x++) { 811 at.set(a, x, 1); 812 } 813 return a; 814 }; 815 816 int n = arraySizeFor(sat.componentType); 817 818 for (int s : ranges(0, n)) { 819 Object a = constructor.apply(sat, s); 820 821 for (int aFrom : ranges(0, s)) { 822 for (int aTo : ranges(aFrom, s)) { 823 int aLength = aTo - aFrom; 824 825 if (aLength > 0) { 826 for (int i = aFrom; i < aTo; i++) { 827 Object ac = sat.copyOf(a); 828 // Create common prefix with a length of i - aFrom 829 sat.set(ac, i, -1); 830 831 int sc = sat.compare(ac, aFrom, aTo, a, aFrom, aTo); 832 int uc = uat.compare(ac, aFrom, aTo, a, aFrom, aTo); 833 834 Assert.assertTrue(sc < 0); 835 Assert.assertTrue(uc > 0); 836 } 837 } 838 } 839 } 840 } 841 } 842 testArrayType(ArrayType<?> at, BiFunction<ArrayType<?>, Integer, Object> constructor, BiFunction<ArrayType<?>, Object, Object> cloner)843 void testArrayType(ArrayType<?> at, 844 BiFunction<ArrayType<?>, Integer, Object> constructor, 845 BiFunction<ArrayType<?>, Object, Object> cloner) { 846 int n = arraySizeFor(at.componentType); 847 848 for (int s : ranges(0, n)) { 849 Object a = constructor.apply(at, s); 850 Object b = cloner.apply(at, a); 851 852 for (int aFrom : ranges(0, s)) { 853 for (int aTo : ranges(aFrom, s)) { 854 int aLength = aTo - aFrom; 855 856 for (int bFrom : ranges(0, s)) { 857 for (int bTo : ranges(bFrom, s)) { 858 int bLength = bTo - bFrom; 859 860 Object anr = at.copyOf(a, aFrom, aTo); 861 Object bnr = at.copyOf(b, bFrom, bTo); 862 863 boolean eq = isEqual(at, a, aFrom, aTo, b, bFrom, bTo); 864 Assert.assertEquals(at.equals(a, aFrom, aTo, b, bFrom, bTo), eq); 865 Assert.assertEquals(at.equals(b, bFrom, bTo, a, aFrom, aTo), eq); 866 Assert.assertEquals(at.equals(anr, bnr), eq); 867 Assert.assertEquals(at.equals(bnr, anr), eq); 868 if (eq) { 869 Assert.assertEquals(at.compare(a, aFrom, aTo, b, bFrom, bTo), 0); 870 Assert.assertEquals(at.compare(b, bFrom, bTo, a, aFrom, aTo), 0); 871 Assert.assertEquals(at.compare(anr, bnr), 0); 872 Assert.assertEquals(at.compare(bnr, anr), 0); 873 874 Assert.assertEquals(at.mismatch(a, aFrom, aTo, b, bFrom, bTo), -1); 875 Assert.assertEquals(at.mismatch(b, bFrom, bTo, a, aFrom, aTo), -1); 876 Assert.assertEquals(at.mismatch(anr, bnr), -1); 877 Assert.assertEquals(at.mismatch(bnr, anr), -1); 878 } 879 else { 880 int aCb = at.compare(a, aFrom, aTo, b, bFrom, bTo); 881 int bCa = at.compare(b, bFrom, bTo, a, aFrom, aTo); 882 int v = Integer.signum(aCb) * Integer.signum(bCa); 883 Assert.assertTrue(v == -1); 884 885 int anrCbnr = at.compare(anr, bnr); 886 int bnrCanr = at.compare(bnr, anr); 887 Assert.assertEquals(anrCbnr, aCb); 888 Assert.assertEquals(bnrCanr, bCa); 889 890 891 int aMb = at.mismatch(a, aFrom, aTo, b, bFrom, bTo); 892 int bMa = at.mismatch(b, bFrom, bTo, a, aFrom, aTo); 893 int anrMbnr = at.mismatch(anr, bnr); 894 int bnrManr = at.mismatch(bnr, anr); 895 896 Assert.assertNotEquals(aMb, -1); 897 Assert.assertEquals(aMb, bMa); 898 Assert.assertNotEquals(anrMbnr, -1); 899 Assert.assertEquals(anrMbnr, bnrManr); 900 Assert.assertEquals(aMb, anrMbnr); 901 Assert.assertEquals(bMa, bnrManr); 902 903 // Common or proper prefix 904 Assert.assertTrue(at.equals(a, aFrom, aFrom + aMb, b, bFrom, bFrom + aMb)); 905 if (aMb < Math.min(aLength, bLength)) { 906 // Common prefix 907 Assert.assertFalse(isEqual(at, a, aFrom + aMb, b, bFrom + aMb)); 908 } 909 } 910 } 911 } 912 913 if (aLength > 0) { 914 for (int i = aFrom; i < aTo; i++) { 915 Object ac = at.copyOf(a); 916 // Create common prefix with a length of i - aFrom 917 at.set(ac, i, -1); 918 919 Object acnr = at.copyOf(ac, aFrom, aTo); 920 Object anr = at.copyOf(a, aFrom, aTo); 921 922 Assert.assertFalse(at.equals(ac, aFrom, aTo, a, aFrom, aTo)); 923 Assert.assertFalse(at.equals(acnr, anr)); 924 925 int acCa = at.compare(ac, aFrom, aTo, a, aFrom, aTo); 926 int aCac = at.compare(a, aFrom, aTo, ac, aFrom, aTo); 927 int v = Integer.signum(acCa) * Integer.signum(aCac); 928 Assert.assertTrue(v == -1); 929 930 int acnrCanr = at.compare(acnr, anr); 931 int anrCacnr = at.compare(anr, acnr); 932 Assert.assertEquals(acnrCanr, acCa); 933 Assert.assertEquals(anrCacnr, aCac); 934 935 936 int acMa = at.mismatch(ac, aFrom, aTo, a, aFrom, aTo); 937 int aMac = at.mismatch(a, aFrom, aTo, ac, aFrom, aTo); 938 Assert.assertEquals(acMa, aMac); 939 Assert.assertEquals(acMa, i - aFrom); 940 941 int acnrManr = at.mismatch(acnr, anr); 942 int anrMacnr = at.mismatch(anr, acnr); 943 Assert.assertEquals(acnrManr, anrMacnr); 944 Assert.assertEquals(acnrManr, i - aFrom); 945 } 946 } 947 } 948 } 949 } 950 } 951 isEqual(ArrayType<?> at, Object a, int aFromIndex, int aToIndex, Object b, int bFromIndex, int bToIndex)952 static boolean isEqual(ArrayType<?> at, Object a, int aFromIndex, int aToIndex, 953 Object b, int bFromIndex, int bToIndex) { 954 int aLength = aToIndex - aFromIndex; 955 int bLength = bToIndex - bFromIndex; 956 if (aLength != bLength) 957 return false; 958 959 for (int i = 0; i < aLength; i++) { 960 Object av = at.get(a, aFromIndex++); 961 Object bv = at.get(b, bFromIndex++); 962 if (!Objects.equals(av, bv)) return false; 963 } 964 965 return true; 966 } 967 isEqual(ArrayType<?> at, Object a, int aFrom, Object b, int bFrom)968 static boolean isEqual(ArrayType<?> at, Object a, int aFrom, Object b, int bFrom) { 969 Object av = at.get(a, aFrom); 970 Object bv = at.get(b, bFrom); 971 972 return Objects.equals(av, bv); 973 } 974 ranges(int from, int to)975 static int[] ranges(int from, int to) { 976 int width = to - from; 977 switch (width) { 978 case 0: 979 return new int[]{}; 980 case 1: 981 return new int[]{from, to}; 982 case 2: 983 return new int[]{from, from + 1, to}; 984 case 3: 985 return new int[]{from, from + 1, from + 2, to}; 986 default: 987 return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to) 988 .filter(i -> i >= from && i <= to) 989 .distinct().toArray(); 990 } 991 } 992 993 994 // Null array reference tests 995 996 @Test(dataProvider = "arrayTypesProvider") testNullArrayRefs(ArrayType<?> arrayType)997 public void testNullArrayRefs(ArrayType<?> arrayType) { 998 Object n = null; 999 Object a = arrayType.construct(0); 1000 1001 Assert.assertTrue(arrayType.equals(n, n)); 1002 Assert.assertFalse(arrayType.equals(n, a)); 1003 Assert.assertFalse(arrayType.equals(a, n)); 1004 1005 Assert.assertEquals(arrayType.compare(n, n), 0); 1006 Assert.assertTrue(arrayType.compare(n, a) < 0); 1007 Assert.assertTrue(arrayType.compare(a, n) > 0); 1008 } 1009 1010 1011 // Exception throwing tests 1012 1013 @Test(dataProvider = "arrayTypesProvider") testNPEs(ArrayType<?> arrayType)1014 public void testNPEs(ArrayType<?> arrayType) { 1015 Object[] values = new Object[]{null, arrayType.construct(0)}; 1016 1017 for (Object o1 : values) { 1018 for (Object o2 : values) { 1019 if (o1 != null && o2 != null) 1020 continue; 1021 1022 testNPE(() -> arrayType.equals(o1, 0, 0, o2, 0, 0)); 1023 testNPE(() -> arrayType.compare(o1, 0, 0, o2, 0, 0)); 1024 testNPE(() -> arrayType.mismatch(o1, o2)); 1025 testNPE(() -> arrayType.mismatch(o1, 0, 0, o2, 0, 0)); 1026 } 1027 } 1028 } 1029 1030 @Test testObjectNPEs()1031 public void testObjectNPEs() { 1032 String[][] values = new String[][]{null, new String[0]}; 1033 Comparator<String> c = String::compareTo; 1034 Comparator[] cs = new Comparator[]{null, c}; 1035 1036 for (String[] o1 : values) { 1037 for (String[] o2 : values) { 1038 for (Comparator o3 : cs) { 1039 if (o1 != null && o2 != null && o3 != null) 1040 continue; 1041 1042 if (o3 == null) { 1043 testNPE(() -> Arrays.equals(o1, o2, o3)); 1044 testNPE(() -> Arrays.compare(o1, o2, o3)); 1045 testNPE(() -> Arrays.mismatch(o1, o2, o3)); 1046 } 1047 1048 testNPE(() -> Arrays.equals(o1, 0, 0, o2, 0, 0, o3)); 1049 testNPE(() -> Arrays.compare(o1, 0, 0, o2, 0, 0, o3)); 1050 testNPE(() -> Arrays.mismatch(o1, 0, 0, o2, 0, 0, o3)); 1051 } 1052 } 1053 } 1054 } 1055 1056 @Test(dataProvider = "arrayTypesProvider") testIAEs(ArrayType<?> arrayType)1057 public void testIAEs(ArrayType<?> arrayType) { 1058 List<Integer> values = Arrays.asList(0, 1); 1059 1060 for (int s : values) { 1061 Object a = arrayType.construct(s); 1062 1063 for (int o1 : values) { 1064 for (int o2 : values) { 1065 if (o1 <= o2) continue; 1066 1067 testIAE(() -> arrayType.equals(a, o1, 0, a, o2, 0)); 1068 testIAE(() -> arrayType.compare(a, o1, 0, a, o2, 0)); 1069 testIAE(() -> arrayType.mismatch(a, o1, 0, a, o2, 0)); 1070 } 1071 } 1072 } 1073 } 1074 1075 @Test(dataProvider = "arrayTypesProvider") testAIOBEs(ArrayType<?> arrayType)1076 public void testAIOBEs(ArrayType<?> arrayType) { 1077 List<Integer> froms = Arrays.asList(-1, 0); 1078 1079 for (int s : Arrays.asList(0, 1)) { 1080 List<Integer> tos = Arrays.asList(s, s + 1); 1081 Object a = arrayType.construct(s); 1082 1083 for (int aFrom : froms) { 1084 for (int aTo : tos) { 1085 for (int bFrom : froms) { 1086 for (int bTo : tos) { 1087 if (aFrom >= 0 && aTo <= s && 1088 bFrom >= 0 && bTo <= s) continue; 1089 1090 testAIOBE(() -> arrayType.equals(a, aFrom, aTo, a, bFrom, bTo)); 1091 testAIOBE(() -> arrayType.compare(a, aFrom, aTo, a, bFrom, bTo)); 1092 testAIOBE(() -> arrayType.mismatch(a, aFrom, aTo, a, bFrom, bTo)); 1093 } 1094 } 1095 } 1096 } 1097 } 1098 } 1099 testNPE(Runnable r)1100 static void testNPE(Runnable r) { 1101 testThrowable(r, NullPointerException.class); 1102 } 1103 testIAE(Runnable r)1104 static void testIAE(Runnable r) { 1105 testThrowable(r, IllegalArgumentException.class); 1106 } 1107 testAIOBE(Runnable r)1108 static void testAIOBE(Runnable r) { 1109 testThrowable(r, ArrayIndexOutOfBoundsException.class); 1110 } 1111 testThrowable(Runnable r, Class<? extends Throwable> expected)1112 static void testThrowable(Runnable r, Class<? extends Throwable> expected) { 1113 Throwable caught = null; 1114 try { 1115 r.run(); 1116 } 1117 catch (Throwable t) { 1118 caught = t; 1119 } 1120 Assert.assertNotNull(caught); 1121 Assert.assertTrue(expected.isInstance(caught)); 1122 } 1123 }