0N/A/*
2362N/A * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 4655503
0N/A * @summary Test for array cloning and slicing methods.
0N/A * @author John Rose
0N/A */
0N/A
0N/Aimport java.util.*;
0N/Aimport java.lang.reflect.*;
0N/A
0N/Apublic class CopyMethods {
0N/A static int muzzle; // if !=0, suppresses ("muzzles") messages
0N/A
0N/A static int maxLen = 40; // maximum length of test arrays
0N/A static int shortStepsNear = 4; // interesting span near critical values
0N/A static int downShift = 3;
0N/A
0N/A static int testCasesRun = 0;
0N/A static long consing = 0;
0N/A
0N/A // very simple tests, mainly to test the framework itself
0N/A static void simpleTests() {
0N/A int[] a = (int[]) makeArray(3, int.class);
0N/A if (muzzle == 0)
0N/A System.out.println("int[] a = "+Arrays.toString(a));
0N/A check(a.length == 3);
0N/A check(a[0] == testValues[0]);
0N/A check(a[1] == testValues[1]);
0N/A check(a[2] == testValues[2]);
0N/A checkArray(a, int.class, 3, 0, 3);
0N/A // negative test of testing framework:
0N/A for (int bad = -2; bad < a.length; bad++) {
0N/A try {
0N/A int[] aa = a.clone();
0N/A if (bad < 0) aa = new int[4];
0N/A else aa[bad] = 0;
0N/A ++muzzle;
0N/A // the following check should fail!
0N/A if (bad == -2)
0N/A checkArray(new String[3], int.class, 0, 0, a.length);
0N/A else
0N/A checkArray(aa, int.class, 0, 0, a.length);
0N/A throw new Error("Should Not Reach Here");
0N/A } catch (RuntimeException ee) {
0N/A --muzzle;
0N/A if (muzzle == 0)
0N/A System.out.println("Expected: "+ee);
0N/A }
0N/A }
0N/A checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3);
0N/A checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3);
0N/A checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3);
0N/A checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3);
0N/A checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3);
0N/A
0N/A // quick test of copyOfRange
0N/A int[] ar = Arrays.copyOfRange(a, 1, 3);
0N/A check(ar.length == 2);
0N/A check(ar[0] == a[1]);
0N/A check(ar[1] == a[2]);
0N/A checkArray(ar, int.class, 2, 1, 2);
0N/A ar = Arrays.copyOfRange(a, 2, 4);
0N/A check(ar.length == 2);
0N/A check(ar[0] == a[2]);
0N/A check(ar[1] == 0);
0N/A checkArray(ar, int.class, 2, 2, 1);
0N/A ar = Arrays.copyOfRange(a, 3, 5);
0N/A check(ar.length == 2);
0N/A check(ar[0] == 0);
0N/A check(ar[1] == 0);
0N/A checkArray(ar, int.class, 2, 3, 0);
0N/A byte[] ba = (byte[]) makeArray(3, byte.class);
0N/A if (muzzle == 0)
0N/A System.out.println("byte[] ba = "+Arrays.toString(ba));
0N/A for (int j = 0; j <= ba.length+2; j++) {
0N/A byte[] bb = Arrays.copyOf(ba, j);
0N/A if (muzzle == 0)
0N/A System.out.println("copyOf(ba,"+j+") = "+
0N/A Arrays.toString(bb));
0N/A checkArray(bb, byte.class, j, 0, ba.length);
0N/A byte[] bbr = Arrays.copyOfRange(ba, 0, j);
0N/A check(Arrays.equals(bb, bbr));
0N/A }
0N/A for (int i = 0; i <= a.length; i++) {
0N/A for (int j = i; j <= a.length+2; j++) {
0N/A byte[] br = Arrays.copyOfRange(ba, i, j);
0N/A if (muzzle == 0)
0N/A System.out.println("copyOfRange(ba,"+i+","+j+") = "+
0N/A Arrays.toString(br));
0N/A checkArray(br, byte.class, j-i, i, ba.length-i);
0N/A }
0N/A }
0N/A String[] sa = (String[]) makeArray(3, String.class);
0N/A if (muzzle == 0)
0N/A System.out.println("String[] sa = "+Arrays.toString(sa));
0N/A check(sa[0].equals(Integer.toHexString(testValues[0])));
0N/A check(sa[1].equals(Integer.toHexString(testValues[1])));
0N/A check(sa[2].equals(Integer.toHexString(testValues[2])));
0N/A checkArray(sa, String.class, sa.length, 0, sa.length);
0N/A String[] sa4 = Arrays.copyOf(sa, sa.length+1);
0N/A check(sa4[0] == sa[0]);
0N/A check(sa4[1] == sa[1]);
0N/A check(sa4[2] == sa[2]);
0N/A check(sa4[sa.length] == null);
0N/A checkArray(sa4, String.class, sa4.length, 0, sa.length);
0N/A String[] sr4 = Arrays.copyOfRange(sa, 1, 5);
0N/A check(sr4[0] == sa[1]);
0N/A check(sr4[1] == sa[2]);
0N/A check(sr4[2] == null);
0N/A check(sr4[3] == null);
0N/A checkArray(sr4, String.class, 4, 1, sa.length-1);
0N/A if (muzzle == 0)
0N/A System.out.println("simpleTests done");
0N/A }
0N/A
0N/A // the framework: a fixed series of test values
0N/A static final int[] testValues;
0N/A static {
0N/A testValues = new int[1000];
0N/A Random r = new Random();
0N/A for (int i = 0; i < testValues.length; i++) {
0N/A testValues[i] = r.nextInt();
0N/A }
0N/A }
0N/A /** Return a canonical test value of a desired index and type.
0N/A * The original test values are random ints. Derive other test
0N/A * values as follows:
0N/A * <pre>
0N/A * int tv = testValues[i]
0N/A * (C)tv C is byte, short, char, long, float, double
0N/A * (tv&1)!=0 C is boolean
0N/A * (Integer)tv C is Object and tv%16 != 0
0N/A * null C is Object and tv%16 == 0
0N/A * Integer.toHexString(tv) C is String and tv != 0
0N/A * null C is String and tv == 0
0N/A * </pre>
0N/A * are derived by ordinary Java coercions, except that boolean
0N/A * samples the LSB of the int value, and String is the hex numeral.
0N/A *
0N/A * (Also, the 0th String is null, and the 0th Object mod 16 is null,
0N/A * regardless of the original int test value.)
0N/A */
0N/A static Object testValue(int i, Class<?> c) {
0N/A int tv = testValues[i % testValues.length];
0N/A if (i >= testValues.length) tv ^= i;
0N/A // Turn the canonical int to a float, boolean, String, whatever:
0N/A return invoke(coercers.get(c), tv);
0N/A }
0N/A /** Build a test array of the given length,
0N/A * packed with a subsequence of the test values.
0N/A * The first element of the array is always testValue(0).
0N/A */
0N/A static Object makeArray(int len, Class<?> c) {
0N/A Object a = Array.newInstance(c, len);
0N/A for (int i = 0; i < len; i++) {
0N/A Array.set(a, i, testValue(i, c));
0N/A }
0N/A return a;
0N/A }
0N/A /** Check that the given array has the required length.
0N/A * Check also that it is packed, up to firstNull, with
0N/A * a particular subsequence of the canonical test values.
0N/A * The subsequence must begin with a[0] == testValue(offset).
0N/A * At a[firstNull] and beyond, the array must contain null values.
0N/A */
0N/A static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) {
0N/A check(c == a.getClass().getComponentType());
0N/A Object nullValue = nullValues.get(c);
0N/A // Note: asserts in here are not part of the test program.
0N/A // They verify the integrity of the test method itself.
0N/A assert(nullValues.containsKey(c));
0N/A
0N/A int misses = 0;
0N/A int firstMiss = -1;
0N/A // Check required length first.
0N/A int length = Array.getLength(a);
0N/A if (length != requiredLen && requiredLen != -1) {
0N/A if (muzzle == 0)
0N/A System.out.println("*** a.length = "+length+" != "+requiredLen);
0N/A ++misses;
0N/A }
0N/A
0N/A for (int i = 0; i < length; i++) {
0N/A Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c);
0N/A Object ai = Array.get(a, i);
0N/A if (!eq(ai, tv)) {
0N/A if (muzzle == 0)
0N/A System.out.println("*** a["+i+"] = "+ai+" != "+tv);
0N/A if (misses == 0) firstMiss = i;
0N/A if (++misses > 10) break;
0N/A }
0N/A }
0N/A if (misses != 0) {
0N/A Method toString = toStrings.get(c);
0N/A if (toString == null) toString = toStrings.get(Object.class);
0N/A throw new RuntimeException("checkArray failed at "+firstMiss
0N/A +" "+c+"[]"
0N/A +" : "+invoke(toString, a));
0N/A }
0N/A }
0N/A // Typical comparison helper. Why isn't this a method somewhere.
0N/A static boolean eq(Object x, Object y) {
0N/A return x == null? y == null: x.equals(y);
0N/A }
0N/A // Exception-ignoring invoke function.
0N/A static Object invoke(Method m, Object... args) {
0N/A Exception ex;
0N/A try {
0N/A return m.invoke(null, args);
0N/A } catch (InvocationTargetException ee) {
0N/A ex = ee;
0N/A } catch (IllegalAccessException ee) {
0N/A ex = ee;
0N/A } catch (IllegalArgumentException ee) {
0N/A ex = ee;
0N/A }
0N/A ArrayList<Object> call = new ArrayList<Object>();
0N/A call.add(m); Collections.addAll(call, args);
0N/A throw new RuntimeException(call+" : "+ex);
0N/A }
0N/A // version of assert() that runs unconditionally
0N/A static void check(boolean z) {
0N/A if (!z) throw new RuntimeException("check failed");
0N/A }
0N/A
0N/A
0N/A /** Run about 10**5 distinct parameter combinations
0N/A * on copyOf and copyOfRange. Use all primitive types,
0N/A * and String and Object.
0N/A * Try to all critical values, looking for fencepost errors.
0N/A */
0N/A static void fullTests(int maxLen, Class<?> c) {
0N/A Method cloner = cloners.get(c);
0N/A assert(cloner != null) : c;
0N/A Method cloneRanger = cloneRangers.get(c);
0N/A // Note: asserts in here are not part of the test program.
0N/A // They verify the integrity of the test method itself.
0N/A assert(cloneRanger != null) : c;
0N/A for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) {
0N/A Object a = makeArray(src, c);
0N/A for (int x : new ArrayList<Integer>()) {}
0N/A for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) {
0N/A // b = Arrays.copyOf(a, j);
0N/A Object b = invoke(cloner, a, j);
0N/A checkArray(b, c, j, 0, src);
0N/A testCasesRun++;
0N/A consing += j;
0N/A
0N/A int maxI = Math.min(src, j);
0N/A for (int i = 0; i <= maxI; i = inc(i, src, maxI)) {
0N/A // r = Arrays.copyOfRange(a, i, j);
0N/A Object r = invoke(cloneRanger, a, i, j);
0N/A checkArray(r, c, j-i, i, src-i);
0N/A //System.out.println("case c="+c+" src="+src+" i="+i+" j="+j);
0N/A testCasesRun++;
0N/A consing += j-i;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A // Increment x by at least one. Increment by a little more unless
0N/A // it is near a critical value, either zero, crit1, or crit2.
0N/A static int inc(int x, int crit1, int crit2) {
0N/A int D = shortStepsNear;
0N/A if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; }
0N/A assert(crit1 <= crit2);
0N/A assert(x <= crit2); // next1 or next2 must be the limit value
0N/A x += 1;
0N/A if (x > D) {
0N/A if (x < crit1-D) {
0N/A x += (x << 1) >> downShift; // giant step toward crit1-D
0N/A if (x > crit1-D) x = crit1-D;
0N/A } else if (x >= crit1+D && x < crit2-D) {
0N/A x += (x << 1) >> downShift; // giant step toward crit2-D
0N/A if (x > crit2-D) x = crit2-D;
0N/A }
0N/A }
0N/A return x;
0N/A }
0N/A
0N/A public static void main(String[] av) {
0N/A boolean verbose = (av.length != 0);
0N/A muzzle = (verbose? 0: 1);
0N/A if (muzzle == 0)
0N/A System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"...");
0N/A
0N/A simpleTests();
0N/A
0N/A muzzle = 0; // turn on print statements (affects failures only)
0N/A
0N/A fullTests();
0N/A if (verbose)
0N/A System.out.println("ran "+testCasesRun+" tests, avg len="
0N/A +(float)consing/testCasesRun);
0N/A
0N/A // test much larger arrays, more sparsely
0N/A maxLen = 500;
0N/A shortStepsNear = 2;
0N/A downShift = 0;
0N/A testCasesRun = 0;
0N/A consing = 0;
0N/A fullTests();
0N/A if (verbose)
0N/A System.out.println("ran "+testCasesRun+" tests, avg len="
0N/A +(float)consing/testCasesRun);
0N/A }
0N/A
0N/A static void fullTests() {
0N/A for (Class<?> c : allTypes) {
0N/A fullTests(maxLen, c);
0N/A }
0N/A }
0N/A
0N/A // We must run all the our tests on each of 8 distinct primitive types,
0N/A // and two reference types (Object, String) for good measure.
0N/A // This would be a pain to write out by hand, statically typed.
0N/A // So, use reflection. Following are the tables of methods we use.
0N/A // (The initial simple tests exercise enough of the static typing
0N/A // features of the API to ensure that they compile as advertised.)
0N/A
0N/A static Object coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); }
0N/A static String coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); }
0N/A static Integer coerceToInteger(int x) { return (x == 0)? null: x; }
0N/A static byte coerceToByte(int x) { return (byte)x; }
0N/A static short coerceToShort(int x) { return (short)x; }
0N/A static int coerceToInt(int x) { return x; }
0N/A static long coerceToLong(int x) { return x; }
0N/A static char coerceToChar(int x) { return (char)x; }
0N/A static float coerceToFloat(int x) { return x; }
0N/A static double coerceToDouble(int x) { return x; }
0N/A static boolean coerceToBoolean(int x) { return (x&1) != 0; }
0N/A
0N/A static Integer[] copyOfIntegerArray(Object[] a, int len) {
0N/A // This guy exercises the API based on a type-token.
0N/A // Note the static typing.
0N/A return Arrays.copyOf(a, len, Integer[].class);
0N/A }
0N/A static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) {
0N/A // This guy exercises the API based on a type-token.
0N/A // Note the static typing.
0N/A return Arrays.copyOfRange(a, m, n, Integer[].class);
0N/A }
0N/A
0N/A static final List<Class<?>> allTypes
0N/A = Arrays.asList(new Class<?>[]
0N/A { Object.class, String.class, Integer.class,
0N/A byte.class, short.class, int.class, long.class,
0N/A char.class, float.class, double.class,
0N/A boolean.class
0N/A });
0N/A static final HashMap<Class<?>,Method> coercers;
0N/A static final HashMap<Class<?>,Method> cloners;
0N/A static final HashMap<Class<?>,Method> cloneRangers;
0N/A static final HashMap<Class<?>,Method> toStrings;
0N/A static final HashMap<Class<?>,Object> nullValues;
0N/A static {
0N/A coercers = new HashMap<Class<?>,Method>();
0N/A Method[] testMethods = CopyMethods.class.getDeclaredMethods();
0N/A Method cia = null, ciar = null;
0N/A for (int i = 0; i < testMethods.length; i++) {
0N/A Method m = testMethods[i];
0N/A if (!Modifier.isStatic(m.getModifiers())) continue;
0N/A Class<?> rt = m.getReturnType();
0N/A if (m.getName().startsWith("coerceTo") && allTypes.contains(rt))
0N/A coercers.put(m.getReturnType(), m);
0N/A if (m.getName().equals("copyOfIntegerArray"))
0N/A cia = m;
0N/A if (m.getName().equals("copyOfIntegerArrayRange"))
0N/A ciar = m;
0N/A }
0N/A Method[] arrayMethods = Arrays.class.getDeclaredMethods();
0N/A cloners = new HashMap<Class<?>,Method>();
0N/A cloneRangers = new HashMap<Class<?>,Method>();
0N/A toStrings = new HashMap<Class<?>,Method>();
0N/A for (int i = 0; i < arrayMethods.length; i++) {
0N/A Method m = arrayMethods[i];
0N/A if (!Modifier.isStatic(m.getModifiers())) continue;
0N/A Class<?> rt = m.getReturnType();
0N/A if (m.getName().equals("copyOf")
0N/A && m.getParameterTypes().length == 2)
0N/A cloners.put(rt.getComponentType(), m);
0N/A if (m.getName().equals("copyOfRange")
0N/A && m.getParameterTypes().length == 3)
0N/A cloneRangers.put(rt.getComponentType(), m);
0N/A if (m.getName().equals("toString")) {
0N/A Class<?> pt = m.getParameterTypes()[0];
0N/A toStrings.put(pt.getComponentType(), m);
0N/A }
0N/A }
0N/A cloners.put(String.class, cloners.get(Object.class));
0N/A cloneRangers.put(String.class, cloneRangers.get(Object.class));
0N/A assert(cia != null);
0N/A cloners.put(Integer.class, cia);
0N/A assert(ciar != null);
0N/A cloneRangers.put(Integer.class, ciar);
0N/A nullValues = new HashMap<Class<?>,Object>();
0N/A for (Class<?> c : allTypes) {
0N/A nullValues.put(c, invoke(coercers.get(c), 0));
0N/A }
0N/A }
0N/A}