jdk/test/java/util/Arrays/CopyMethods.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2005 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     4655503
       
    27  * @summary Test for array cloning and slicing methods.
       
    28  * @author  John Rose
       
    29  */
       
    30 
       
    31 import java.util.*;
       
    32 import java.lang.reflect.*;
       
    33 
       
    34 public class CopyMethods {
       
    35     static int muzzle;  // if !=0, suppresses ("muzzles") messages
       
    36 
       
    37     static int maxLen = 40;  // maximum length of test arrays
       
    38     static int shortStepsNear = 4;  // interesting span near critical values
       
    39     static int downShift = 3;
       
    40 
       
    41     static int testCasesRun = 0;
       
    42     static long consing = 0;
       
    43 
       
    44     // very simple tests, mainly to test the framework itself
       
    45     static void simpleTests() {
       
    46         int[] a = (int[]) makeArray(3, int.class);
       
    47         if (muzzle == 0)
       
    48             System.out.println("int[] a = "+Arrays.toString(a));
       
    49         check(a.length == 3);
       
    50         check(a[0] == testValues[0]);
       
    51         check(a[1] == testValues[1]);
       
    52         check(a[2] == testValues[2]);
       
    53         checkArray(a, int.class, 3, 0, 3);
       
    54         // negative test of testing framework:
       
    55         for (int bad = -2; bad < a.length; bad++) {
       
    56             try {
       
    57                 int[] aa = a.clone();
       
    58                 if (bad < 0)  aa = new int[4];
       
    59                 else          aa[bad] = 0;
       
    60                 ++muzzle;
       
    61                 // the following check should fail!
       
    62                 if (bad == -2)
       
    63                     checkArray(new String[3], int.class, 0, 0, a.length);
       
    64                 else
       
    65                     checkArray(aa, int.class, 0, 0, a.length);
       
    66                 throw new Error("Should Not Reach Here");
       
    67             } catch (RuntimeException ee) {
       
    68                 --muzzle;
       
    69                 if (muzzle == 0)
       
    70                     System.out.println("Expected: "+ee);
       
    71             }
       
    72         }
       
    73         checkArray(Arrays.copyOf(a, 0), int.class, 0, 0, 3);
       
    74         checkArray(Arrays.copyOf(a, 1), int.class, 1, 0, 3);
       
    75         checkArray(Arrays.copyOf(a, 2), int.class, 2, 0, 3);
       
    76         checkArray(Arrays.copyOf(a, 3), int.class, 3, 0, 3);
       
    77         checkArray(Arrays.copyOf(a, 4), int.class, 4, 0, 3);
       
    78 
       
    79         // quick test of copyOfRange
       
    80         int[] ar = Arrays.copyOfRange(a, 1, 3);
       
    81         check(ar.length == 2);
       
    82         check(ar[0] == a[1]);
       
    83         check(ar[1] == a[2]);
       
    84         checkArray(ar, int.class, 2, 1, 2);
       
    85         ar = Arrays.copyOfRange(a, 2, 4);
       
    86         check(ar.length == 2);
       
    87         check(ar[0] == a[2]);
       
    88         check(ar[1] == 0);
       
    89         checkArray(ar, int.class, 2, 2, 1);
       
    90         ar = Arrays.copyOfRange(a, 3, 5);
       
    91         check(ar.length == 2);
       
    92         check(ar[0] == 0);
       
    93         check(ar[1] == 0);
       
    94         checkArray(ar, int.class, 2, 3, 0);
       
    95         byte[] ba = (byte[]) makeArray(3, byte.class);
       
    96         if (muzzle == 0)
       
    97             System.out.println("byte[] ba = "+Arrays.toString(ba));
       
    98         for (int j = 0; j <= ba.length+2; j++) {
       
    99             byte[] bb = Arrays.copyOf(ba, j);
       
   100             if (muzzle == 0)
       
   101                 System.out.println("copyOf(ba,"+j+") = "+
       
   102                                    Arrays.toString(bb));
       
   103             checkArray(bb, byte.class, j, 0, ba.length);
       
   104             byte[] bbr = Arrays.copyOfRange(ba, 0, j);
       
   105             check(Arrays.equals(bb, bbr));
       
   106         }
       
   107         for (int i = 0; i <= a.length; i++) {
       
   108             for (int j = i; j <= a.length+2; j++) {
       
   109                 byte[] br = Arrays.copyOfRange(ba, i, j);
       
   110                 if (muzzle == 0)
       
   111                     System.out.println("copyOfRange(ba,"+i+","+j+") = "+
       
   112                                        Arrays.toString(br));
       
   113                 checkArray(br, byte.class, j-i, i, ba.length-i);
       
   114             }
       
   115         }
       
   116         String[] sa = (String[]) makeArray(3, String.class);
       
   117         if (muzzle == 0)
       
   118             System.out.println("String[] sa = "+Arrays.toString(sa));
       
   119         check(sa[0].equals(Integer.toHexString(testValues[0])));
       
   120         check(sa[1].equals(Integer.toHexString(testValues[1])));
       
   121         check(sa[2].equals(Integer.toHexString(testValues[2])));
       
   122         checkArray(sa, String.class, sa.length, 0, sa.length);
       
   123         String[] sa4 = Arrays.copyOf(sa, sa.length+1);
       
   124         check(sa4[0] == sa[0]);
       
   125         check(sa4[1] == sa[1]);
       
   126         check(sa4[2] == sa[2]);
       
   127         check(sa4[sa.length] == null);
       
   128         checkArray(sa4, String.class, sa4.length, 0, sa.length);
       
   129         String[] sr4 = Arrays.copyOfRange(sa, 1, 5);
       
   130         check(sr4[0] == sa[1]);
       
   131         check(sr4[1] == sa[2]);
       
   132         check(sr4[2] == null);
       
   133         check(sr4[3] == null);
       
   134         checkArray(sr4, String.class, 4, 1, sa.length-1);
       
   135         if (muzzle == 0)
       
   136             System.out.println("simpleTests done");
       
   137     }
       
   138 
       
   139     // the framework:  a fixed series of test values
       
   140     static final int[] testValues;
       
   141     static {
       
   142         testValues = new int[1000];
       
   143         Random r = new Random();
       
   144         for (int i = 0; i < testValues.length; i++) {
       
   145             testValues[i] = r.nextInt();
       
   146         }
       
   147     }
       
   148     /** Return a canonical test value of a desired index and type.
       
   149      *  The original test values are random ints.  Derive other test
       
   150      *  values as follows:
       
   151      *  <pre>
       
   152      *  int tv = testValues[i]
       
   153      *  (C)tv                    C is byte, short, char, long, float, double
       
   154      *  (tv&1)!=0                C is boolean
       
   155      *  (Integer)tv              C is Object and tv%16 != 0
       
   156      *  null                     C is Object and tv%16 == 0
       
   157      *  Integer.toHexString(tv)  C is String and tv != 0
       
   158      *  null                     C is String and tv == 0
       
   159      *  </pre>
       
   160      *  are derived by ordinary Java coercions, except that boolean
       
   161      *  samples the LSB of the int value, and String is the hex numeral.
       
   162      *
       
   163      *  (Also, the 0th String is null, and the 0th Object mod 16 is null,
       
   164      *  regardless of the original int test value.)
       
   165      */
       
   166     static Object testValue(int i, Class<?> c) {
       
   167         int tv = testValues[i % testValues.length];
       
   168         if (i >= testValues.length)  tv ^= i;
       
   169         // Turn the canonical int to a float, boolean, String, whatever:
       
   170         return invoke(coercers.get(c), tv);
       
   171     }
       
   172     /** Build a test array of the given length,
       
   173      *  packed with a subsequence of the test values.
       
   174      *  The first element of the array is always testValue(0).
       
   175      */
       
   176     static Object makeArray(int len, Class<?> c) {
       
   177         Object a = Array.newInstance(c, len);
       
   178         for (int i = 0; i < len; i++) {
       
   179             Array.set(a, i, testValue(i, c));
       
   180         }
       
   181         return a;
       
   182     }
       
   183     /** Check that the given array has the required length.
       
   184      *  Check also that it is packed, up to firstNull, with
       
   185      *  a particular subsequence of the canonical test values.
       
   186      *  The subsequence must begin with a[0] == testValue(offset).
       
   187      *  At a[firstNull] and beyond, the array must contain null values.
       
   188      */
       
   189     static void checkArray(Object a, Class<?> c, int requiredLen, int offset, int firstNull) {
       
   190         check(c == a.getClass().getComponentType());
       
   191         Object nullValue = nullValues.get(c);
       
   192         // Note:  asserts in here are not part of the test program.
       
   193         // They verify the integrity of the test method itself.
       
   194         assert(nullValues.containsKey(c));
       
   195 
       
   196         int misses = 0;
       
   197         int firstMiss = -1;
       
   198         // Check required length first.
       
   199         int length = Array.getLength(a);
       
   200         if (length != requiredLen && requiredLen != -1) {
       
   201             if (muzzle == 0)
       
   202                 System.out.println("*** a.length = "+length+" != "+requiredLen);
       
   203             ++misses;
       
   204         }
       
   205 
       
   206         for (int i = 0; i < length; i++) {
       
   207             Object tv = (i >= firstNull) ? nullValue : testValue(i+offset, c);
       
   208             Object ai = Array.get(a, i);
       
   209             if (!eq(ai, tv)) {
       
   210                 if (muzzle == 0)
       
   211                     System.out.println("*** a["+i+"] = "+ai+" != "+tv);
       
   212                 if (misses == 0)  firstMiss = i;
       
   213                 if (++misses > 10)  break;
       
   214             }
       
   215         }
       
   216         if (misses != 0) {
       
   217             Method toString = toStrings.get(c);
       
   218             if (toString == null)  toString = toStrings.get(Object.class);
       
   219             throw new RuntimeException("checkArray failed at "+firstMiss
       
   220                                        +" "+c+"[]"
       
   221                                        +" : "+invoke(toString, a));
       
   222         }
       
   223     }
       
   224     // Typical comparison helper.  Why isn't this a method somewhere.
       
   225     static boolean eq(Object x, Object y) {
       
   226         return x == null? y == null: x.equals(y);
       
   227     }
       
   228     // Exception-ignoring invoke function.
       
   229     static Object invoke(Method m, Object... args) {
       
   230         Exception ex;
       
   231         try {
       
   232             return m.invoke(null, args);
       
   233         } catch (InvocationTargetException ee) {
       
   234             ex = ee;
       
   235         } catch (IllegalAccessException ee) {
       
   236             ex = ee;
       
   237         } catch (IllegalArgumentException ee) {
       
   238             ex = ee;
       
   239         }
       
   240         ArrayList<Object> call = new ArrayList<Object>();
       
   241         call.add(m); Collections.addAll(call, args);
       
   242         throw new RuntimeException(call+" : "+ex);
       
   243     }
       
   244     // version of assert() that runs unconditionally
       
   245     static void check(boolean z) {
       
   246         if (!z)  throw new RuntimeException("check failed");
       
   247     }
       
   248 
       
   249 
       
   250     /** Run about 10**5 distinct parameter combinations
       
   251      *  on copyOf and copyOfRange.  Use all primitive types,
       
   252      *  and String and Object.
       
   253      *  Try to all critical values, looking for fencepost errors.
       
   254      */
       
   255     static void fullTests(int maxLen, Class<?> c) {
       
   256         Method cloner      = cloners.get(c);
       
   257         assert(cloner != null) : c;
       
   258         Method cloneRanger = cloneRangers.get(c);
       
   259         // Note:  asserts in here are not part of the test program.
       
   260         // They verify the integrity of the test method itself.
       
   261         assert(cloneRanger != null) : c;
       
   262         for (int src = 0; src <= maxLen; src = inc(src, 0, maxLen)) {
       
   263             Object a = makeArray(src, c);
       
   264             for (int x : new ArrayList<Integer>()) {}
       
   265             for (int j = 0; j <= maxLen; j = inc(j, src, maxLen)) {
       
   266                 // b = Arrays.copyOf(a, j);
       
   267                 Object b = invoke(cloner, a, j);
       
   268                 checkArray(b, c, j, 0, src);
       
   269                 testCasesRun++;
       
   270                 consing += j;
       
   271 
       
   272                 int maxI = Math.min(src, j);
       
   273                 for (int i = 0; i <= maxI; i = inc(i, src, maxI)) {
       
   274                     // r = Arrays.copyOfRange(a, i, j);
       
   275                     Object r = invoke(cloneRanger, a, i, j);
       
   276                     checkArray(r, c, j-i, i, src-i);
       
   277                     //System.out.println("case c="+c+" src="+src+" i="+i+" j="+j);
       
   278                     testCasesRun++;
       
   279                     consing += j-i;
       
   280                 }
       
   281             }
       
   282         }
       
   283     }
       
   284     // Increment x by at least one.  Increment by a little more unless
       
   285     // it is near a critical value, either zero, crit1, or crit2.
       
   286     static int inc(int x, int crit1, int crit2) {
       
   287         int D = shortStepsNear;
       
   288         if (crit1 > crit2) { int t = crit1; crit1 = crit2; crit2 = t; }
       
   289         assert(crit1 <= crit2);
       
   290         assert(x <= crit2);  // next1 or next2 must be the limit value
       
   291         x += 1;
       
   292         if (x > D) {
       
   293             if (x < crit1-D) {
       
   294                 x += (x << 1) >> downShift;  // giant step toward crit1-D
       
   295                 if (x > crit1-D)  x = crit1-D;
       
   296             } else if (x >= crit1+D && x < crit2-D) {
       
   297                 x += (x << 1) >> downShift;  // giant step toward crit2-D
       
   298                 if (x > crit2-D)  x = crit2-D;
       
   299             }
       
   300         }
       
   301         return x;
       
   302     }
       
   303 
       
   304     public static void main(String[] av) {
       
   305         boolean verbose = (av.length != 0);
       
   306         muzzle = (verbose? 0: 1);
       
   307         if (muzzle == 0)
       
   308             System.out.println("test values: "+Arrays.toString(Arrays.copyOf(testValues, 5))+"...");
       
   309 
       
   310         simpleTests();
       
   311 
       
   312         muzzle = 0;  // turn on print statements (affects failures only)
       
   313 
       
   314         fullTests();
       
   315         if (verbose)
       
   316             System.out.println("ran "+testCasesRun+" tests, avg len="
       
   317                                +(float)consing/testCasesRun);
       
   318 
       
   319         // test much larger arrays, more sparsely
       
   320         maxLen = 500;
       
   321         shortStepsNear = 2;
       
   322         downShift = 0;
       
   323         testCasesRun = 0;
       
   324         consing = 0;
       
   325         fullTests();
       
   326         if (verbose)
       
   327             System.out.println("ran "+testCasesRun+" tests, avg len="
       
   328                                +(float)consing/testCasesRun);
       
   329     }
       
   330 
       
   331     static void fullTests() {
       
   332         for (Class<?> c : allTypes) {
       
   333             fullTests(maxLen, c);
       
   334         }
       
   335     }
       
   336 
       
   337     // We must run all the our tests on each of 8 distinct primitive types,
       
   338     // and two reference types (Object, String) for good measure.
       
   339     // This would be a pain to write out by hand, statically typed.
       
   340     // So, use reflection.  Following are the tables of methods we use.
       
   341     // (The initial simple tests exercise enough of the static typing
       
   342     // features of the API to ensure that they compile as advertised.)
       
   343 
       
   344     static Object  coerceToObject(int x) { return (x & 0xF) == 0? null: new Integer(x); }
       
   345     static String  coerceToString(int x) { return (x == 0)? null: Integer.toHexString(x); }
       
   346     static Integer coerceToInteger(int x) { return (x == 0)? null: x; }
       
   347     static byte    coerceToByte(int x) { return (byte)x; }
       
   348     static short   coerceToShort(int x) { return (short)x; }
       
   349     static int     coerceToInt(int x) { return x; }
       
   350     static long    coerceToLong(int x) { return x; }
       
   351     static char    coerceToChar(int x) { return (char)x; }
       
   352     static float   coerceToFloat(int x) { return x; }
       
   353     static double  coerceToDouble(int x) { return x; }
       
   354     static boolean coerceToBoolean(int x) { return (x&1) != 0; }
       
   355 
       
   356     static Integer[] copyOfIntegerArray(Object[] a, int len) {
       
   357         // This guy exercises the API based on a type-token.
       
   358         // Note the static typing.
       
   359         return Arrays.copyOf(a, len, Integer[].class);
       
   360     }
       
   361     static Integer[] copyOfIntegerArrayRange(Object[] a, int m, int n) {
       
   362         // This guy exercises the API based on a type-token.
       
   363         // Note the static typing.
       
   364         return Arrays.copyOfRange(a, m, n, Integer[].class);
       
   365     }
       
   366 
       
   367     static final List<Class<?>> allTypes
       
   368         = Arrays.asList(new Class<?>[]
       
   369                         {   Object.class, String.class, Integer.class,
       
   370                             byte.class, short.class, int.class, long.class,
       
   371                             char.class, float.class, double.class,
       
   372                             boolean.class
       
   373                         });
       
   374     static final HashMap<Class<?>,Method> coercers;
       
   375     static final HashMap<Class<?>,Method> cloners;
       
   376     static final HashMap<Class<?>,Method> cloneRangers;
       
   377     static final HashMap<Class<?>,Method> toStrings;
       
   378     static final HashMap<Class<?>,Object> nullValues;
       
   379     static {
       
   380         coercers = new HashMap<Class<?>,Method>();
       
   381         Method[] testMethods = CopyMethods.class.getDeclaredMethods();
       
   382         Method cia = null, ciar = null;
       
   383         for (int i = 0; i < testMethods.length; i++) {
       
   384             Method m = testMethods[i];
       
   385             if (!Modifier.isStatic(m.getModifiers()))  continue;
       
   386             Class<?> rt = m.getReturnType();
       
   387             if (m.getName().startsWith("coerceTo") && allTypes.contains(rt))
       
   388                 coercers.put(m.getReturnType(), m);
       
   389             if (m.getName().equals("copyOfIntegerArray"))
       
   390                 cia = m;
       
   391             if (m.getName().equals("copyOfIntegerArrayRange"))
       
   392                 ciar = m;
       
   393         }
       
   394         Method[] arrayMethods = Arrays.class.getDeclaredMethods();
       
   395         cloners      = new HashMap<Class<?>,Method>();
       
   396         cloneRangers = new HashMap<Class<?>,Method>();
       
   397         toStrings    = new HashMap<Class<?>,Method>();
       
   398         for (int i = 0; i < arrayMethods.length; i++) {
       
   399             Method m = arrayMethods[i];
       
   400             if (!Modifier.isStatic(m.getModifiers()))  continue;
       
   401             Class<?> rt = m.getReturnType();
       
   402             if (m.getName().equals("copyOf")
       
   403                 && m.getParameterTypes().length == 2)
       
   404                 cloners.put(rt.getComponentType(), m);
       
   405             if (m.getName().equals("copyOfRange")
       
   406                 && m.getParameterTypes().length == 3)
       
   407                 cloneRangers.put(rt.getComponentType(), m);
       
   408             if (m.getName().equals("toString")) {
       
   409                 Class<?> pt = m.getParameterTypes()[0];
       
   410                 toStrings.put(pt.getComponentType(), m);
       
   411             }
       
   412         }
       
   413         cloners.put(String.class, cloners.get(Object.class));
       
   414         cloneRangers.put(String.class, cloneRangers.get(Object.class));
       
   415         assert(cia != null);
       
   416         cloners.put(Integer.class, cia);
       
   417         assert(ciar != null);
       
   418         cloneRangers.put(Integer.class, ciar);
       
   419         nullValues = new HashMap<Class<?>,Object>();
       
   420         for (Class<?> c : allTypes) {
       
   421             nullValues.put(c, invoke(coercers.get(c), 0));
       
   422         }
       
   423     }
       
   424 }