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