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
32import java.util.*;
33import java.io.*;
34
35public 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
200class 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
402class 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}
507