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