1 /*
   2  * Copyright (c) 2014, 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 }