1 /*
2 * Copyright (c) 2003, 2026, 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 4906359 6239296
27 * @summary Basic test for content-based array object methods
28 * @author Josh Bloch, Martin Buchholz
29 * @key randomness
30 * @library /test/lib
31 */
32
33 import java.util.*;
34 import java.io.*;
35
36 import jdk.test.lib.valueclass.AsValueClass;
37
38 public class ArrayObjectMethods {
39
40 @AsValueClass
41 record V(int x, int y) implements Serializable {}
42
43 int[] sizes = {0, 10, 100, 200, 1000};
44
45 void test(String[] args) throws Throwable {
46 equal(Arrays.deepToString(null), "null");
47 equal(Arrays.deepToString(new Object[]{}), "[]");
48 equal(Arrays.deepToString(new Object[]{null}), "[null]");
49 equal(Arrays.deepToString(new Object[]{null, 1}), "[null, 1]");
50 equal(Arrays.deepToString(new Object[]{1, null}), "[1, null]");
51 equal(Arrays.deepToString(new Object[]{new Object[]{}, null}), "[[], null]");
52
53 {
54 Object[] a = {1, null};
55 a[1] = a;
56 equal(Arrays.deepToString(a), "[1, [...]]");
57 a[0] = a;
58 equal(Arrays.deepToString(a), "[[...], [...]]");
59 a[0] = a[1] = new Object[]{1, null, a};
60 equal(Arrays.deepToString(a), "[[1, null, [...]], [1, null, [...]]]");
61 }
62
63 for (int size : sizes) {
64 {
65 long[] a = Rnd.longArray(size);
66 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
67 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
68 }
69 {
70 int[] a = Rnd.intArray(size);
71 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
72 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
73 }
74 {
75 short[] a = Rnd.shortArray(size);
76 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
77 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
78 }
79 {
80 char[] a = Rnd.charArray(size);
81 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
82 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
83 }
84 {
85 byte[] a = Rnd.byteArray(size);
86 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
87 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
88 }
89 {
90 boolean[] a = Rnd.booleanArray(size);
91 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
92 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
93 }
94 {
95 double[] a = Rnd.doubleArray(size);
96 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
97 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
98 }
99 {
100 float[] a = Rnd.floatArray(size);
101 equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
102 equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
103 }
104 {
105 Object[] a = Rnd.flatObjectArray(size);
106 equal(Arrays.toString(a), Arrays.asList(a).toString());
107 equal(Arrays.deepToString(a), Arrays.asList(a).toString());
108 equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
109 }
110
111 if (size <= 200) {
112 Object[] a = Rnd.nestedObjectArray(size);
113 List aList = deepToList(a);
114 equal(Arrays.toString(a), Arrays.asList(a).toString());
115 equal(Arrays.deepToString(a), aList.toString());
116 equal(Arrays.deepHashCode(a), aList.hashCode());
117 equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
118
119 Object[] deepCopy = (Object[]) deepCopy(a);
120 check(Arrays.deepEquals(a, deepCopy));
121 check(Arrays.deepEquals(deepCopy, a));
122
123 // Make deepCopy != a
124 if (size == 0)
125 deepCopy = new Object[] {"foo"};
126 else if (deepCopy[deepCopy.length - 1] == null)
127 deepCopy[deepCopy.length - 1] = "baz";
128 else
129 deepCopy[deepCopy.length - 1] = null;
130 check(! Arrays.deepEquals(a, deepCopy));
131 check(! Arrays.deepEquals(deepCopy, a));
132 }
133 }
134 }
135
136 // Utility method to turn an array into a list "deeply," turning
137 // all primitives into objects
138 List<Object> deepToList(Object[] a) {
139 List<Object> result = new ArrayList<Object>();
140 for (Object e : a) {
141 if (e instanceof byte[])
142 result.add(PrimitiveArrays.asList((byte[])e));
143 else if (e instanceof short[])
144 result.add(PrimitiveArrays.asList((short[])e));
145 else if (e instanceof int[])
146 result.add(PrimitiveArrays.asList((int[])e));
147 else if (e instanceof long[])
148 result.add(PrimitiveArrays.asList((long[])e));
149 else if (e instanceof char[])
150 result.add(PrimitiveArrays.asList((char[])e));
151 else if (e instanceof double[])
152 result.add(PrimitiveArrays.asList((double[])e));
153 else if (e instanceof float[])
154 result.add(PrimitiveArrays.asList((float[])e));
155 else if (e instanceof boolean[])
156 result.add(PrimitiveArrays.asList((boolean[])e));
157 else if (e instanceof Object[])
158 result.add(deepToList((Object[])e));
159 else
160 result.add(e);
161 }
162 return result;
163 }
164
165 // Utility method to do a deep copy of an object *very slowly* using
166 // serialization/deserialization
167 Object deepCopy(Object oldObj) {
168 try {
169 ByteArrayOutputStream bos = new ByteArrayOutputStream();
170 ObjectOutputStream oos = new ObjectOutputStream(bos);
171 oos.writeObject(oldObj);
172 oos.flush();
173 ByteArrayInputStream bin = new ByteArrayInputStream(
174 bos.toByteArray());
175 ObjectInputStream ois = new ObjectInputStream(bin);
176 return ois.readObject();
177 } catch(Exception e) {
178 throw new IllegalArgumentException(e);
179 }
180 }
181
182 //--------------------- Infrastructure ---------------------------
183 volatile int passed = 0, failed = 0;
184 void pass() {passed++;}
185 void fail() {failed++; Thread.dumpStack();}
186 void fail(String msg) {System.err.println(msg); fail();}
187 void unexpected(Throwable t) {failed++; t.printStackTrace();}
188 void check(boolean cond) {if (cond) pass(); else fail();}
189 void equal(Object x, Object y) {
190 if (x == null ? y == null : x.equals(y)) pass();
191 else fail(x + " not equal to " + y);}
192 public static void main(String[] args) throws Throwable {
193 new ArrayObjectMethods().instanceMain(args);}
194 void instanceMain(String[] args) throws Throwable {
195 try {test(args);} catch (Throwable t) {unexpected(t);}
196 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
197 if (failed > 0) throw new AssertionError("Some tests failed");}
198 }
199
200 /**
201 * Methods to generate "interesting" random primitives and primitive
202 * arrays. Unlike Random.nextXxx, these methods return small values
203 * and boundary values (e.g., 0, -1, NaN) with greater than normal
204 * likelihood.
205 */
206
207 class Rnd {
208 private static Random rnd = new Random();
209
210 public static long nextLong() {
211 switch(rnd.nextInt(10)) {
212 case 0: return 0;
213 case 1: return Long.MIN_VALUE;
214 case 2: return Long.MAX_VALUE;
215 case 3: case 4: case 5:
216 return (long) (rnd.nextInt(20) - 10);
217 default: return rnd.nextLong();
218 }
219 }
220
221 public static int nextInt() {
222 switch(rnd.nextInt(10)) {
223 case 0: return 0;
224 case 1: return Integer.MIN_VALUE;
225 case 2: return Integer.MAX_VALUE;
226 case 3: case 4: case 5:
227 return rnd.nextInt(20) - 10;
228 default: return rnd.nextInt();
229 }
230 }
231
232 public static short nextShort() {
233 switch(rnd.nextInt(10)) {
234 case 0: return 0;
235 case 1: return Short.MIN_VALUE;
236 case 2: return Short.MAX_VALUE;
237 case 3: case 4: case 5:
238 return (short) (rnd.nextInt(20) - 10);
239 default: return (short) rnd.nextInt();
240 }
241 }
242
243 public static char nextChar() {
244 switch(rnd.nextInt(10)) {
245 case 0: return 0;
246 case 1: return Character.MIN_VALUE;
247 case 2: return Character.MAX_VALUE;
248 case 3: case 4: case 5:
249 return (char) (rnd.nextInt(20) - 10);
250 default: return (char) rnd.nextInt();
251 }
252 }
253
254 public static byte nextByte() {
255 switch(rnd.nextInt(10)) {
256 case 0: return 0;
257 case 1: return Byte.MIN_VALUE;
258 case 2: return Byte.MAX_VALUE;
259 case 3: case 4: case 5:
260 return (byte) (rnd.nextInt(20) - 10);
261 default: return (byte) rnd.nextInt();
262 }
263 }
264
265 public static boolean nextBoolean() {
266 return rnd.nextBoolean();
267 }
268
269 public static double nextDouble() {
270 switch(rnd.nextInt(20)) {
271 case 0: return 0;
272 case 1: return -0.0;
273 case 2: return Double.MIN_VALUE;
274 case 3: return Double.MAX_VALUE;
275 case 4: return Double.NaN;
276 case 5: return Double.NEGATIVE_INFINITY;
277 case 6: return Double.POSITIVE_INFINITY;
278 case 7: case 8: case 9:
279 return (rnd.nextInt(20) - 10);
280 default: return rnd.nextDouble();
281 }
282 }
283
284 public static float nextFloat() {
285 switch(rnd.nextInt(20)) {
286 case 0: return 0;
287 case 1: return -0.0f;
288 case 2: return Float.MIN_VALUE;
289 case 3: return Float.MAX_VALUE;
290 case 4: return Float.NaN;
291 case 5: return Float.NEGATIVE_INFINITY;
292 case 6: return Float.POSITIVE_INFINITY;
293 case 7: case 8: case 9:
294 return (rnd.nextInt(20) - 10);
295 default: return rnd.nextFloat();
296 }
297 }
298
299 public static Object nextObject() {
300 switch(rnd.nextInt(12)) {
301 case 0: return null;
302 case 1: return "foo";
303 case 2: case 3: case 4: return Double.valueOf(nextDouble());
304 case 5: case 6: return nextV();
305 default: return Integer.valueOf(nextInt());
306 }
307 }
308
309 public static long[] longArray(int length) {
310 long[] result = new long[length];
311 for (int i = 0; i < length; i++)
312 result[i] = Rnd.nextLong();
313 return result;
314 }
315
316 public static int[] intArray(int length) {
317 int[] result = new int[length];
318 for (int i = 0; i < length; i++)
319 result[i] = Rnd.nextInt();
320 return result;
321 }
322
323 public static short[] shortArray(int length) {
324 short[] result = new short[length];
325 for (int i = 0; i < length; i++)
326 result[i] = Rnd.nextShort();
327 return result;
328 }
329
330 public static char[] charArray(int length) {
331 char[] result = new char[length];
332 for (int i = 0; i < length; i++)
333 result[i] = Rnd.nextChar();
334 return result;
335 }
336
337 public static byte[] byteArray(int length) {
338 byte[] result = new byte[length];
339 for (int i = 0; i < length; i++)
340 result[i] = Rnd.nextByte();
341 return result;
342 }
343
344 public static boolean[] booleanArray(int length) {
345 boolean[] result = new boolean[length];
346 for (int i = 0; i < length; i++)
347 result[i] = Rnd.nextBoolean();
348 return result;
349 }
350
351 public static double[] doubleArray(int length) {
352 double[] result = new double[length];
353 for (int i = 0; i < length; i++)
354 result[i] = Rnd.nextDouble();
355 return result;
356 }
357
358 public static float[] floatArray(int length) {
359 float[] result = new float[length];
360 for (int i = 0; i < length; i++)
361 result[i] = Rnd.nextFloat();
362 return result;
363 }
364
365 public static Object[] flatObjectArray(int length) {
366 Object[] result = new Object[length];
367 for (int i = 0; i < length; i++)
368 result[i] = Rnd.nextObject();
369 return result;
370 }
371
372 public static ArrayObjectMethods.V nextV() {
373 return new ArrayObjectMethods.V(nextInt(), nextInt());
374 }
375
376 public static ArrayObjectMethods.V[] vArray(int length) {
377 ArrayObjectMethods.V[] result = new ArrayObjectMethods.V[length];
378 for (int i = 0; i < length; i++)
379 result[i] = nextV();
380 return result;
381 }
382
383 // Calling this for length >> 100 is likely to run out of memory! It
384 // should be perhaps be tuned to allow for longer arrays
385 public static Object[] nestedObjectArray(int length) {
386 Object[] result = new Object[length];
387 for (int i = 0; i < length; i++) {
388 switch(rnd.nextInt(16)) {
389 case 0: result[i] = nestedObjectArray(length/2);
390 break;
391 case 1: result[i] = longArray(length/2);
392 break;
393 case 2: result[i] = intArray(length/2);
394 break;
395 case 3: result[i] = shortArray(length/2);
396 break;
397 case 4: result[i] = charArray(length/2);
398 break;
399 case 5: result[i] = byteArray(length/2);
400 break;
401 case 6: result[i] = floatArray(length/2);
402 break;
403 case 7: result[i] = doubleArray(length/2);
404 break;
405 case 8: result[i] = longArray(length/2);
406 break;
407 case 9: result[i] = vArray(length/2);
408 break;
409 case 10: result[i] = nextV();
410 break;
411 default: result[i] = Rnd.nextObject();
412 }
413 }
414 return result;
415 }
416 }
417
418 /**
419 * Primitive arrays viewed as lists. Inefficient but cool.
420 * This utility should be generally useful in writing regression/unit/basic
421 * tests.
422 */
423
424 class PrimitiveArrays {
425 public static List<Long> asList(final long[] a) {
426 return new AbstractList<Long>() {
427 public Long get(int i) { return a[i]; }
428 public int size() { return a.length; }
429
430 public Long set(int i, Long e) {
431 long oldVal = a[i];
432 a[i] = e;
433 return oldVal;
434 }
435 };
436 }
437
438 public static List<Integer> asList(final int[] a) {
439 return new AbstractList<Integer>() {
440 public Integer get(int i) { return a[i]; }
441 public int size() { return a.length; }
442
443 public Integer set(int i, Integer e) {
444 int oldVal = a[i];
445 a[i] = e;
446 return oldVal;
447 }
448 };
449 }
450
451 public static List<Short> asList(final short[] a) {
452 return new AbstractList<Short>() {
453 public Short get(int i) { return a[i]; }
454 public int size() { return a.length; }
455
456 public Short set(int i, Short e) {
457 short oldVal = a[i];
458 a[i] = e;
459 return oldVal;
460 }
461 };
462 }
463
464 public static List<Character> asList(final char[] a) {
465 return new AbstractList<Character>() {
466 public Character get(int i) { return a[i]; }
467 public int size() { return a.length; }
468
469 public Character set(int i, Character e) {
470 Character oldVal = a[i];
471 a[i] = e;
472 return oldVal;
473 }
474 };
475 }
476
477 public static List<Byte> asList(final byte[] a) {
478 return new AbstractList<Byte>() {
479 public Byte get(int i) { return a[i]; }
480 public int size() { return a.length; }
481
482 public Byte set(int i, Byte e) {
483 Byte oldVal = a[i];
484 a[i] = e;
485 return oldVal;
486 }
487 };
488 }
489
490 public static List<Boolean> asList(final boolean[] a) {
491 return new AbstractList<Boolean>() {
492 public Boolean get(int i) { return a[i]; }
493 public int size() { return a.length; }
494
495 public Boolean set(int i, Boolean e) {
496 Boolean oldVal = a[i];
497 a[i] = e;
498 return oldVal;
499 }
500 };
501 }
502
503 public static List<Double> asList(final double[] a) {
504 return new AbstractList<Double>() {
505 public Double get(int i) { return a[i]; }
506 public int size() { return a.length; }
507
508 public Double set(int i, Double e) {
509 Double oldVal = a[i];
510 a[i] = e;
511 return oldVal;
512 }
513 };
514 }
515
516 public static List<Float> asList(final float[] a) {
517 return new AbstractList<Float>() {
518 public Float get(int i) { return a[i]; }
519 public int size() { return a.length; }
520
521 public Float set(int i, Float e) {
522 Float oldVal = a[i];
523 a[i] = e;
524 return oldVal;
525 }
526 };
527 }
528 }