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 }