test/tools/javac/lambdaShapes/org/openjdk/tests/separate/TestHarness.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
equal deleted inserted replaced
-1:000000000000 0:959103a6100f
1 /*
2 * Copyright (c) 2012, 2013, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package org.openjdk.tests.separate;
27
28 import org.testng.ITestResult;
29 import org.testng.annotations.AfterMethod;
30
31 import java.lang.reflect.InvocationTargetException;
32 import java.util.Arrays;
33 import java.util.HashSet;
34 import java.util.List;
35
36 import static org.openjdk.tests.separate.SourceModel.Class;
37 import static org.openjdk.tests.separate.SourceModel.*;
38 import static org.testng.Assert.*;
39
40 public class TestHarness {
41
42 /**
43 * Creates a per-thread persistent compiler object to allow as much
44 * sharing as possible, but still allows for parallel execution of tests.
45 */
46 protected ThreadLocal<Compiler> compilerLocal = new ThreadLocal<Compiler>(){
47 protected synchronized Compiler initialValue() {
48 return new Compiler();
49 }
50 };
51
52 protected ThreadLocal<Boolean> verboseLocal = new ThreadLocal<Boolean>() {
53 protected synchronized Boolean initialValue() {
54 return Boolean.FALSE;
55 }
56 };
57
58 protected boolean verbose;
59 protected boolean canUseCompilerCache;
60 public static final String stdMethodName = SourceModel.stdMethodName;
61
62 private TestHarness() {
63 }
64
65 protected TestHarness(boolean verbose, boolean canUseCompilerCache) {
66 this.verbose = verbose;
67 this.canUseCompilerCache = canUseCompilerCache;
68 }
69
70 public void setTestVerbose() {
71 verboseLocal.set(Boolean.TRUE);
72 }
73
74 @AfterMethod
75 public void reset() {
76 if (!this.verbose) {
77 verboseLocal.set(Boolean.FALSE);
78 }
79 }
80
81 public Compiler.Flags[] compilerFlags() {
82 HashSet<Compiler.Flags> flags = new HashSet<>();
83 if (verboseLocal.get() == Boolean.TRUE) {
84 flags.add(Compiler.Flags.VERBOSE);
85 }
86 if (this.canUseCompilerCache) {
87 flags.add(Compiler.Flags.USECACHE);
88 }
89 return flags.toArray(new Compiler.Flags[0]);
90 }
91
92 @AfterMethod
93 public void printError(ITestResult result) {
94 if (result.getStatus() == ITestResult.FAILURE) {
95 String clsName = result.getTestClass().getName();
96 clsName = clsName.substring(clsName.lastIndexOf(".") + 1);
97 System.out.println("Test " + clsName + "." +
98 result.getName() + " FAILED");
99 }
100 }
101
102 private static final ConcreteMethod stdCM = ConcreteMethod.std("-1");
103 private static final AbstractMethod stdAM =
104 new AbstractMethod("int", stdMethodName);
105
106 /**
107 * Returns a class which has a static method with the same name as
108 * 'method', whose body creates an new instance of 'specimen' and invokes
109 * 'method' upon it via an invokevirtual instruction with 'args' as
110 * function call parameters.
111 *
112 * 'returns' is a dummy return value that need only match 'methods'
113 * return type (it is only used in the dummy class when compiling IV).
114 */
115 private Class invokeVirtualHarness(
116 Class specimen, ConcreteMethod method,
117 String returns, String ... args) {
118 Method cm = new ConcreteMethod(
119 method.getReturnType(), method.getName(),
120 "return " + returns + ";", method.getElements());
121 Class stub = new Class(specimen.getName(), cm);
122
123 String params = toJoinedString(args, ", ");
124
125 ConcreteMethod sm = new ConcreteMethod(
126 method.getReturnType(), method.getName(),
127 String.format("return (new %s()).%s(%s);",
128 specimen.getName(), method.getName(), params),
129 new AccessFlag("public"), new AccessFlag("static"));
130
131 Class iv = new Class("IV_" + specimen.getName(), sm);
132
133 iv.addCompilationDependency(stub);
134 iv.addCompilationDependency(cm);
135
136 return iv;
137 }
138
139 /**
140 * Returns a class which has a static method with the same name as
141 * 'method', whose body creates an new instance of 'specimen', casts it
142 * to 'iface' (including the type parameters) and invokes
143 * 'method' upon it via an invokeinterface instruction with 'args' as
144 * function call parameters.
145 */
146 private Class invokeInterfaceHarness(Class specimen, Extends iface,
147 AbstractMethod method, String ... args) {
148 Interface istub = new Interface(
149 iface.getType().getName(), iface.getType().getAccessFlags(),
150 iface.getType().getParameters(),
151 null, Arrays.asList((Method)method));
152 Class cstub = new Class(specimen.getName());
153
154 String params = toJoinedString(args, ", ");
155
156 ConcreteMethod sm = new ConcreteMethod(
157 "int", SourceModel.stdMethodName,
158 String.format("return ((%s)(new %s())).%s(%s);", iface.toString(),
159 specimen.getName(), method.getName(), params),
160 new AccessFlag("public"), new AccessFlag("static"));
161 sm.suppressWarnings();
162
163 Class ii = new Class("II_" + specimen.getName() + "_" +
164 iface.getType().getName(), sm);
165 ii.addCompilationDependency(istub);
166 ii.addCompilationDependency(cstub);
167 ii.addCompilationDependency(method);
168 return ii;
169 }
170
171
172 /**
173 * Uses 'loader' to load class 'clzz', and calls the static method
174 * 'method'. If the return value does not equal 'value' (or if an
175 * exception is thrown), then a test failure is indicated.
176 *
177 * If 'value' is null, then no equality check is performed -- the assertion
178 * fails only if an exception is thrown.
179 */
180 protected void assertStaticCallEquals(
181 ClassLoader loader, Class clzz, String method, Object value) {
182 java.lang.Class<?> cls = null;
183 try {
184 cls = java.lang.Class.forName(clzz.getName(), true, loader);
185 } catch (ClassNotFoundException e) {}
186 assertNotNull(cls);
187
188 java.lang.reflect.Method m = null;
189 try {
190 m = cls.getMethod(method);
191 } catch (NoSuchMethodException e) {}
192 assertNotNull(m);
193
194 try {
195 Object res = m.invoke(null);
196 assertNotNull(res);
197 if (value != null) {
198 assertEquals(res, value);
199 }
200 } catch (InvocationTargetException | IllegalAccessException e) {
201 fail("Unexpected exception thrown: " + e.getCause(), e.getCause());
202 }
203 }
204
205 /**
206 * Creates a class which calls target::method(args) via invokevirtual,
207 * compiles and loads both the new class and 'target', and then invokes
208 * the method. If the returned value does not match 'value' then a
209 * test failure is indicated.
210 */
211 public void assertInvokeVirtualEquals(
212 Object value, Class target, ConcreteMethod method,
213 String returns, String ... args) {
214
215 Compiler compiler = compilerLocal.get();
216 compiler.setFlags(compilerFlags());
217
218 Class iv = invokeVirtualHarness(target, method, returns, args);
219 ClassLoader loader = compiler.compile(iv, target);
220
221 assertStaticCallEquals(loader, iv, method.getName(), value);
222 compiler.cleanup();
223 }
224
225 /**
226 * Convenience method for above, which assumes stdMethodName,
227 * a return type of 'int', and no arguments.
228 */
229 public void assertInvokeVirtualEquals(int value, Class target) {
230 assertInvokeVirtualEquals(value, target, stdCM, "-1");
231 }
232
233 /**
234 * Creates a class which calls target::method(args) via invokeinterface
235 * through 'iface', compiles and loads both it and 'target', and
236 * then invokes the method. If the returned value does not match
237 * 'value' then a test failure is indicated.
238 */
239 public void assertInvokeInterfaceEquals(Object value, Class target,
240 Extends iface, AbstractMethod method, String ... args) {
241
242 Compiler compiler = compilerLocal.get();
243 compiler.setFlags(compilerFlags());
244
245 Class ii = invokeInterfaceHarness(target, iface, method, args);
246 ClassLoader loader = compiler.compile(ii, target);
247
248 assertStaticCallEquals(loader, ii, method.getName(), value);
249 compiler.cleanup();
250 }
251
252 /**
253 * Convenience method for above, which assumes stdMethodName,
254 * a return type of 'int', and no arguments.
255 */
256 public void assertInvokeInterfaceEquals(
257 int value, Class target, Interface iface) {
258
259 Compiler compiler = compilerLocal.get();
260 compiler.setFlags(compilerFlags());
261
262 assertInvokeInterfaceEquals(value, target, new Extends(iface), stdAM);
263
264 compiler.cleanup();
265 }
266
267 protected void assertInvokeInterfaceThrows(java.lang.Class<? extends Throwable> errorClass,
268 Class target, Extends iface, AbstractMethod method,
269 String... args) {
270 try {
271 assertInvokeInterfaceEquals(0, target, iface, method, args);
272 fail("Expected exception: " + errorClass);
273 }
274 catch (AssertionError e) {
275 Throwable cause = e.getCause();
276 if (cause == null)
277 throw e;
278 else if ((errorClass.isAssignableFrom(cause.getClass()))) {
279 // this is success
280 return;
281 }
282 else
283 throw e;
284 }
285 }
286
287 /**
288 * Creates a class which calls target::method(args) via invokevirtual,
289 * compiles and loads both the new class and 'target', and then invokes
290 * the method. If an exception of type 'exceptionType' is not thrown,
291 * then a test failure is indicated.
292 */
293 public void assertThrows(java.lang.Class<?> exceptionType, Class target,
294 ConcreteMethod method, String returns, String ... args) {
295
296 Compiler compiler = compilerLocal.get();
297 compiler.setFlags(compilerFlags());
298
299 Class iv = invokeVirtualHarness(target, method, returns, args);
300 ClassLoader loader = compiler.compile(iv, target);
301
302 java.lang.Class<?> cls = null;
303 try {
304 cls = java.lang.Class.forName(iv.getName(), true, loader);
305 } catch (ClassNotFoundException e) {}
306 assertNotNull(cls);
307
308 java.lang.reflect.Method m = null;
309 try {
310 m = cls.getMethod(method.getName());
311 } catch (NoSuchMethodException e) {}
312 assertNotNull(m);
313
314 try {
315 m.invoke(null);
316 fail("Exception should have been thrown");
317 } catch (InvocationTargetException | IllegalAccessException e) {
318 if (verboseLocal.get() == Boolean.TRUE) {
319 System.out.println(e.getCause());
320 }
321 assertTrue(exceptionType.isAssignableFrom(e.getCause().getClass()));
322 }
323 compiler.cleanup();
324 }
325
326 /**
327 * Convenience method for above, which assumes stdMethodName,
328 * a return type of 'int', and no arguments.
329 */
330 public void assertThrows(java.lang.Class<?> exceptionType, Class target) {
331 assertThrows(exceptionType, target, stdCM, "-1");
332 }
333
334 private static <T> String toJoinedString(T[] a, String... p) {
335 return toJoinedString(Arrays.asList(a), p);
336 }
337
338 private static <T> String toJoinedString(List<T> list, String... p) {
339 StringBuilder sb = new StringBuilder();
340 String sep = "";
341 String init = "";
342 String end = "";
343 String empty = null;
344 switch (p.length) {
345 case 4:
346 empty = p[3];
347 /*fall-through*/
348 case 3:
349 end = p[2];
350 /*fall-through*/
351 case 2:
352 init = p[1];
353 /*fall-through*/
354 case 1:
355 sep = p[0];
356 break;
357 }
358 if (empty != null && list.isEmpty()) {
359 return empty;
360 } else {
361 sb.append(init);
362 for (T x : list) {
363 if (sb.length() != init.length()) {
364 sb.append(sep);
365 }
366 sb.append(x.toString());
367 }
368 sb.append(end);
369 return sb.toString();
370 }
371 }
372 }

mercurial