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 }