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