3789983e89
Reviewed-by: darcy, ihse
507 lines
18 KiB
Java
507 lines
18 KiB
Java
/*
|
|
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 4906359 6239296
|
|
* @summary Basic test for content-based array object methods
|
|
* @author Josh Bloch, Martin Buchholz
|
|
* @key randomness
|
|
*/
|
|
|
|
import java.util.*;
|
|
import java.io.*;
|
|
|
|
public class ArrayObjectMethods {
|
|
int[] sizes = {0, 10, 100, 200, 1000};
|
|
|
|
void test(String[] args) throws Throwable {
|
|
equal(Arrays.deepToString(null), "null");
|
|
equal(Arrays.deepToString(new Object[]{}), "[]");
|
|
equal(Arrays.deepToString(new Object[]{null}), "[null]");
|
|
equal(Arrays.deepToString(new Object[]{null, 1}), "[null, 1]");
|
|
equal(Arrays.deepToString(new Object[]{1, null}), "[1, null]");
|
|
equal(Arrays.deepToString(new Object[]{new Object[]{}, null}), "[[], null]");
|
|
|
|
{
|
|
Object[] a = {1, null};
|
|
a[1] = a;
|
|
equal(Arrays.deepToString(a), "[1, [...]]");
|
|
a[0] = a;
|
|
equal(Arrays.deepToString(a), "[[...], [...]]");
|
|
a[0] = a[1] = new Object[]{1, null, a};
|
|
equal(Arrays.deepToString(a), "[[1, null, [...]], [1, null, [...]]]");
|
|
}
|
|
|
|
for (int size : sizes) {
|
|
{
|
|
long[] a = Rnd.longArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
int[] a = Rnd.intArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
short[] a = Rnd.shortArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
char[] a = Rnd.charArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
byte[] a = Rnd.byteArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
boolean[] a = Rnd.booleanArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
double[] a = Rnd.doubleArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
float[] a = Rnd.floatArray(size);
|
|
equal(Arrays.toString(a), PrimitiveArrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), PrimitiveArrays.asList(a).hashCode());
|
|
}
|
|
{
|
|
Object[] a = Rnd.flatObjectArray(size);
|
|
equal(Arrays.toString(a), Arrays.asList(a).toString());
|
|
equal(Arrays.deepToString(a), Arrays.asList(a).toString());
|
|
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
|
|
}
|
|
|
|
if (size <= 200) {
|
|
Object[] a = Rnd.nestedObjectArray(size);
|
|
List aList = deepToList(a);
|
|
equal(Arrays.toString(a), Arrays.asList(a).toString());
|
|
equal(Arrays.deepToString(a), aList.toString());
|
|
equal(Arrays.deepHashCode(a), aList.hashCode());
|
|
equal(Arrays.hashCode(a), Arrays.asList(a).hashCode());
|
|
|
|
Object[] deepCopy = (Object[]) deepCopy(a);
|
|
check(Arrays.deepEquals(a, deepCopy));
|
|
check(Arrays.deepEquals(deepCopy, a));
|
|
|
|
// Make deepCopy != a
|
|
if (size == 0)
|
|
deepCopy = new Object[] {"foo"};
|
|
else if (deepCopy[deepCopy.length - 1] == null)
|
|
deepCopy[deepCopy.length - 1] = "baz";
|
|
else
|
|
deepCopy[deepCopy.length - 1] = null;
|
|
check(! Arrays.deepEquals(a, deepCopy));
|
|
check(! Arrays.deepEquals(deepCopy, a));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Utility method to turn an array into a list "deeply," turning
|
|
// all primitives into objects
|
|
List<Object> deepToList(Object[] a) {
|
|
List<Object> result = new ArrayList<Object>();
|
|
for (Object e : a) {
|
|
if (e instanceof byte[])
|
|
result.add(PrimitiveArrays.asList((byte[])e));
|
|
else if (e instanceof short[])
|
|
result.add(PrimitiveArrays.asList((short[])e));
|
|
else if (e instanceof int[])
|
|
result.add(PrimitiveArrays.asList((int[])e));
|
|
else if (e instanceof long[])
|
|
result.add(PrimitiveArrays.asList((long[])e));
|
|
else if (e instanceof char[])
|
|
result.add(PrimitiveArrays.asList((char[])e));
|
|
else if (e instanceof double[])
|
|
result.add(PrimitiveArrays.asList((double[])e));
|
|
else if (e instanceof float[])
|
|
result.add(PrimitiveArrays.asList((float[])e));
|
|
else if (e instanceof boolean[])
|
|
result.add(PrimitiveArrays.asList((boolean[])e));
|
|
else if (e instanceof Object[])
|
|
result.add(deepToList((Object[])e));
|
|
else
|
|
result.add(e);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Utility method to do a deep copy of an object *very slowly* using
|
|
// serialization/deserialization
|
|
Object deepCopy(Object oldObj) {
|
|
try {
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
|
oos.writeObject(oldObj);
|
|
oos.flush();
|
|
ByteArrayInputStream bin = new ByteArrayInputStream(
|
|
bos.toByteArray());
|
|
ObjectInputStream ois = new ObjectInputStream(bin);
|
|
return ois.readObject();
|
|
} catch(Exception e) {
|
|
throw new IllegalArgumentException(e);
|
|
}
|
|
}
|
|
|
|
//--------------------- Infrastructure ---------------------------
|
|
volatile int passed = 0, failed = 0;
|
|
void pass() {passed++;}
|
|
void fail() {failed++; Thread.dumpStack();}
|
|
void fail(String msg) {System.err.println(msg); fail();}
|
|
void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
|
void check(boolean cond) {if (cond) pass(); else fail();}
|
|
void equal(Object x, Object y) {
|
|
if (x == null ? y == null : x.equals(y)) pass();
|
|
else fail(x + " not equal to " + y);}
|
|
public static void main(String[] args) throws Throwable {
|
|
new ArrayObjectMethods().instanceMain(args);}
|
|
void instanceMain(String[] args) throws Throwable {
|
|
try {test(args);} catch (Throwable t) {unexpected(t);}
|
|
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
|
|
if (failed > 0) throw new AssertionError("Some tests failed");}
|
|
}
|
|
|
|
/**
|
|
* Methods to generate "interesting" random primitives and primitive
|
|
* arrays. Unlike Random.nextXxx, these methods return small values
|
|
* and boundary values (e.g., 0, -1, NaN) with greater than normal
|
|
* likelihood.
|
|
*/
|
|
|
|
class Rnd {
|
|
private static Random rnd = new Random();
|
|
|
|
public static long nextLong() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return 0;
|
|
case 1: return Long.MIN_VALUE;
|
|
case 2: return Long.MAX_VALUE;
|
|
case 3: case 4: case 5:
|
|
return (long) (rnd.nextInt(20) - 10);
|
|
default: return rnd.nextLong();
|
|
}
|
|
}
|
|
|
|
public static int nextInt() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return 0;
|
|
case 1: return Integer.MIN_VALUE;
|
|
case 2: return Integer.MAX_VALUE;
|
|
case 3: case 4: case 5:
|
|
return rnd.nextInt(20) - 10;
|
|
default: return rnd.nextInt();
|
|
}
|
|
}
|
|
|
|
public static short nextShort() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return 0;
|
|
case 1: return Short.MIN_VALUE;
|
|
case 2: return Short.MAX_VALUE;
|
|
case 3: case 4: case 5:
|
|
return (short) (rnd.nextInt(20) - 10);
|
|
default: return (short) rnd.nextInt();
|
|
}
|
|
}
|
|
|
|
public static char nextChar() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return 0;
|
|
case 1: return Character.MIN_VALUE;
|
|
case 2: return Character.MAX_VALUE;
|
|
case 3: case 4: case 5:
|
|
return (char) (rnd.nextInt(20) - 10);
|
|
default: return (char) rnd.nextInt();
|
|
}
|
|
}
|
|
|
|
public static byte nextByte() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return 0;
|
|
case 1: return Byte.MIN_VALUE;
|
|
case 2: return Byte.MAX_VALUE;
|
|
case 3: case 4: case 5:
|
|
return (byte) (rnd.nextInt(20) - 10);
|
|
default: return (byte) rnd.nextInt();
|
|
}
|
|
}
|
|
|
|
public static boolean nextBoolean() {
|
|
return rnd.nextBoolean();
|
|
}
|
|
|
|
public static double nextDouble() {
|
|
switch(rnd.nextInt(20)) {
|
|
case 0: return 0;
|
|
case 1: return -0.0;
|
|
case 2: return Double.MIN_VALUE;
|
|
case 3: return Double.MAX_VALUE;
|
|
case 4: return Double.NaN;
|
|
case 5: return Double.NEGATIVE_INFINITY;
|
|
case 6: return Double.POSITIVE_INFINITY;
|
|
case 7: case 8: case 9:
|
|
return (rnd.nextInt(20) - 10);
|
|
default: return rnd.nextDouble();
|
|
}
|
|
}
|
|
|
|
public static float nextFloat() {
|
|
switch(rnd.nextInt(20)) {
|
|
case 0: return 0;
|
|
case 1: return -0.0f;
|
|
case 2: return Float.MIN_VALUE;
|
|
case 3: return Float.MAX_VALUE;
|
|
case 4: return Float.NaN;
|
|
case 5: return Float.NEGATIVE_INFINITY;
|
|
case 6: return Float.POSITIVE_INFINITY;
|
|
case 7: case 8: case 9:
|
|
return (rnd.nextInt(20) - 10);
|
|
default: return rnd.nextFloat();
|
|
}
|
|
}
|
|
|
|
public static Object nextObject() {
|
|
switch(rnd.nextInt(10)) {
|
|
case 0: return null;
|
|
case 1: return "foo";
|
|
case 2: case 3: case 4:
|
|
return Double.valueOf(nextDouble());
|
|
default: return Integer.valueOf(nextInt());
|
|
}
|
|
}
|
|
|
|
public static long[] longArray(int length) {
|
|
long[] result = new long[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextLong();
|
|
return result;
|
|
}
|
|
|
|
public static int[] intArray(int length) {
|
|
int[] result = new int[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextInt();
|
|
return result;
|
|
}
|
|
|
|
public static short[] shortArray(int length) {
|
|
short[] result = new short[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextShort();
|
|
return result;
|
|
}
|
|
|
|
public static char[] charArray(int length) {
|
|
char[] result = new char[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextChar();
|
|
return result;
|
|
}
|
|
|
|
public static byte[] byteArray(int length) {
|
|
byte[] result = new byte[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextByte();
|
|
return result;
|
|
}
|
|
|
|
public static boolean[] booleanArray(int length) {
|
|
boolean[] result = new boolean[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextBoolean();
|
|
return result;
|
|
}
|
|
|
|
public static double[] doubleArray(int length) {
|
|
double[] result = new double[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextDouble();
|
|
return result;
|
|
}
|
|
|
|
public static float[] floatArray(int length) {
|
|
float[] result = new float[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextFloat();
|
|
return result;
|
|
}
|
|
|
|
public static Object[] flatObjectArray(int length) {
|
|
Object[] result = new Object[length];
|
|
for (int i = 0; i < length; i++)
|
|
result[i] = Rnd.nextObject();
|
|
return result;
|
|
}
|
|
|
|
// Calling this for length >> 100 is likely to run out of memory! It
|
|
// should be perhaps be tuned to allow for longer arrays
|
|
public static Object[] nestedObjectArray(int length) {
|
|
Object[] result = new Object[length];
|
|
for (int i = 0; i < length; i++) {
|
|
switch(rnd.nextInt(16)) {
|
|
case 0: result[i] = nestedObjectArray(length/2);
|
|
break;
|
|
case 1: result[i] = longArray(length/2);
|
|
break;
|
|
case 2: result[i] = intArray(length/2);
|
|
break;
|
|
case 3: result[i] = shortArray(length/2);
|
|
break;
|
|
case 4: result[i] = charArray(length/2);
|
|
break;
|
|
case 5: result[i] = byteArray(length/2);
|
|
break;
|
|
case 6: result[i] = floatArray(length/2);
|
|
break;
|
|
case 7: result[i] = doubleArray(length/2);
|
|
break;
|
|
case 8: result[i] = longArray(length/2);
|
|
break;
|
|
default: result[i] = Rnd.nextObject();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Primitive arrays viewed as lists. Inefficient but cool.
|
|
* This utility should be generally useful in writing regression/unit/basic
|
|
* tests.
|
|
*/
|
|
|
|
class PrimitiveArrays {
|
|
public static List<Long> asList(final long[] a) {
|
|
return new AbstractList<Long>() {
|
|
public Long get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Long set(int i, Long e) {
|
|
long oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Integer> asList(final int[] a) {
|
|
return new AbstractList<Integer>() {
|
|
public Integer get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Integer set(int i, Integer e) {
|
|
int oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Short> asList(final short[] a) {
|
|
return new AbstractList<Short>() {
|
|
public Short get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Short set(int i, Short e) {
|
|
short oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Character> asList(final char[] a) {
|
|
return new AbstractList<Character>() {
|
|
public Character get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Character set(int i, Character e) {
|
|
Character oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Byte> asList(final byte[] a) {
|
|
return new AbstractList<Byte>() {
|
|
public Byte get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Byte set(int i, Byte e) {
|
|
Byte oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Boolean> asList(final boolean[] a) {
|
|
return new AbstractList<Boolean>() {
|
|
public Boolean get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Boolean set(int i, Boolean e) {
|
|
Boolean oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Double> asList(final double[] a) {
|
|
return new AbstractList<Double>() {
|
|
public Double get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Double set(int i, Double e) {
|
|
Double oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
|
|
public static List<Float> asList(final float[] a) {
|
|
return new AbstractList<Float>() {
|
|
public Float get(int i) { return a[i]; }
|
|
public int size() { return a.length; }
|
|
|
|
public Float set(int i, Float e) {
|
|
Float oldVal = a[i];
|
|
a[i] = e;
|
|
return oldVal;
|
|
}
|
|
};
|
|
}
|
|
}
|