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