1 /* 2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 4655503 27 * @summary Test for array cloning and slicing methods. 28 * @author John Rose 29 * @key randomness 30 */ 31 32 package test.java.util.Arrays; 33 34 import java.util.*; 35 import java.lang.reflect.*; 36 37 public class CopyMethods { 38 static int muzzle; // if !=0, suppresses ("muzzles") messages 39 40 static int maxLen = 40; // maximum length of test arrays 41 static int shortStepsNear = 4; // interesting span near critical values 42 static int downShift = 3; 43 44 static int testCasesRun = 0; 45 static long consing = 0; 46 47 // very simple tests, mainly to test the framework itself simpleTests()48 static void simpleTests() { 49 int[] a = (int[]) makeArray(3, int.class); 50 if (muzzle == 0) 51 System.out.println("int[] a = "+Arrays.toString(a)); 52 check(a.length == 3); 53 check(a[0] == testValues[0]); 54 check(a[1] == testValues[1]); 55 check(a[2] == testValues[2]); 56 checkArray(a, int.class, 3, 0, 3); 57 // negative test of testing framework: 58 for (int bad = -2; bad < a.length; bad++) { 59 try { 60 int[] aa = a.clone(); 61 if (bad < 0) aa = new int[4]; 62 else aa[bad] = 0; 63 ++muzzle; 64 // the following check should fail! 65 if (bad == -2) 66 checkArray(new String[3], int.class, 0, 0, a.length); 67 else 68 checkArray(aa, int.class, 0, 0, a.length); 69 throw new Error("Should Not Reach Here"); 70 } catch (RuntimeException ee) { 71 --muzzle; 72 if (muzzle == 0) 73 System.out.println("Expected: "+ee); 74 } 75 } 76 checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3); 77 checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3); 78 checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3); 79 checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3); 80 checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3); 81 82 // quick test of copyOfRange 83 int[] ar = Arrays.copyOfRange(a, 1, 3); 84 check(ar.length == 2); 85 check(ar[0] == a[1]); 86 check(ar[1] == a[2]); 87 checkArray(ar, int.class, 2, 1, 2); 88 ar = Arrays.copyOfRange(a, 2, 4); 89 check(ar.length == 2); 90 check(ar[0] == a[2]); 91 check(ar[1] == 0); 92 checkArray(ar, int.class, 2, 2, 1); 93 ar = Arrays.copyOfRange(a, 3, 5); 94 check(ar.length == 2); 95 check(ar[0] == 0); 96 check(ar[1] == 0); 97 checkArray(ar, int.class, 2, 3, 0); 98 byte[] ba = (byte[]) makeArray(3, byte.class); 99 if (muzzle == 0) 100 System.out.println("byte[] ba = "+Arrays.toString(ba)); 101 for (int j = 0; j <= ba.length+2; j++) { 102 byte[] bb = Arrays.copyOf(ba, j); 103 if (muzzle == 0) 104 System.out.println("copyOf(ba,"+j+") = "+ 105 Arrays.toString(bb)); 106 checkArray(bb, byte.class, j, 0, ba.length); 107 byte[] bbr = Arrays.copyOfRange(ba, 0, j); 108 check(Arrays.equals(bb, bbr)); 109 } 110 for (int i = 0; i <= a.length; i++) { 111 for (int j = i; j <= a.length+2; j++) { 112 byte[] br = Arrays.copyOfRange(ba, i, j); 113 if (muzzle == 0) 114 System.out.println("copyOfRange(ba,"+i+","+j+") = "+ 115 Arrays.toString(br)); 116 checkArray(br, byte.class, j-i, i, ba.length-i); 117 } 118 } 119 String[] sa = (String[]) makeArray(3, String.class); 120 if (muzzle == 0) 121 System.out.println("String[] sa = "+Arrays.toString(sa)); 122 check(sa[0].equals(Integer.toHexString(testValues[0]))); 123 check(sa[1].equals(Integer.toHexString(testValues[1]))); 124 check(sa[2].equals(Integer.toHexString(testValues[2]))); 125 checkArray(sa, String.class, sa.length, 0, sa.length); 126 String[] sa4 = Arrays.copyOf(sa, sa.length+1); 127 check(sa4[0] == sa[0]); 128 check(sa4[1] == sa[1]); 129 check(sa4[2] == sa[2]); 130 check(sa4[sa.length] == null); 131 checkArray(sa4, String.class, sa4.length, 0, sa.length); 132 String[] sr4 = Arrays.copyOfRange(sa, 1, 5); 133 check(sr4[0] == sa[1]); 134 check(sr4[1] == sa[2]); 135 check(sr4[2] == null); 136 check(sr4[3] == null); 137 checkArray(sr4, String.class, 4, 1, sa.length-1); 138 if (muzzle == 0) 139 System.out.println("simpleTests done"); 140 } 141 142 // the framework: a fixed series of test values 143 static final int[] testValues; 144 static { 145 testValues = new int[1000]; 146 Random r = new Random(); 147 for (int i = 0; i < testValues.length; i++) { 148 testValues[i] = r.nextInt(); 149 } 150 } 151 /** Return a canonical test value of a desired index and type. 152 * The original test values are random ints. Derive other test 153 * values as follows: 154 * <pre> 155 * int tv = testValues[i] 156 * (C)tv C is byte, short, char, long, float, double 157 * (tv&1)!=0 C is boolean 158 * (Integer)tv C is Object and tv%16 != 0 159 * null C is Object and tv%16 == 0 160 * Integer.toHexString(tv) C is String and tv != 0 161 * null C is String and tv == 0 162 * </pre> 163 * are derived by ordinary Java coercions, except that boolean 164 * samples the LSB of the int value, and String is the hex numeral. 165 * 166 * (Also, the 0th String is null, and the 0th Object mod 16 is null, 167 * regardless of the original int test value.) 168 */ testValue(int i, Class<?> c)169 static Object testValue(int i, Class<?> c) { 170 int tv = testValues[i % testValues.length]; 171 if (i >= testValues.length) tv ^= i; 172 // Turn the canonical int to a float, boolean, String, whatever: 173 return invoke(coercers.get(c), tv); 174 } 175 /** Build a test array of the given length, 176 * packed with a subsequence of the test values. 177 * The first element of the array is always testValue(0). 178 */ makeArray(int len, Class<?> c)179 static Object makeArray(int len, Class<?> c) { 180 Object a = Array.newInstance(c, len); 181 for (int i = 0; i < len; i++) { 182 Array.set(a, i, testValue(i, c)); 183 } 184 return a; 185 } 186 /** Check that the given array has the required length. 187 * Check also that it is packed, up to firstNull, with 188 * a particular subsequence of the canonical test values. 189 * The subsequence must begin with a[0] == testValue(offset). 190 * At a[firstNull] and beyond, the array must contain null values. 191 */ checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull)192 static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) { 193 check(c == a.getClass().getComponentType()); 194 Object nullValue = nullValues.get(c); 195 // Note: asserts in here are not part of the test program. 196 // They verify the integrity of the test method itself. 197 assert(nullValues.containsKey(c)); 198 199 int misses = 0; 200 int firstMiss = -1; 201 // Check required length first. 202 int length = Array.getLength(a); 203 if (length != requiredLen && requiredLen != -1) { 204 if (muzzle == 0) 205 System.out.println("*** a.length = "+length+" != "+requiredLen); 206 ++misses; 207 } 208 209 for (int i = 0; i < length; i++) { 210 Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c); 211 Object ai = Array.get(a, i); 212 if (!eq(ai, tv)) { 213 if (muzzle == 0) 214 System.out.println("*** a["+i+"] = "+ai+" != "+tv); 215 if (misses == 0) firstMiss = i; 216 if (++misses > 10) break; 217 } 218 } 219 if (misses != 0) { 220 Method toString = toStrings.get(c); 221 if (toString == null) toString = toStrings.get(Object.class); 222 throw new RuntimeException("checkArray failed at "+firstMiss 223 +" "+c+"[]" 224 +" : "+invoke(toString, a)); 225 } 226 } 227 // Typical comparison helper. Why isn't this a method somewhere. eq(Object x, Object y)228 static boolean eq(Object x, Object y) { 229 return x == null? y == null: x.equals(y); 230 } 231 // Exception-ignoring invoke function. invoke(Method m, Object... args)232 static Object invoke(Method m, Object... args) { 233 Exception ex; 234 try { 235 return m.invoke(null, args); 236 } catch (InvocationTargetException ee) { 237 ex = ee; 238 } catch (IllegalAccessException ee) { 239 ex = ee; 240 } catch (IllegalArgumentException ee) { 241 ex = ee; 242 } 243 ArrayList<Object> call = new ArrayList<Object>(); 244 call.add(m); Collections.addAll(call, args); 245 throw new RuntimeException(call+" : "+ex); 246 } 247 // version of assert() that runs unconditionally check(boolean z)248 static void check(boolean z) { 249 if (!z) throw new RuntimeException("check failed"); 250 } 251 252 253 /** Run about 10**5 distinct parameter combinations 254 * on copyOf and copyOfRange. Use all primitive types, 255 * and String and Object. 256 * Try to all critical values, looking for fencepost errors. 257 */ fullTests(int maxLen, Class<?> c)258 static void fullTests(int maxLen, Class<?> c) { 259 Method cloner = cloners.get(c); 260 assert(cloner != null) : c; 261 Method cloneRanger = cloneRangers.get(c); 262 // Note: asserts in here are not part of the test program. 263 // They verify the integrity of the test method itself. 264 assert(cloneRanger != null) : c; 265 for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) { 266 Object a = makeArray(src, c); 267 for (int x : new ArrayList<Integer>()) {} 268 for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) { 269 // b = Arrays.copyOf(a, j); 270 Object b = invoke(cloner, a, j); 271 checkArray(b, c, j, 0, src); 272 testCasesRun++; 273 consing += j; 274 275 int maxI = Math.min(src, j); 276 for (int i = 0; i <= maxI; i = inc(i, src, maxI)) { 277 // r = Arrays.copyOfRange(a, i, j); 278 Object r = invoke(cloneRanger, a, i, j); 279 checkArray(r, c, j-i, i, src-i); 280 //System.out.println("case c="+c+" src="+src+" i="+i+" j="+j); 281 testCasesRun++; 282 consing += j-i; 283 } 284 } 285 } 286 } 287 // Increment x by at least one. Increment by a little more unless 288 // it is near a critical value, either zero, crit1, or crit2. inc(int x, int crit1, int crit2)289 static int inc(int x, int crit1, int crit2) { 290 int D = shortStepsNear; 291 if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; } 292 assert(crit1 <= crit2); 293 assert(x <= crit2); // next1 or next2 must be the limit value 294 x += 1; 295 if (x > D) { 296 if (x < crit1-D) { 297 x += (x << 1) >> downShift; // giant step toward crit1-D 298 if (x > crit1-D) x = crit1-D; 299 } else if (x >= crit1+D && x < crit2-D) { 300 x += (x << 1) >> downShift; // giant step toward crit2-D 301 if (x > crit2-D) x = crit2-D; 302 } 303 } 304 return x; 305 } 306 main(String[] av)307 public static void main(String[] av) { 308 boolean verbose = (av.length != 0); 309 muzzle = (verbose? 0: 1); 310 if (muzzle == 0) 311 System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"..."); 312 313 simpleTests(); 314 315 muzzle = 0; // turn on print statements (affects failures only) 316 317 fullTests(); 318 if (verbose) 319 System.out.println("ran "+testCasesRun+" tests, avg len=" 320 +(float)consing/testCasesRun); 321 322 // test much larger arrays, more sparsely 323 maxLen = 500; 324 shortStepsNear = 2; 325 downShift = 0; 326 testCasesRun = 0; 327 consing = 0; 328 fullTests(); 329 if (verbose) 330 System.out.println("ran "+testCasesRun+" tests, avg len=" 331 +(float)consing/testCasesRun); 332 } 333 fullTests()334 static void fullTests() { 335 for (Class<?> c : allTypes) { 336 fullTests(maxLen, c); 337 } 338 } 339 340 // We must run all the our tests on each of 8 distinct primitive types, 341 // and two reference types (Object, String) for good measure. 342 // This would be a pain to write out by hand, statically typed. 343 // So, use reflection. Following are the tables of methods we use. 344 // (The initial simple tests exercise enough of the static typing 345 // features of the API to ensure that they compile as advertised.) 346 coerceToObject(int x)347 static Object coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); } coerceToString(int x)348 static String coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); } coerceToInteger(int x)349 static Integer coerceToInteger(int x) { return (x == 0)? null: x; } coerceToByte(int x)350 static byte coerceToByte(int x) { return (byte)x; } coerceToShort(int x)351 static short coerceToShort(int x) { return (short)x; } coerceToInt(int x)352 static int coerceToInt(int x) { return x; } coerceToLong(int x)353 static long coerceToLong(int x) { return x; } coerceToChar(int x)354 static char coerceToChar(int x) { return (char)x; } coerceToFloat(int x)355 static float coerceToFloat(int x) { return x; } coerceToDouble(int x)356 static double coerceToDouble(int x) { return x; } coerceToBoolean(int x)357 static boolean coerceToBoolean(int x) { return (x&1) != 0; } 358 copyOfIntegerArray(Object[] a, int len)359 static Integer[] copyOfIntegerArray(Object[] a, int len) { 360 // This guy exercises the API based on a type-token. 361 // Note the static typing. 362 return Arrays.copyOf(a, len, Integer[].class); 363 } copyOfIntegerArrayRange(Object[] a, int m, int n)364 static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) { 365 // This guy exercises the API based on a type-token. 366 // Note the static typing. 367 return Arrays.copyOfRange(a, m, n, Integer[].class); 368 } 369 370 static final List<Class<?>> allTypes 371 = Arrays.asList(new Class<?>[] 372 { Object.class, String.class, Integer.class, 373 byte.class, short.class, int.class, long.class, 374 char.class, float.class, double.class, 375 boolean.class 376 }); 377 static final HashMap<Class<?>,Method> coercers; 378 static final HashMap<Class<?>,Method> cloners; 379 static final HashMap<Class<?>,Method> cloneRangers; 380 static final HashMap<Class<?>,Method> toStrings; 381 static final HashMap<Class<?>,Object> nullValues; 382 static { 383 coercers = new HashMap<Class<?>,Method>(); 384 Method[] testMethods = CopyMethods.class.getDeclaredMethods(); 385 Method cia = null, ciar = null; 386 for (int i = 0; i < testMethods.length; i++) { 387 Method m = testMethods[i]; 388 if (!Modifier.isStatic(m.getModifiers())) continue; 389 Class<?> rt = m.getReturnType(); 390 if (m.getName().startsWith("coerceTo") && allTypes.contains(rt)) m.getReturnType()391 coercers.put(m.getReturnType(), m); 392 if (m.getName().equals("copyOfIntegerArray")) 393 cia = m; 394 if (m.getName().equals("copyOfIntegerArrayRange")) 395 ciar = m; 396 } 397 Method[] arrayMethods = Arrays.class.getDeclaredMethods(); 398 cloners = new HashMap<Class<?>,Method>(); 399 cloneRangers = new HashMap<Class<?>,Method>(); 400 toStrings = new HashMap<Class<?>,Method>(); 401 for (int i = 0; i < arrayMethods.length; i++) { 402 Method m = arrayMethods[i]; 403 if (!Modifier.isStatic(m.getModifiers())) continue; 404 Class<?> rt = m.getReturnType(); 405 if (m.getName().equals("copyOf") 406 && m.getParameterTypes().length == 2) rt.getComponentType()407 cloners.put(rt.getComponentType(), m); 408 if (m.getName().equals("copyOfRange") 409 && m.getParameterTypes().length == 3) rt.getComponentType()410 cloneRangers.put(rt.getComponentType(), m); 411 if (m.getName().equals("toString")) { 412 Class<?> pt = m.getParameterTypes()[0]; pt.getComponentType()413 toStrings.put(pt.getComponentType(), m); 414 } 415 } cloners.put(String.class, cloners.get(Object.class))416 cloners.put(String.class, cloners.get(Object.class)); cloneRangers.put(String.class, cloneRangers.get(Object.class))417 cloneRangers.put(String.class, cloneRangers.get(Object.class)); 418 assert(cia != null); cloners.put(Integer.class, cia)419 cloners.put(Integer.class, cia); 420 assert(ciar != null); cloneRangers.put(Integer.class, ciar)421 cloneRangers.put(Integer.class, ciar); 422 nullValues = new HashMap<Class<?>,Object>(); 423 for (Class<?> c : allTypes) { nullValues.put(c, invoke(coercers.get(c), 0))424 nullValues.put(c, invoke(coercers.get(c), 0)); 425 } 426 } 427 } 428