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 }