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