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 }