Path: blob/master/test/jdk/java/util/Arrays/ArraysEqCmpTest.java
41152 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 8033148 814140926* @summary tests for array equals and compare27* @run testng ArraysEqCmpTest28*/2930import org.testng.Assert;31import org.testng.annotations.DataProvider;32import org.testng.annotations.Test;3334import java.lang.invoke.MethodHandle;35import java.lang.invoke.MethodHandles;36import java.lang.invoke.MethodType;37import java.lang.reflect.Array;38import java.util.Arrays;39import java.util.Comparator;40import java.util.HashMap;41import java.util.List;42import java.util.Map;43import java.util.Objects;44import java.util.function.BiFunction;45import java.util.function.LongFunction;46import java.util.stream.IntStream;4748public class ArraysEqCmpTest {4950// Maximum width in bits51static final int MAX_WIDTH = 512;5253static final Map<Class, Integer> typeToWidth;5455static {56typeToWidth = new HashMap<>();57typeToWidth.put(boolean.class, Byte.SIZE);58typeToWidth.put(byte.class, Byte.SIZE);59typeToWidth.put(short.class, Short.SIZE);60typeToWidth.put(char.class, Character.SIZE);61typeToWidth.put(int.class, Integer.SIZE);62typeToWidth.put(long.class, Long.SIZE);63typeToWidth.put(float.class, Float.SIZE);64typeToWidth.put(double.class, Double.SIZE);65typeToWidth.put(Object.class, Integer.SIZE); // @@@ 32 or 64?66}6768static int arraySizeFor(Class<?> type) {69type = type.isPrimitive() ? type : Object.class;70return 4 * MAX_WIDTH / typeToWidth.get(type);71}7273static abstract class ArrayType<T> {74final Class<?> arrayType;75final Class<?> componentType;76final boolean unsigned;7778final MethodHandle cpy;7980final MethodHandle eq;81final MethodHandle eqr;82final MethodHandle cmp;83final MethodHandle cmpr;84final MethodHandle mm;85final MethodHandle mmr;8687final MethodHandle getter;8889final MethodHandle toString;9091public ArrayType(Class<T> arrayType) {92this(arrayType, false);93}9495public ArrayType(Class<T> arrayType, boolean unsigned) {96this.arrayType = arrayType;97this.componentType = arrayType.getComponentType();98this.unsigned = unsigned;99100try {101MethodHandles.Lookup l = MethodHandles.lookup();102103getter = MethodHandles.arrayElementGetter(arrayType);104105if (componentType.isPrimitive()) {106cpy = l.findStatic(Arrays.class, "copyOfRange",107MethodType.methodType(arrayType, arrayType, int.class, int.class));108109MethodType eqt = MethodType.methodType(110boolean.class, arrayType, arrayType);111MethodType eqrt = MethodType.methodType(112boolean.class, arrayType, int.class, int.class, arrayType, int.class, int.class);113114eq = l.findStatic(Arrays.class, "equals", eqt);115eqr = l.findStatic(Arrays.class, "equals", eqrt);116117String compareName = unsigned ? "compareUnsigned" : "compare";118cmp = l.findStatic(Arrays.class, compareName,119eqt.changeReturnType(int.class));120cmpr = l.findStatic(Arrays.class, compareName,121eqrt.changeReturnType(int.class));122123mm = l.findStatic(Arrays.class, "mismatch",124eqt.changeReturnType(int.class));125mmr = l.findStatic(Arrays.class, "mismatch",126eqrt.changeReturnType(int.class));127128toString = l.findStatic(Arrays.class, "toString",129MethodType.methodType(String.class, arrayType));130}131else {132cpy = l.findStatic(Arrays.class, "copyOfRange",133MethodType.methodType(Object[].class, Object[].class, int.class, int.class));134135MethodType eqt = MethodType.methodType(136boolean.class, Object[].class, Object[].class);137MethodType eqrt = MethodType.methodType(138boolean.class, Object[].class, int.class, int.class, Object[].class, int.class, int.class);139140eq = l.findStatic(Arrays.class, "equals", eqt);141eqr = l.findStatic(Arrays.class, "equals", eqrt);142143MethodType cmpt = MethodType.methodType(144int.class, Comparable[].class, Comparable[].class);145MethodType cmprt = MethodType.methodType(146int.class, Comparable[].class, int.class, int.class, Comparable[].class, int.class, int.class);147148cmp = l.findStatic(Arrays.class, "compare", cmpt);149cmpr = l.findStatic(Arrays.class, "compare", cmprt);150151mm = l.findStatic(Arrays.class, "mismatch",152eqt.changeReturnType(int.class));153mmr = l.findStatic(Arrays.class, "mismatch",154eqrt.changeReturnType(int.class));155156toString = l.findStatic(Arrays.class, "toString",157MethodType.methodType(String.class, Object[].class));158}159160}161catch (Exception e) {162throw new Error(e);163}164}165166@Override167public String toString() {168String s = arrayType.getCanonicalName();169return unsigned ? "unsigned " + s : s;170}171172Object construct(int length) {173return Array.newInstance(componentType, length);174}175176Object copyOf(Object a) {177return copyOf(a, 0, Array.getLength(a));178}179180Object copyOf(Object a, int from, int to) {181try {182return (Object) cpy.invoke(a, from, to);183}184catch (RuntimeException | Error e) {185throw e;186}187catch (Throwable t) {188throw new Error(t);189}190}191192Object get(Object a, int i) {193try {194return (Object) getter.invoke(a, i);195}196catch (RuntimeException | Error e) {197throw e;198}199catch (Throwable t) {200throw new Error(t);201}202}203204abstract void set(Object a, int i, Object v);205206boolean equals(Object a, Object b) {207try {208return (boolean) eq.invoke(a, b);209}210catch (RuntimeException | Error e) {211throw e;212}213catch (Throwable t) {214throw new Error(t);215}216}217218boolean equals(Object a, int aFromIndex, int aToIndex,219Object b, int bFromIndex, int bToIndex) {220try {221return (boolean) eqr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);222}223catch (RuntimeException | Error e) {224throw e;225}226catch (Throwable t) {227throw new Error(t);228}229}230231int compare(Object a, Object b) {232try {233return (int) cmp.invoke(a, b);234}235catch (RuntimeException | Error e) {236throw e;237}238catch (Throwable t) {239throw new Error(t);240}241}242243int compare(Object a, int aFromIndex, int aToIndex,244Object b, int bFromIndex, int bToIndex) {245try {246return (int) cmpr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);247}248catch (RuntimeException | Error e) {249throw e;250}251catch (Throwable t) {252throw new Error(t);253}254}255256int mismatch(Object a, Object b) {257try {258return (int) mm.invoke(a, b);259}260catch (RuntimeException | Error e) {261throw e;262}263catch (Throwable t) {264throw new Error(t);265}266}267268int mismatch(Object a, int aFromIndex, int aToIndex,269Object b, int bFromIndex, int bToIndex) {270try {271return (int) mmr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex);272}273catch (RuntimeException | Error e) {274throw e;275}276catch (Throwable t) {277throw new Error(t);278}279}280281String toString(Object a) {282try {283return (String) toString.invoke(a);284}285catch (RuntimeException | Error e) {286throw e;287}288catch (Throwable t) {289throw new Error(t);290}291}292293static class BoxedIntegers extends ArrayType<Integer[]> {294public BoxedIntegers() {295super(Integer[].class);296}297298@Override299void set(Object a, int i, Object v) {300// Ensure unique reference301((Integer[]) a)[i] = v != null ? new Integer((Integer) v) : null;302}303}304305static class BoxedIntegersWithReverseComparator extends BoxedIntegers {306final Comparator<Integer> c = (a, b) -> {307// Nulls sort after non-nulls308if (a == null || b == null)309return a == null ? b == null ? 0 : 1 : -1;310311return Integer.compare(b, a);312};313314final MethodHandle eqc;315final MethodHandle eqcr;316final MethodHandle cmpc;317final MethodHandle cmpcr;318final MethodHandle mismatchc;319final MethodHandle mismatchcr;320321public BoxedIntegersWithReverseComparator() {322try {323MethodHandles.Lookup l = MethodHandles.lookup();324325MethodType cmpt = MethodType.methodType(326int.class, Object[].class, Object[].class, Comparator.class);327MethodType cmprt = MethodType.methodType(328int.class, Object[].class, int.class, int.class,329Object[].class, int.class, int.class, Comparator.class);330331eqc = l.findStatic(Arrays.class, "equals", cmpt.changeReturnType(boolean.class));332eqcr = l.findStatic(Arrays.class, "equals", cmprt.changeReturnType(boolean.class));333cmpc = l.findStatic(Arrays.class, "compare", cmpt);334cmpcr = l.findStatic(Arrays.class, "compare", cmprt);335mismatchc = l.findStatic(Arrays.class, "mismatch", cmpt);336mismatchcr = l.findStatic(Arrays.class, "mismatch", cmprt);337}338catch (Exception e) {339throw new Error(e);340}341}342343@Override344boolean equals(Object a, Object b) {345try {346return (boolean) eqc.invoke(a, b, c);347}348catch (RuntimeException | Error e) {349throw e;350}351catch (Throwable t) {352throw new Error(t);353}354}355356@Override357boolean equals(Object a, int aFromIndex, int aToIndex,358Object b, int bFromIndex, int bToIndex) {359try {360return (boolean) eqcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);361}362catch (RuntimeException | Error e) {363throw e;364}365catch (Throwable t) {366throw new Error(t);367}368}369370@Override371int compare(Object a, Object b) {372try {373return (int) cmpc.invoke(a, b, c);374}375catch (RuntimeException | Error e) {376throw e;377}378catch (Throwable t) {379throw new Error(t);380}381}382383@Override384int compare(Object a, int aFromIndex, int aToIndex,385Object b, int bFromIndex, int bToIndex) {386try {387return (int) cmpcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);388}389catch (RuntimeException | Error e) {390throw e;391}392catch (Throwable t) {393throw new Error(t);394}395}396397@Override398int mismatch(Object a, Object b) {399try {400return (int) mismatchc.invoke(a, b, c);401}402catch (RuntimeException | Error e) {403throw e;404}405catch (Throwable t) {406throw new Error(t);407}408}409410@Override411int mismatch(Object a, int aFromIndex, int aToIndex,412Object b, int bFromIndex, int bToIndex) {413try {414return (int) mismatchcr.invoke(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex, c);415}416catch (RuntimeException | Error e) {417throw e;418}419catch (Throwable t) {420throw new Error(t);421}422}423424@Override425public String toString() {426return arrayType.getCanonicalName() + " with Comparator";427}428}429430static class Booleans extends ArrayType<boolean[]> {431public Booleans() {432super(boolean[].class);433}434435@Override436void set(Object a, int i, Object v) {437boolean pv;438if (v instanceof Boolean) {439pv = (Boolean) v;440}441else if (v instanceof Integer) {442pv = ((Integer) v) >= 0;443}444else throw new IllegalStateException();445446((boolean[]) a)[i] = pv;447}448}449450static class Bytes extends ArrayType<byte[]> {451public Bytes(boolean unsigned) {452super(byte[].class, unsigned);453}454455@Override456void set(Object a, int i, Object v) {457byte pv;458if (v instanceof Byte) {459pv = (Byte) v;460}461else if (v instanceof Integer) {462pv = ((Integer) v).byteValue();463}464else throw new IllegalStateException();465466((byte[]) a)[i] = pv;467}468}469470static class Characters extends ArrayType<char[]> {471public Characters() {472super(char[].class);473}474475@Override476void set(Object a, int i, Object v) {477char pv;478if (v instanceof Character) {479pv = (Character) v;480}481else if (v instanceof Integer) {482pv = (char) ((Integer) v).intValue();483}484else throw new IllegalStateException();485486((char[]) a)[i] = pv;487}488}489490static class Shorts extends ArrayType<short[]> {491public Shorts(boolean unsigned) {492super(short[].class, unsigned);493}494495@Override496void set(Object a, int i, Object v) {497short pv;498if (v instanceof Short) {499pv = (Short) v;500}501else if (v instanceof Integer) {502pv = ((Integer) v).shortValue();503}504else throw new IllegalStateException();505506((short[]) a)[i] = pv;507}508}509510static class Integers extends ArrayType<int[]> {511public Integers(boolean unsigned) {512super(int[].class, unsigned);513}514515@Override516void set(Object a, int i, Object v) {517int pv;518if (v instanceof Integer) {519pv = ((Integer) v).shortValue();520}521else throw new IllegalStateException();522523((int[]) a)[i] = pv;524}525}526527static class Longs extends ArrayType<long[]> {528public Longs(boolean unsigned) {529super(long[].class, unsigned);530}531532@Override533void set(Object a, int i, Object v) {534long pv;535if (v instanceof Long) {536pv = (Long) v;537}538else if (v instanceof Integer) {539pv = ((Integer) v).longValue();540}541else throw new IllegalStateException();542543((long[]) a)[i] = pv;544}545}546547static class Floats extends ArrayType<float[]> {548public Floats() {549super(float[].class);550}551552@Override553void set(Object a, int i, Object v) {554float pv;555if (v instanceof Float) {556pv = (Float) v;557}558else if (v instanceof Integer) {559pv = ((Integer) v).floatValue();560}561else throw new IllegalStateException();562563((float[]) a)[i] = pv;564}565}566567static class Doubles extends ArrayType<double[]> {568public Doubles() {569super(double[].class);570}571572@Override573void set(Object a, int i, Object v) {574double pv;575if (v instanceof Double) {576pv = (Double) v;577}578else if (v instanceof Integer) {579pv = ((Integer) v).doubleValue();580}581else throw new IllegalStateException();582583((double[]) a)[i] = pv;584}585}586}587588static Object[][] arrayTypes;589590@DataProvider591public static Object[][] arrayTypesProvider() {592if (arrayTypes == null) {593arrayTypes = new Object[][]{594new Object[]{new ArrayType.BoxedIntegers()},595new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},596new Object[]{new ArrayType.Booleans()},597new Object[]{new ArrayType.Bytes(false)},598new Object[]{new ArrayType.Bytes(true)},599new Object[]{new ArrayType.Characters()},600new Object[]{new ArrayType.Shorts(false)},601new Object[]{new ArrayType.Shorts(true)},602new Object[]{new ArrayType.Integers(false)},603new Object[]{new ArrayType.Integers(true)},604new Object[]{new ArrayType.Longs(false)},605new Object[]{new ArrayType.Longs(true)},606new Object[]{new ArrayType.Floats()},607new Object[]{new ArrayType.Doubles()},608};609}610return arrayTypes;611}612613static Object[][] floatArrayTypes;614615@DataProvider616public static Object[][] floatArrayTypesProvider() {617if (floatArrayTypes == null) {618LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);619LongFunction<Object> bToD = Double::longBitsToDouble;620621floatArrayTypes = new Object[][]{622new Object[]{new ArrayType.Floats(), 0x7fc00000L, 0x7f800001L, bTof},623new Object[]{new ArrayType.Doubles(), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},624};625}626return floatArrayTypes;627}628629static Object[][] objectArrayTypes;630631@DataProvider632public static Object[][] objectArrayTypesProvider() {633if (objectArrayTypes == null) {634LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);635LongFunction<Object> bToD = Double::longBitsToDouble;636637objectArrayTypes = new Object[][]{638new Object[]{new ArrayType.BoxedIntegers()},639new Object[]{new ArrayType.BoxedIntegersWithReverseComparator()},640};641}642return objectArrayTypes;643}644645646static Object[][] signedUnsignedArrayTypes;647648@DataProvider649public static Object[][] signedUnsignedArrayTypes() {650if (signedUnsignedArrayTypes == null) {651signedUnsignedArrayTypes = new Object[][]{652new Object[]{new ArrayType.Bytes(false), new ArrayType.Bytes(true)},653new Object[]{new ArrayType.Shorts(false), new ArrayType.Shorts(true)},654new Object[]{new ArrayType.Integers(false), new ArrayType.Integers(true)},655new Object[]{new ArrayType.Longs(false), new ArrayType.Longs(true)},656};657}658return signedUnsignedArrayTypes;659}660661// Equality and comparison tests662663@Test(dataProvider = "arrayTypesProvider")664public void testArray(ArrayType<?> arrayType) {665BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {666Object a = at.construct(s);667for (int x = 0; x < s; x++) {668at.set(a, x, x % 8);669}670return a;671};672673BiFunction<ArrayType<?>, Object, Object> cloner = (at, a) ->674constructor.apply(at, Array.getLength(a));675676testArrayType(arrayType, constructor, cloner);677}678679@Test(dataProvider = "floatArrayTypesProvider")680public void testPrimitiveFloatArray(681ArrayType<?> arrayType,682long canonicalNanRawBits, long nonCanonicalNanRawBits,683LongFunction<Object> bitsToFloat) {684Object canonicalNan = bitsToFloat.apply(canonicalNanRawBits);685// If conversion is a signalling NaN it may be subject to conversion to a686// quiet NaN on some processors, even if a copy is performed687// The tests assume that if conversion occurs it does not convert to the688// canonical NaN689Object nonCanonicalNan = bitsToFloat.apply(nonCanonicalNanRawBits);690691BiFunction<ArrayType<?>, Integer, Object> canonicalNaNs = (at, s) -> {692Object a = at.construct(s);693for (int x = 0; x < s; x++) {694at.set(a, x, canonicalNan);695}696return a;697};698699BiFunction<ArrayType<?>, Object, Object> nonCanonicalNaNs = (at, a) -> {700int s = Array.getLength(a);701Object ac = at.construct(s);702for (int x = 0; x < s; x++) {703at.set(ac, x, nonCanonicalNan);704}705return ac;706};707708BiFunction<ArrayType<?>, Object, Object> halfNonCanonicalNaNs = (at, a) -> {709int s = Array.getLength(a);710Object ac = at.construct(s);711for (int x = 0; x < s / 2; x++) {712at.set(ac, x, nonCanonicalNan);713}714for (int x = s / 2; x < s; x++) {715at.set(ac, x, 1);716}717return ac;718};719720testArrayType(arrayType, canonicalNaNs, nonCanonicalNaNs);721testArrayType(arrayType, canonicalNaNs, halfNonCanonicalNaNs);722}723724@Test(dataProvider = "objectArrayTypesProvider")725public void testNullElementsInObjectArray(ArrayType<?> arrayType) {726BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;727728// All nulls729testArrayType(arrayType,730(at, s) -> {731Object a = at.construct(s);732for (int x = 0; x < s; x++) {733at.set(a, x, null);734}735return a;736},737cloner);738739740// Some nulls741testArrayType(arrayType,742(at, s) -> {743Object a = at.construct(s);744for (int x = 0; x < s; x++) {745int v = x % 8;746at.set(a, x, v == 0 ? null : v);747}748return a;749},750cloner);751752Integer[] a = new Integer[]{null, 0};753Integer[] b = new Integer[]{0, 0};754Assert.assertTrue(Arrays.compare(a, b) < 0);755Assert.assertTrue(Arrays.compare(b, a) > 0);756}757758@Test(dataProvider = "objectArrayTypesProvider")759public void testSameRefElementsInObjectArray(ArrayType<?> arrayType) {760BiFunction<ArrayType<?>, Object, Object> cloner = ArrayType::copyOf;761762// One ref763Integer one = 1;764testArrayType(arrayType,765(at, s) -> {766Integer[] a = (Integer[]) at.construct(s);767for (int x = 0; x < s; x++) {768a[x] = one;769}770return a;771},772cloner);773774// All ref775testArrayType(arrayType,776(at, s) -> {777Integer[] a = (Integer[]) at.construct(s);778for (int x = 0; x < s; x++) {779a[x] = Integer.valueOf(s);780}781return a;782},783cloner);784785// Some same ref786testArrayType(arrayType,787(at, s) -> {788Integer[] a = (Integer[]) at.construct(s);789for (int x = 0; x < s; x++) {790int v = x % 8;791a[x] = v == 1 ? one : new Integer(v);792}793return a;794},795cloner);796}797798@Test(dataProvider = "signedUnsignedArrayTypes")799public void testSignedUnsignedArray(ArrayType<?> sat, ArrayType<?> uat) {800BiFunction<ArrayType<?>, Integer, Object> constructor = (at, s) -> {801Object a = at.construct(s);802for (int x = 0; x < s; x++) {803at.set(a, x, 1);804}805return a;806};807808int n = arraySizeFor(sat.componentType);809810for (int s : ranges(0, n)) {811Object a = constructor.apply(sat, s);812813for (int aFrom : ranges(0, s)) {814for (int aTo : ranges(aFrom, s)) {815int aLength = aTo - aFrom;816817if (aLength > 0) {818for (int i = aFrom; i < aTo; i++) {819Object ac = sat.copyOf(a);820// Create common prefix with a length of i - aFrom821sat.set(ac, i, -1);822823int sc = sat.compare(ac, aFrom, aTo, a, aFrom, aTo);824int uc = uat.compare(ac, aFrom, aTo, a, aFrom, aTo);825826Assert.assertTrue(sc < 0);827Assert.assertTrue(uc > 0);828}829}830}831}832}833}834835void testArrayType(ArrayType<?> at,836BiFunction<ArrayType<?>, Integer, Object> constructor,837BiFunction<ArrayType<?>, Object, Object> cloner) {838int n = arraySizeFor(at.componentType);839840for (int s : ranges(0, n)) {841Object a = constructor.apply(at, s);842Object b = cloner.apply(at, a);843844for (int aFrom : ranges(0, s)) {845for (int aTo : ranges(aFrom, s)) {846int aLength = aTo - aFrom;847848for (int bFrom : ranges(0, s)) {849for (int bTo : ranges(bFrom, s)) {850int bLength = bTo - bFrom;851852Object anr = at.copyOf(a, aFrom, aTo);853Object bnr = at.copyOf(b, bFrom, bTo);854855boolean eq = isEqual(at, a, aFrom, aTo, b, bFrom, bTo);856Assert.assertEquals(at.equals(a, aFrom, aTo, b, bFrom, bTo), eq);857Assert.assertEquals(at.equals(b, bFrom, bTo, a, aFrom, aTo), eq);858Assert.assertEquals(at.equals(anr, bnr), eq);859Assert.assertEquals(at.equals(bnr, anr), eq);860if (eq) {861Assert.assertEquals(at.compare(a, aFrom, aTo, b, bFrom, bTo), 0);862Assert.assertEquals(at.compare(b, bFrom, bTo, a, aFrom, aTo), 0);863Assert.assertEquals(at.compare(anr, bnr), 0);864Assert.assertEquals(at.compare(bnr, anr), 0);865866Assert.assertEquals(at.mismatch(a, aFrom, aTo, b, bFrom, bTo), -1);867Assert.assertEquals(at.mismatch(b, bFrom, bTo, a, aFrom, aTo), -1);868Assert.assertEquals(at.mismatch(anr, bnr), -1);869Assert.assertEquals(at.mismatch(bnr, anr), -1);870}871else {872int aCb = at.compare(a, aFrom, aTo, b, bFrom, bTo);873int bCa = at.compare(b, bFrom, bTo, a, aFrom, aTo);874int v = Integer.signum(aCb) * Integer.signum(bCa);875Assert.assertTrue(v == -1);876877int anrCbnr = at.compare(anr, bnr);878int bnrCanr = at.compare(bnr, anr);879Assert.assertEquals(anrCbnr, aCb);880Assert.assertEquals(bnrCanr, bCa);881882883int aMb = at.mismatch(a, aFrom, aTo, b, bFrom, bTo);884int bMa = at.mismatch(b, bFrom, bTo, a, aFrom, aTo);885int anrMbnr = at.mismatch(anr, bnr);886int bnrManr = at.mismatch(bnr, anr);887888Assert.assertNotEquals(aMb, -1);889Assert.assertEquals(aMb, bMa);890Assert.assertNotEquals(anrMbnr, -1);891Assert.assertEquals(anrMbnr, bnrManr);892Assert.assertEquals(aMb, anrMbnr);893Assert.assertEquals(bMa, bnrManr);894895// Common or proper prefix896Assert.assertTrue(at.equals(a, aFrom, aFrom + aMb, b, bFrom, bFrom + aMb));897if (aMb < Math.min(aLength, bLength)) {898// Common prefix899Assert.assertFalse(isEqual(at, a, aFrom + aMb, b, bFrom + aMb));900}901}902}903}904905if (aLength > 0) {906for (int i = aFrom; i < aTo; i++) {907Object ac = at.copyOf(a);908// Create common prefix with a length of i - aFrom909at.set(ac, i, -1);910911Object acnr = at.copyOf(ac, aFrom, aTo);912Object anr = at.copyOf(a, aFrom, aTo);913914Assert.assertFalse(at.equals(ac, aFrom, aTo, a, aFrom, aTo));915Assert.assertFalse(at.equals(acnr, anr));916917int acCa = at.compare(ac, aFrom, aTo, a, aFrom, aTo);918int aCac = at.compare(a, aFrom, aTo, ac, aFrom, aTo);919int v = Integer.signum(acCa) * Integer.signum(aCac);920Assert.assertTrue(v == -1);921922int acnrCanr = at.compare(acnr, anr);923int anrCacnr = at.compare(anr, acnr);924Assert.assertEquals(acnrCanr, acCa);925Assert.assertEquals(anrCacnr, aCac);926927928int acMa = at.mismatch(ac, aFrom, aTo, a, aFrom, aTo);929int aMac = at.mismatch(a, aFrom, aTo, ac, aFrom, aTo);930Assert.assertEquals(acMa, aMac);931Assert.assertEquals(acMa, i - aFrom);932933int acnrManr = at.mismatch(acnr, anr);934int anrMacnr = at.mismatch(anr, acnr);935Assert.assertEquals(acnrManr, anrMacnr);936Assert.assertEquals(acnrManr, i - aFrom);937}938}939}940}941}942}943944static boolean isEqual(ArrayType<?> at, Object a, int aFromIndex, int aToIndex,945Object b, int bFromIndex, int bToIndex) {946int aLength = aToIndex - aFromIndex;947int bLength = bToIndex - bFromIndex;948if (aLength != bLength)949return false;950951for (int i = 0; i < aLength; i++) {952Object av = at.get(a, aFromIndex++);953Object bv = at.get(b, bFromIndex++);954if (!Objects.equals(av, bv)) return false;955}956957return true;958}959960static boolean isEqual(ArrayType<?> at, Object a, int aFrom, Object b, int bFrom) {961Object av = at.get(a, aFrom);962Object bv = at.get(b, bFrom);963964return Objects.equals(av, bv);965}966967static int[] ranges(int from, int to) {968int width = to - from;969switch (width) {970case 0:971return new int[]{};972case 1:973return new int[]{from, to};974case 2:975return new int[]{from, from + 1, to};976case 3:977return new int[]{from, from + 1, from + 2, to};978default:979return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)980.filter(i -> i >= from && i <= to)981.distinct().toArray();982}983}984985986// Null array reference tests987988@Test(dataProvider = "arrayTypesProvider")989public void testNullArrayRefs(ArrayType<?> arrayType) {990Object n = null;991Object a = arrayType.construct(0);992993Assert.assertTrue(arrayType.equals(n, n));994Assert.assertFalse(arrayType.equals(n, a));995Assert.assertFalse(arrayType.equals(a, n));996997Assert.assertEquals(arrayType.compare(n, n), 0);998Assert.assertTrue(arrayType.compare(n, a) < 0);999Assert.assertTrue(arrayType.compare(a, n) > 0);1000}100110021003// Exception throwing tests10041005@Test(dataProvider = "arrayTypesProvider")1006public void testNPEs(ArrayType<?> arrayType) {1007Object[] values = new Object[]{null, arrayType.construct(0)};10081009for (Object o1 : values) {1010for (Object o2 : values) {1011if (o1 != null && o2 != null)1012continue;10131014testNPE(() -> arrayType.equals(o1, 0, 0, o2, 0, 0));1015testNPE(() -> arrayType.compare(o1, 0, 0, o2, 0, 0));1016testNPE(() -> arrayType.mismatch(o1, o2));1017testNPE(() -> arrayType.mismatch(o1, 0, 0, o2, 0, 0));1018}1019}1020}10211022@Test1023public void testObjectNPEs() {1024String[][] values = new String[][]{null, new String[0]};1025Comparator<String> c = String::compareTo;1026Comparator[] cs = new Comparator[]{null, c};10271028for (String[] o1 : values) {1029for (String[] o2 : values) {1030for (Comparator o3 : cs) {1031if (o1 != null && o2 != null && o3 != null)1032continue;10331034if (o3 == null) {1035testNPE(() -> Arrays.equals(o1, o2, o3));1036testNPE(() -> Arrays.compare(o1, o2, o3));1037testNPE(() -> Arrays.mismatch(o1, o2, o3));1038}10391040testNPE(() -> Arrays.equals(o1, 0, 0, o2, 0, 0, o3));1041testNPE(() -> Arrays.compare(o1, 0, 0, o2, 0, 0, o3));1042testNPE(() -> Arrays.mismatch(o1, 0, 0, o2, 0, 0, o3));1043}1044}1045}1046}10471048@Test(dataProvider = "arrayTypesProvider")1049public void testIAEs(ArrayType<?> arrayType) {1050List<Integer> values = Arrays.asList(0, 1);10511052for (int s : values) {1053Object a = arrayType.construct(s);10541055for (int o1 : values) {1056for (int o2 : values) {1057if (o1 <= o2) continue;10581059testIAE(() -> arrayType.equals(a, o1, 0, a, o2, 0));1060testIAE(() -> arrayType.compare(a, o1, 0, a, o2, 0));1061testIAE(() -> arrayType.mismatch(a, o1, 0, a, o2, 0));1062}1063}1064}1065}10661067@Test(dataProvider = "arrayTypesProvider")1068public void testAIOBEs(ArrayType<?> arrayType) {1069List<Integer> froms = Arrays.asList(-1, 0);10701071for (int s : Arrays.asList(0, 1)) {1072List<Integer> tos = Arrays.asList(s, s + 1);1073Object a = arrayType.construct(s);10741075for (int aFrom : froms) {1076for (int aTo : tos) {1077for (int bFrom : froms) {1078for (int bTo : tos) {1079if (aFrom >= 0 && aTo <= s &&1080bFrom >= 0 && bTo <= s) continue;10811082testAIOBE(() -> arrayType.equals(a, aFrom, aTo, a, bFrom, bTo));1083testAIOBE(() -> arrayType.compare(a, aFrom, aTo, a, bFrom, bTo));1084testAIOBE(() -> arrayType.mismatch(a, aFrom, aTo, a, bFrom, bTo));1085}1086}1087}1088}1089}1090}10911092static void testNPE(Runnable r) {1093testThrowable(r, NullPointerException.class);1094}10951096static void testIAE(Runnable r) {1097testThrowable(r, IllegalArgumentException.class);1098}10991100static void testAIOBE(Runnable r) {1101testThrowable(r, ArrayIndexOutOfBoundsException.class);1102}11031104static void testThrowable(Runnable r, Class<? extends Throwable> expected) {1105Throwable caught = null;1106try {1107r.run();1108}1109catch (Throwable t) {1110caught = t;1111}1112Assert.assertNotNull(caught);1113Assert.assertTrue(expected.isInstance(caught));1114}1115}11161117