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