jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java
changeset 45319 faf6c48f1f71
parent 45318 50e95c11aa99
parent 45314 d50641964075
child 45320 eb60a37a5b98
equal deleted inserted replaced
45318:50e95c11aa99 45319:faf6c48f1f71
     1 /*
       
     2  * Copyright (c) 2014, 2015, 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 package com.oracle.testlibrary.jsr292;
       
    24 
       
    25 import jdk.testlibrary.Asserts;
       
    26 
       
    27 import java.lang.invoke.MethodHandle;
       
    28 import java.lang.invoke.MethodHandles;
       
    29 import java.lang.invoke.MethodType;
       
    30 import java.lang.reflect.Array;
       
    31 import java.util.*;
       
    32 
       
    33 public class Helper {
       
    34     /** Flag for verbose output, true if {@code -Dverbose} specified */
       
    35     public static final boolean IS_VERBOSE
       
    36             = System.getProperty("verbose") != null;
       
    37     /**
       
    38      * Flag for thorough testing -- all test will be executed,
       
    39      * true if {@code -Dthorough} specified. */
       
    40     public static final boolean IS_THOROUGH
       
    41             = System.getProperty("thorough") != null;
       
    42     /** Random number generator w/ initial seed equal to {@code -Dseed} */
       
    43     public static final Random RNG;
       
    44 
       
    45     static {
       
    46         String str = System.getProperty("seed");
       
    47         long seed = str != null ? Long.parseLong(str) : new Random().nextLong();
       
    48         RNG = new Random(seed);
       
    49         System.out.printf("-Dseed=%d%n", seed);
       
    50     }
       
    51 
       
    52     public static final long TEST_LIMIT;
       
    53     static {
       
    54         String str = System.getProperty("testLimit");
       
    55         TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2000L;
       
    56         System.out.printf("-DtestLimit=%d%n", TEST_LIMIT);
       
    57     }
       
    58 
       
    59     public static final int MAX_ARITY = 254;
       
    60     public static final String MISSING_ARG = "missingArg";
       
    61     public static final String MISSING_ARG_2 = "missingArg#2";
       
    62 
       
    63     private static final int
       
    64             // first int value
       
    65             ONE_MILLION = (1000 * 1000),
       
    66             // scale factor to reach upper 32 bits
       
    67             TEN_BILLION = (10 * 1000 * 1000 * 1000),
       
    68             // <<1 makes space for sign bit;
       
    69             INITIAL_ARG_VAL = ONE_MILLION << 1;
       
    70 
       
    71     public static final MethodHandle AS_LIST;
       
    72 
       
    73     static {
       
    74         try {
       
    75             AS_LIST = MethodHandles.lookup().findStatic(
       
    76                     Arrays.class, "asList",
       
    77                     MethodType.methodType(List.class, Object[].class));
       
    78         } catch (NoSuchMethodException | IllegalAccessException ex) {
       
    79             throw new Error(ex);
       
    80         }
       
    81     }
       
    82 
       
    83     public static boolean isDoubleCost(Class<?> aClass) {
       
    84         return aClass == double.class || aClass == long.class;
       
    85     }
       
    86 
       
    87     private static List<List<Object>> calledLog = new ArrayList<>();
       
    88     private static long nextArgVal;
       
    89 
       
    90     public static void assertCalled(String name, Object... args) {
       
    91         assertCalled(0, name, args);
       
    92     }
       
    93 
       
    94     public static void assertCalled(int lag, String name, Object... args) {
       
    95         Object expected = logEntry(name, args);
       
    96         Object actual = getCalled(lag);
       
    97         Asserts.assertEQ(expected, actual, "method call w/ lag = " + lag);
       
    98     }
       
    99 
       
   100     public static Object called(String name, Object... args) {
       
   101         List<Object> entry = logEntry(name, args);
       
   102         calledLog.add(entry);
       
   103         return entry;
       
   104     }
       
   105 
       
   106     private static List<Object> logEntry(String name, Object... args) {
       
   107         return Arrays.asList(name, Arrays.asList(args));
       
   108     }
       
   109 
       
   110     public static void clear() {
       
   111         calledLog.clear();
       
   112     }
       
   113 
       
   114     public static List<Object> getCalled(int lag) {
       
   115         int size = calledLog.size();
       
   116         return size <= lag ? null : calledLog.get(size - lag - 1);
       
   117     }
       
   118 
       
   119     public static List<Class<?>> randomClasses(Class<?>[] classes, int size) {
       
   120         List<Class<?>> result = new ArrayList<>(size);
       
   121         for (int i = 0; i < size; ++i) {
       
   122             result.add(classes[RNG.nextInt(classes.length)]);
       
   123         }
       
   124         return result;
       
   125     }
       
   126 
       
   127     public static List<Class<?>> getParams(List<Class<?>> classes,
       
   128             boolean isVararg, int argsCount) {
       
   129         boolean unmodifiable = true;
       
   130         List<Class<?>> result = classes.subList(0,
       
   131                 Math.min(argsCount, (MAX_ARITY / 2) - 1));
       
   132         int extra = 0;
       
   133         if (argsCount >= MAX_ARITY / 2) {
       
   134             result = new ArrayList<>(result);
       
   135             unmodifiable = false;
       
   136             extra = (int) result.stream().filter(Helper::isDoubleCost).count();
       
   137             int i = result.size();
       
   138             while (result.size() + extra < argsCount) {
       
   139                 Class<?> aClass = classes.get(i);
       
   140                 if (Helper.isDoubleCost(aClass)) {
       
   141                     ++extra;
       
   142                     if (result.size() + extra >= argsCount) {
       
   143                         break;
       
   144                     }
       
   145                 }
       
   146                 result.add(aClass);
       
   147             }
       
   148         }
       
   149         if (isVararg && result.size() > 0) {
       
   150             if (unmodifiable) {
       
   151                 result = new ArrayList<>(result);
       
   152             }
       
   153             int last = result.size() - 1;
       
   154             Class<?> aClass = result.get(last);
       
   155             aClass = Array.newInstance(aClass, 2).getClass();
       
   156             result.set(last, aClass);
       
   157         }
       
   158         return result;
       
   159     }
       
   160 
       
   161     public static MethodHandle addTrailingArgs(MethodHandle target, int nargs,
       
   162             List<Class<?>> classes) {
       
   163         int targetLen = target.type().parameterCount();
       
   164         int extra = (nargs - targetLen);
       
   165         if (extra <= 0) {
       
   166             return target;
       
   167         }
       
   168         List<Class<?>> fakeArgs = new ArrayList<>(extra);
       
   169         for (int i = 0; i < extra; ++i) {
       
   170             fakeArgs.add(classes.get(i % classes.size()));
       
   171         }
       
   172         return MethodHandles.dropArguments(target, targetLen, fakeArgs);
       
   173     }
       
   174 
       
   175     public static MethodHandle varargsList(int arity) {
       
   176         return AS_LIST.asCollector(Object[].class, arity);
       
   177     }
       
   178 
       
   179     private static long nextArg(boolean moreBits) {
       
   180         long val = nextArgVal++;
       
   181         long sign = -(val & 1); // alternate signs
       
   182         val >>= 1;
       
   183         if (moreBits)
       
   184         // Guarantee some bits in the high word.
       
   185         // In any case keep the decimal representation simple-looking,
       
   186         // with lots of zeroes, so as not to make the printed decimal
       
   187         // strings unnecessarily noisy.
       
   188         {
       
   189             val += (val % ONE_MILLION) * TEN_BILLION;
       
   190         }
       
   191         return val ^ sign;
       
   192     }
       
   193 
       
   194     private static int nextArg() {
       
   195         // Produce a 32-bit result something like ONE_MILLION+(smallint).
       
   196         // Example: 1_000_042.
       
   197         return (int) nextArg(false);
       
   198     }
       
   199 
       
   200     private static long nextArg(Class<?> kind) {
       
   201         if (kind == long.class || kind == Long.class ||
       
   202                 kind == double.class || kind == Double.class)
       
   203         // produce a 64-bit result something like
       
   204         // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
       
   205         // Example: 10_000_420_001_000_042.
       
   206         {
       
   207             return nextArg(true);
       
   208         }
       
   209         return (long) nextArg();
       
   210     }
       
   211 
       
   212     private static Object randomArg(Class<?> param) {
       
   213         Object wrap = castToWrapperOrNull(nextArg(param), param);
       
   214         if (wrap != null) {
       
   215             return wrap;
       
   216         }
       
   217 
       
   218         if (param.isInterface()) {
       
   219             for (Class<?> c : param.getClasses()) {
       
   220                 if (param.isAssignableFrom(c) && !c.isInterface()) {
       
   221                     param = c;
       
   222                     break;
       
   223                 }
       
   224             }
       
   225         }
       
   226         if (param.isArray()) {
       
   227             Class<?> ctype = param.getComponentType();
       
   228             Object arg = Array.newInstance(ctype, 2);
       
   229             Array.set(arg, 0, randomArg(ctype));
       
   230             return arg;
       
   231         }
       
   232         if (param.isInterface() && param.isAssignableFrom(List.class)) {
       
   233             return Arrays.asList("#" + nextArg());
       
   234         }
       
   235         if (param.isInterface() || param.isAssignableFrom(String.class)) {
       
   236             return "#" + nextArg();
       
   237         }
       
   238 
       
   239         try {
       
   240             return param.newInstance();
       
   241         } catch (InstantiationException | IllegalAccessException ex) {
       
   242         }
       
   243         return null;  // random class not Object, String, Integer, etc.
       
   244     }
       
   245 
       
   246     public static Object[] randomArgs(Class<?>... params) {
       
   247         Object[] args = new Object[params.length];
       
   248         for (int i = 0; i < args.length; i++) {
       
   249             args[i] = randomArg(params[i]);
       
   250         }
       
   251         return args;
       
   252     }
       
   253 
       
   254     public static Object[] randomArgs(int nargs, Class<?> param) {
       
   255         Object[] args = new Object[nargs];
       
   256         for (int i = 0; i < args.length; i++) {
       
   257             args[i] = randomArg(param);
       
   258         }
       
   259         return args;
       
   260     }
       
   261 
       
   262     public static Object[] randomArgs(int nargs, Class<?>... params) {
       
   263         Object[] args = new Object[nargs];
       
   264         for (int i = 0; i < args.length; i++) {
       
   265             Class<?> param = params[i % params.length];
       
   266             args[i] = randomArg(param);
       
   267         }
       
   268         return args;
       
   269     }
       
   270 
       
   271     public static Object[] randomArgs(List<Class<?>> params) {
       
   272         return randomArgs(params.toArray(new Class<?>[params.size()]));
       
   273     }
       
   274 
       
   275     public static Object castToWrapper(Object value, Class<?> dst) {
       
   276         Object wrap = null;
       
   277         if (value instanceof Number) {
       
   278             wrap = castToWrapperOrNull(((Number) value).longValue(), dst);
       
   279         }
       
   280         if (value instanceof Character) {
       
   281             wrap = castToWrapperOrNull((char) (Character) value, dst);
       
   282         }
       
   283         if (wrap != null) {
       
   284             return wrap;
       
   285         }
       
   286         return dst.cast(value);
       
   287     }
       
   288 
       
   289     @SuppressWarnings("cast")
       
   290     // primitive cast to (long) is part of the pattern
       
   291     private static Object castToWrapperOrNull(long value, Class<?> dst) {
       
   292         if (dst == int.class || dst == Integer.class) {
       
   293             return (int) (value);
       
   294         }
       
   295         if (dst == long.class || dst == Long.class) {
       
   296             return (long) (value);
       
   297         }
       
   298         if (dst == char.class || dst == Character.class) {
       
   299             return (char) (value);
       
   300         }
       
   301         if (dst == short.class || dst == Short.class) {
       
   302             return (short) (value);
       
   303         }
       
   304         if (dst == float.class || dst == Float.class) {
       
   305             return (float) (value);
       
   306         }
       
   307         if (dst == double.class || dst == Double.class) {
       
   308             return (double) (value);
       
   309         }
       
   310         if (dst == byte.class || dst == Byte.class) {
       
   311             return (byte) (value);
       
   312         }
       
   313         if (dst == boolean.class || dst == Boolean.class) {
       
   314             return ((value % 29) & 1) == 0;
       
   315         }
       
   316         return null;
       
   317     }
       
   318 
       
   319     /**
       
   320      * Routine used to obtain a randomly generated method type.
       
   321      *
       
   322      * @param arity Arity of returned method type.
       
   323      * @return MethodType generated randomly.
       
   324      */
       
   325     public static MethodType randomMethodTypeGenerator(int arity) {
       
   326         final Class<?>[] CLASSES = {
       
   327             Object.class,
       
   328             int.class,
       
   329             boolean.class,
       
   330             byte.class,
       
   331             short.class,
       
   332             char.class,
       
   333             long.class,
       
   334             float.class,
       
   335             double.class
       
   336         };
       
   337         if (arity > MAX_ARITY) {
       
   338             throw new IllegalArgumentException(
       
   339                     String.format("Arity should not exceed %d!", MAX_ARITY));
       
   340         }
       
   341         List<Class<?>> list = randomClasses(CLASSES, arity);
       
   342         list = getParams(list, false, arity);
       
   343         int i = RNG.nextInt(CLASSES.length + 1);
       
   344         Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i];
       
   345         return MethodType.methodType(rtype, list);
       
   346     }
       
   347 }