// 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. *Theoriginaltestvaluesarerandomints.Deriveothertest *valuesasfollows: *<pre> *inttv=testValues[i] *(C)tvCisbyte,short,char,long,float,double *(tv&1)!=0Cisboolean *(Integer)tvCisObjectandtv%16!=0 *nullCisObjectandtv%16==0 *Integer.toHexString(tv)CisStringandtv!=0 *nullCisStringandtv==0 *</pre> *arederivedbyordinaryJavacoercions,exceptthatboolean *samplestheLSBoftheintvalue,andStringisthehexnumeral. * *(Also,the0thStringisnull,andthe0thObjectmod16isnull, *regardlessoftheoriginalinttestvalue.)
*/ 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, *packedwithasubsequenceofthetestvalues. *ThefirstelementofthearrayisalwaystestValue(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. *Checkalsothatitispacked,uptofirstNull,with *aparticularsubsequenceofthecanonicaltestvalues. *Thesubsequencemustbeginwitha[0]==testValue(offset). *Ata[firstNull]andbeyond,thearraymustcontainnullvalues.
*/ 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 *oncopyOfandcopyOfRange.Useallprimitivetypes, *andStringandObject. *Trytoallcriticalvalues,lookingforfenceposterrors.
*/ 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 und die Messung sind noch experimentell.