Path: blob/master/test/jdk/java/util/Arrays/CopyMethods.java
41149 views
/*1* Copyright (c) 2005, 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 465550326* @summary Test for array cloning and slicing methods.27* @author John Rose28* @key randomness29*/3031import java.util.*;32import java.lang.reflect.*;3334public class CopyMethods {35static int muzzle; // if !=0, suppresses ("muzzles") messages3637static int maxLen = 40; // maximum length of test arrays38static int shortStepsNear = 4; // interesting span near critical values39static int downShift = 3;4041static int testCasesRun = 0;42static long consing = 0;4344// very simple tests, mainly to test the framework itself45static void simpleTests() {46int[] a = (int[]) makeArray(3, int.class);47if (muzzle == 0)48System.out.println("int[] a = "+Arrays.toString(a));49check(a.length == 3);50check(a[0] == testValues[0]);51check(a[1] == testValues[1]);52check(a[2] == testValues[2]);53checkArray(a, int.class, 3, 0, 3);54// negative test of testing framework:55for (int bad = -2; bad < a.length; bad++) {56try {57int[] aa = a.clone();58if (bad < 0) aa = new int[4];59else aa[bad] = 0;60++muzzle;61// the following check should fail!62if (bad == -2)63checkArray(new String[3], int.class, 0, 0, a.length);64else65checkArray(aa, int.class, 0, 0, a.length);66throw new Error("Should Not Reach Here");67} catch (RuntimeException ee) {68--muzzle;69if (muzzle == 0)70System.out.println("Expected: "+ee);71}72}73checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3);74checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3);75checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3);76checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3);77checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3);7879// quick test of copyOfRange80int[] ar = Arrays.copyOfRange(a, 1, 3);81check(ar.length == 2);82check(ar[0] == a[1]);83check(ar[1] == a[2]);84checkArray(ar, int.class, 2, 1, 2);85ar = Arrays.copyOfRange(a, 2, 4);86check(ar.length == 2);87check(ar[0] == a[2]);88check(ar[1] == 0);89checkArray(ar, int.class, 2, 2, 1);90ar = Arrays.copyOfRange(a, 3, 5);91check(ar.length == 2);92check(ar[0] == 0);93check(ar[1] == 0);94checkArray(ar, int.class, 2, 3, 0);95byte[] ba = (byte[]) makeArray(3, byte.class);96if (muzzle == 0)97System.out.println("byte[] ba = "+Arrays.toString(ba));98for (int j = 0; j <= ba.length+2; j++) {99byte[] bb = Arrays.copyOf(ba, j);100if (muzzle == 0)101System.out.println("copyOf(ba,"+j+") = "+102Arrays.toString(bb));103checkArray(bb, byte.class, j, 0, ba.length);104byte[] bbr = Arrays.copyOfRange(ba, 0, j);105check(Arrays.equals(bb, bbr));106}107for (int i = 0; i <= a.length; i++) {108for (int j = i; j <= a.length+2; j++) {109byte[] br = Arrays.copyOfRange(ba, i, j);110if (muzzle == 0)111System.out.println("copyOfRange(ba,"+i+","+j+") = "+112Arrays.toString(br));113checkArray(br, byte.class, j-i, i, ba.length-i);114}115}116String[] sa = (String[]) makeArray(3, String.class);117if (muzzle == 0)118System.out.println("String[] sa = "+Arrays.toString(sa));119check(sa[0].equals(Integer.toHexString(testValues[0])));120check(sa[1].equals(Integer.toHexString(testValues[1])));121check(sa[2].equals(Integer.toHexString(testValues[2])));122checkArray(sa, String.class, sa.length, 0, sa.length);123String[] sa4 = Arrays.copyOf(sa, sa.length+1);124check(sa4[0] == sa[0]);125check(sa4[1] == sa[1]);126check(sa4[2] == sa[2]);127check(sa4[sa.length] == null);128checkArray(sa4, String.class, sa4.length, 0, sa.length);129String[] sr4 = Arrays.copyOfRange(sa, 1, 5);130check(sr4[0] == sa[1]);131check(sr4[1] == sa[2]);132check(sr4[2] == null);133check(sr4[3] == null);134checkArray(sr4, String.class, 4, 1, sa.length-1);135if (muzzle == 0)136System.out.println("simpleTests done");137}138139// the framework: a fixed series of test values140static final int[] testValues;141static {142testValues = new int[1000];143Random r = new Random();144for (int i = 0; i < testValues.length; i++) {145testValues[i] = r.nextInt();146}147}148/** Return a canonical test value of a desired index and type.149* The original test values are random ints. Derive other test150* values as follows:151* <pre>152* int tv = testValues[i]153* (C)tv C is byte, short, char, long, float, double154* (tv&1)!=0 C is boolean155* (Integer)tv C is Object and tv%16 != 0156* null C is Object and tv%16 == 0157* Integer.toHexString(tv) C is String and tv != 0158* null C is String and tv == 0159* </pre>160* are derived by ordinary Java coercions, except that boolean161* samples the LSB of the int value, and String is the hex numeral.162*163* (Also, the 0th String is null, and the 0th Object mod 16 is null,164* regardless of the original int test value.)165*/166static Object testValue(int i, Class<?> c) {167int tv = testValues[i % testValues.length];168if (i >= testValues.length) tv ^= i;169// Turn the canonical int to a float, boolean, String, whatever:170return invoke(coercers.get(c), tv);171}172/** Build a test array of the given length,173* packed with a subsequence of the test values.174* The first element of the array is always testValue(0).175*/176static Object makeArray(int len, Class<?> c) {177Object a = Array.newInstance(c, len);178for (int i = 0; i < len; i++) {179Array.set(a, i, testValue(i, c));180}181return a;182}183/** Check that the given array has the required length.184* Check also that it is packed, up to firstNull, with185* a particular subsequence of the canonical test values.186* The subsequence must begin with a[0] == testValue(offset).187* At a[firstNull] and beyond, the array must contain null values.188*/189static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) {190check(c == a.getClass().getComponentType());191Object nullValue = nullValues.get(c);192// Note: asserts in here are not part of the test program.193// They verify the integrity of the test method itself.194assert(nullValues.containsKey(c));195196int misses = 0;197int firstMiss = -1;198// Check required length first.199int length = Array.getLength(a);200if (length != requiredLen && requiredLen != -1) {201if (muzzle == 0)202System.out.println("*** a.length = "+length+" != "+requiredLen);203++misses;204}205206for (int i = 0; i < length; i++) {207Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c);208Object ai = Array.get(a, i);209if (!eq(ai, tv)) {210if (muzzle == 0)211System.out.println("*** a["+i+"] = "+ai+" != "+tv);212if (misses == 0) firstMiss = i;213if (++misses > 10) break;214}215}216if (misses != 0) {217Method toString = toStrings.get(c);218if (toString == null) toString = toStrings.get(Object.class);219throw new RuntimeException("checkArray failed at "+firstMiss220+" "+c+"[]"221+" : "+invoke(toString, a));222}223}224// Typical comparison helper. Why isn't this a method somewhere.225static boolean eq(Object x, Object y) {226return x == null? y == null: x.equals(y);227}228// Exception-ignoring invoke function.229static Object invoke(Method m, Object... args) {230Exception ex;231try {232return m.invoke(null, args);233} catch (InvocationTargetException ee) {234ex = ee;235} catch (IllegalAccessException ee) {236ex = ee;237} catch (IllegalArgumentException ee) {238ex = ee;239}240ArrayList<Object> call = new ArrayList<Object>();241call.add(m); Collections.addAll(call, args);242throw new RuntimeException(call+" : "+ex);243}244// version of assert() that runs unconditionally245static void check(boolean z) {246if (!z) throw new RuntimeException("check failed");247}248249250/** Run about 10**5 distinct parameter combinations251* on copyOf and copyOfRange. Use all primitive types,252* and String and Object.253* Try to all critical values, looking for fencepost errors.254*/255static void fullTests(int maxLen, Class<?> c) {256Method cloner = cloners.get(c);257assert(cloner != null) : c;258Method cloneRanger = cloneRangers.get(c);259// Note: asserts in here are not part of the test program.260// They verify the integrity of the test method itself.261assert(cloneRanger != null) : c;262for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) {263Object a = makeArray(src, c);264for (int x : new ArrayList<Integer>()) {}265for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) {266// b = Arrays.copyOf(a, j);267Object b = invoke(cloner, a, j);268checkArray(b, c, j, 0, src);269testCasesRun++;270consing += j;271272int maxI = Math.min(src, j);273for (int i = 0; i <= maxI; i = inc(i, src, maxI)) {274// r = Arrays.copyOfRange(a, i, j);275Object r = invoke(cloneRanger, a, i, j);276checkArray(r, c, j-i, i, src-i);277//System.out.println("case c="+c+" src="+src+" i="+i+" j="+j);278testCasesRun++;279consing += j-i;280}281}282}283}284// Increment x by at least one. Increment by a little more unless285// it is near a critical value, either zero, crit1, or crit2.286static int inc(int x, int crit1, int crit2) {287int D = shortStepsNear;288if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; }289assert(crit1 <= crit2);290assert(x <= crit2); // next1 or next2 must be the limit value291x += 1;292if (x > D) {293if (x < crit1-D) {294x += (x << 1) >> downShift; // giant step toward crit1-D295if (x > crit1-D) x = crit1-D;296} else if (x >= crit1+D && x < crit2-D) {297x += (x << 1) >> downShift; // giant step toward crit2-D298if (x > crit2-D) x = crit2-D;299}300}301return x;302}303304public static void main(String[] av) {305boolean verbose = (av.length != 0);306muzzle = (verbose? 0: 1);307if (muzzle == 0)308System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"...");309310simpleTests();311312muzzle = 0; // turn on print statements (affects failures only)313314fullTests();315if (verbose)316System.out.println("ran "+testCasesRun+" tests, avg len="317+(float)consing/testCasesRun);318319// test much larger arrays, more sparsely320maxLen = 500;321shortStepsNear = 2;322downShift = 0;323testCasesRun = 0;324consing = 0;325fullTests();326if (verbose)327System.out.println("ran "+testCasesRun+" tests, avg len="328+(float)consing/testCasesRun);329}330331static void fullTests() {332for (Class<?> c : allTypes) {333fullTests(maxLen, c);334}335}336337// We must run all the our tests on each of 8 distinct primitive types,338// and two reference types (Object, String) for good measure.339// This would be a pain to write out by hand, statically typed.340// So, use reflection. Following are the tables of methods we use.341// (The initial simple tests exercise enough of the static typing342// features of the API to ensure that they compile as advertised.)343344static Object coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); }345static String coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); }346static Integer coerceToInteger(int x) { return (x == 0)? null: x; }347static byte coerceToByte(int x) { return (byte)x; }348static short coerceToShort(int x) { return (short)x; }349static int coerceToInt(int x) { return x; }350static long coerceToLong(int x) { return x; }351static char coerceToChar(int x) { return (char)x; }352static float coerceToFloat(int x) { return x; }353static double coerceToDouble(int x) { return x; }354static boolean coerceToBoolean(int x) { return (x&1) != 0; }355356static Integer[] copyOfIntegerArray(Object[] a, int len) {357// This guy exercises the API based on a type-token.358// Note the static typing.359return Arrays.copyOf(a, len, Integer[].class);360}361static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) {362// This guy exercises the API based on a type-token.363// Note the static typing.364return Arrays.copyOfRange(a, m, n, Integer[].class);365}366367static final List<Class<?>> allTypes368= Arrays.asList(new Class<?>[]369{ Object.class, String.class, Integer.class,370byte.class, short.class, int.class, long.class,371char.class, float.class, double.class,372boolean.class373});374static final HashMap<Class<?>,Method> coercers;375static final HashMap<Class<?>,Method> cloners;376static final HashMap<Class<?>,Method> cloneRangers;377static final HashMap<Class<?>,Method> toStrings;378static final HashMap<Class<?>,Object> nullValues;379static {380coercers = new HashMap<Class<?>,Method>();381Method[] testMethods = CopyMethods.class.getDeclaredMethods();382Method cia = null, ciar = null;383for (int i = 0; i < testMethods.length; i++) {384Method m = testMethods[i];385if (!Modifier.isStatic(m.getModifiers())) continue;386Class<?> rt = m.getReturnType();387if (m.getName().startsWith("coerceTo") && allTypes.contains(rt))388coercers.put(m.getReturnType(), m);389if (m.getName().equals("copyOfIntegerArray"))390cia = m;391if (m.getName().equals("copyOfIntegerArrayRange"))392ciar = m;393}394Method[] arrayMethods = Arrays.class.getDeclaredMethods();395cloners = new HashMap<Class<?>,Method>();396cloneRangers = new HashMap<Class<?>,Method>();397toStrings = new HashMap<Class<?>,Method>();398for (int i = 0; i < arrayMethods.length; i++) {399Method m = arrayMethods[i];400if (!Modifier.isStatic(m.getModifiers())) continue;401Class<?> rt = m.getReturnType();402if (m.getName().equals("copyOf")403&& m.getParameterTypes().length == 2)404cloners.put(rt.getComponentType(), m);405if (m.getName().equals("copyOfRange")406&& m.getParameterTypes().length == 3)407cloneRangers.put(rt.getComponentType(), m);408if (m.getName().equals("toString")) {409Class<?> pt = m.getParameterTypes()[0];410toStrings.put(pt.getComponentType(), m);411}412}413cloners.put(String.class, cloners.get(Object.class));414cloneRangers.put(String.class, cloneRangers.get(Object.class));415assert(cia != null);416cloners.put(Integer.class, cia);417assert(ciar != null);418cloneRangers.put(Integer.class, ciar);419nullValues = new HashMap<Class<?>,Object>();420for (Class<?> c : allTypes) {421nullValues.put(c, invoke(coercers.get(c), 0));422}423}424}425426427