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