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