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 }