1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.core.tests.util;
15 
16 import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
17 import org.eclipse.jdt.core.tests.runtime.*;
18 import java.io.*;
19 import java.net.*;
20 /**
21  * Verifies that the .class files resulting from a compilation can be loaded
22  * in a VM and that they can be run.
23  */
24 public class TestVerifier {
25 	public String failureReason;
26 
27 	boolean reuseVM = true;
28 	String[] classpathCache;
29 	LocalVirtualMachine vm;
30 	StringBuffer outputBuffer;
31 	StringBuffer errorBuffer;
32 	Socket socket;
TestVerifier(boolean reuseVM)33 public TestVerifier(boolean reuseVM) {
34 	this.reuseVM = reuseVM;
35 }
checkBuffers(String outputString, String errorString, String sourceFileName, String expectedOutputString, String expectedErrorStringStart)36 private boolean checkBuffers(String outputString, String errorString,
37 		String sourceFileName, String expectedOutputString, String expectedErrorStringStart) {
38 	boolean didMatchExpectation = true;
39 	String platformIndependantString;
40 	this.failureReason = null;
41 	if (expectedOutputString != null) {
42 		platformIndependantString = Util.convertToIndependantLineDelimiter(outputString.trim());
43 		if (!Util.convertToIndependantLineDelimiter(expectedOutputString).equals(platformIndependantString)) {
44 			System.out.println(Util.displayString(platformIndependantString, 2));
45 			this.failureReason =
46 				"Unexpected output running resulting class file for "
47 					+ sourceFileName
48 					+ ":\n"
49 					+ "--[START]--\n"
50 					+ outputString
51 					+ "---[END]---\n";
52 			didMatchExpectation = false;
53 		}
54 	}
55 	String trimmedErrorString = errorString.trim();
56 	if (expectedErrorStringStart != null) {
57 		platformIndependantString = Util.convertToIndependantLineDelimiter(trimmedErrorString);
58 		if (expectedErrorStringStart.length() == 0 && platformIndependantString.length() > 0 ||
59 				!platformIndependantString.startsWith(Util.convertToIndependantLineDelimiter(expectedErrorStringStart))) {
60 			/*
61 			 * This is an opportunistic heuristic for error strings comparison:
62 			 * - null means skip test;
63 			 * - empty means exactly empty;
64 			 * - other means starts with.
65 			 * If this became insufficient, we could envision using specific
66 			 * matchers for specific needs.
67 			 */
68 			System.out.println(Util.displayString(platformIndependantString, 2));
69 			this.failureReason =
70 				"Unexpected error running resulting class file for "
71 					+ sourceFileName
72 					+ ":\n"
73 					+ "--[START]--\n"
74 					+ errorString
75 					+ "---[END]---\n";
76 			didMatchExpectation = false;
77 		}
78 	} else if (trimmedErrorString.length() != 0){
79 		platformIndependantString = Util.convertToIndependantLineDelimiter(trimmedErrorString);
80 		System.out.println(Util.displayString(platformIndependantString, 2));
81 		this.failureReason =
82 			"Unexpected error running resulting class file for "
83 				+ sourceFileName
84 				+ ":\n"
85 				+ "--[START]--\n"
86 				+ errorString
87 				+ "---[END]---\n";
88 		didMatchExpectation = false;
89 	}
90 	return didMatchExpectation;
91 }
92 
checkBuffersThrowingError(String errorString, String sourceFileName, String expectedSuccessOutputString)93 private boolean checkBuffersThrowingError(String errorString, String sourceFileName, String expectedSuccessOutputString) {
94 
95 	if (errorString.length() > 0 && errorString.indexOf(expectedSuccessOutputString) != -1) {
96 		return true;
97 	}
98 
99 	this.failureReason =
100 		"Expected error not thrown for "
101 			+ sourceFileName
102 			+ ":\n"
103 			+ expectedSuccessOutputString;
104 	return false;
105 }
106 
compileVerifyTests(String verifierDir)107 private void compileVerifyTests(String verifierDir) {
108 	String fullyQualifiedName = VerifyTests.class.getName();
109 
110 	int lastDot = fullyQualifiedName.lastIndexOf('.');
111 	String packageName = fullyQualifiedName.substring(0, lastDot);
112 	String simpleName = fullyQualifiedName.substring(lastDot + 1);
113 
114 	String dirName = verifierDir.replace('\\', '/') + "/" + packageName.replace('.', '/');
115 	File dir = new File(dirName.replace('/', File.separatorChar));
116 	if (!dir.exists() && !dir.mkdirs()) {
117 		System.out.println("Could not create " + dir);
118 		return;
119 	}
120 	String fileName = dir + File.separator + simpleName + ".java";
121 	Util.writeToFile(getVerifyTestsCode(), fileName);
122 	BatchCompiler.compile("\"" + fileName + "\" -d \"" + verifierDir + "\" -warn:-resource -classpath \"" + Util.getJavaClassLibsAsString() + "\"", new PrintWriter(System.out), new PrintWriter(System.err), null/*progress*/);
123 }
execute(String className, String[] classpaths)124 public void execute(String className, String[] classpaths) {
125 	this.outputBuffer = new StringBuffer();
126 	this.errorBuffer = new StringBuffer();
127 
128 	launchAndRun(className, classpaths, null, null);
129 }
130 @Override
finalize()131 protected void finalize() throws Throwable {
132 	shutDown();
133 }
getExecutionOutput()134 public String getExecutionOutput(){
135 	return this.outputBuffer.toString();
136 }
137 
getExecutionError()138 public String getExecutionError(){
139 	return this.errorBuffer.toString();
140 }
141 /**
142  * Returns the code of the VerifyTests class.
143  *
144  * IMPORTANT NOTE: DO NOTE EDIT BUT GENERATE INSTEAD (see below)
145  *
146  * To generate:
147  * - export VerifyTests.java to d:/temp
148  * - inspect org.eclipse.jdt.core.tests.util.Util.fileContentToDisplayString("d:/temp/VerifyTests.java", 2, true)
149  */
getVerifyTestsCode()150 private String getVerifyTestsCode() {
151 	return
152 		"/*******************************************************************************\n" +
153 		" * Copyright (c) 2000, 2017 IBM Corporation and others.\n" +
154 		" * All rights reserved. This program and the accompanying materials\n" +
155 		" * are made available under the terms of the Eclipse Public License v1.0\n" +
156 		" * which accompanies this distribution, and is available at\n" +
157 		" * http://www.eclipse.org/legal/epl-v10.html\n" +
158 		" *\n" +
159 		" * Contributors:\n" +
160 		" *     IBM Corporation - initial API and implementation\n" +
161 		" *******************************************************************************/\n" +
162 		"package org.eclipse.jdt.core.tests.util;\n" +
163 		"\n" +
164 		"import java.io.DataInputStream;\n" +
165 		"import java.io.DataOutputStream;\n" +
166 		"import java.io.File;\n" +
167 		"import java.io.FileInputStream;\n" +
168 		"import java.io.FileNotFoundException;\n" +
169 		"import java.io.IOException;\n" +
170 		"import java.io.InputStream;\n" +
171 		"import java.lang.reflect.InvocationTargetException;\n" +
172 		"import java.lang.reflect.Method;\n" +
173 		"import java.net.Socket;\n" +
174 		"import java.util.StringTokenizer;\n" +
175 		"\n" +
176 		"/******************************************************\n" +
177 		" *\n" +
178 		" * IMPORTANT NOTE: If modifying this class, copy the source to TestVerifier#getVerifyTestsCode()\n" +
179 		" * (see this method for details)\n" +
180 		" *\n" +
181 		" ******************************************************/\n" +
182 		"\n" +
183 		"public class VerifyTests {\n" +
184 		"	int portNumber;\n" +
185 		"	Socket socket;\n" +
186 		"\n" +
187 		"/**\n" +
188 		" * NOTE: Code copied from junit.util.TestCaseClassLoader.\n" +
189 		" *\n" +
190 		" * A custom class loader which enables the reloading\n" +
191 		" * of classes for each test run. The class loader\n" +
192 		" * can be configured with a list of package paths that\n" +
193 		" * should be excluded from loading. The loading\n" +
194 		" * of these packages is delegated to the system class\n" +
195 		" * loader. They will be shared across test runs.\n" +
196 		" * <p>\n" +
197 		" * The list of excluded package paths is specified in\n" +
198 		" * a properties file \"excluded.properties\" that is located in\n" +
199 		" * the same place as the TestCaseClassLoader class.\n" +
200 		" * <p>\n" +
201 		" * <b>Known limitation:</b> the VerifyClassLoader cannot load classes\n" +
202 		" * from jar files.\n" +
203 		" */\n" +
204 		"\n" +
205 		"\n" +
206 		"public class VerifyClassLoader extends ClassLoader {\n" +
207 		"	/** scanned class path */\n" +
208 		"	private String[] pathItems;\n" +
209 		"\n" +
210 		"	/** excluded paths */\n" +
211 		"	private String[] excluded= {};\n" +
212 		"\n" +
213 		"	/**\n" +
214 		"	 * Constructs a VerifyClassLoader. It scans the class path\n" +
215 		"	 * and the excluded package paths\n" +
216 		"	 */\n" +
217 		"	public VerifyClassLoader() {\n" +
218 		"		super();\n" +
219 		"		String classPath= System.getProperty(\"java.class.path\");\n" +
220 		"		String separator= System.getProperty(\"path.separator\");\n" +
221 		"\n" +
222 		"		// first pass: count elements\n" +
223 		"		StringTokenizer st= new StringTokenizer(classPath, separator);\n" +
224 		"		int i= 0;\n" +
225 		"		while (st.hasMoreTokens()) {\n" +
226 		"			st.nextToken();\n" +
227 		"			i++;\n" +
228 		"		}\n" +
229 		"		// second pass: split\n" +
230 		"		this.pathItems= new String[i];\n" +
231 		"		st= new StringTokenizer(classPath, separator);\n" +
232 		"		i= 0;\n" +
233 		"		while (st.hasMoreTokens()) {\n" +
234 		"			this.pathItems[i++]= st.nextToken();\n" +
235 		"		}\n" +
236 		"\n" +
237 		"	}\n" +
238 		"	public java.net.URL getResource(String name) {\n" +
239 		"		return ClassLoader.getSystemResource(name);\n" +
240 		"	}\n" +
241 		"	public InputStream getResourceAsStream(String name) {\n" +
242 		"		return ClassLoader.getSystemResourceAsStream(name);\n" +
243 		"	}\n" +
244 		"	protected boolean isExcluded(String name) {\n" +
245 		"		// exclude the \"java\" packages.\n" +
246 		"		// They always need to be excluded so that they are loaded by the system class loader\n" +
247 		"		if (name.startsWith(\"java\") || name.startsWith(\"[Ljava\"))\n" +
248 		"			return true;\n" +
249 		"\n" +
250 		"		// exclude the user defined package paths\n" +
251 		"		for (int i= 0; i < this.excluded.length; i++) {\n" +
252 		"			if (name.startsWith(this.excluded[i])) {\n" +
253 		"				return true;\n" +
254 		"			}\n" +
255 		"		}\n" +
256 		"		return false;\n" +
257 		"	}\n" +
258 		"	public synchronized Class loadClass(String name, boolean resolve)\n" +
259 		"		throws ClassNotFoundException {\n" +
260 		"\n" +
261 		"		Class c= findLoadedClass(name);\n" +
262 		"		if (c != null)\n" +
263 		"			return c;\n" +
264 		"		//\n" +
265 		"		// Delegate the loading of excluded classes to the\n" +
266 		"		// standard class loader.\n" +
267 		"		//\n" +
268 		"		if (isExcluded(name)) {\n" +
269 		"			try {\n" +
270 		"				c= findSystemClass(name);\n" +
271 		"				return c;\n" +
272 		"			} catch (ClassNotFoundException e) {\n" +
273 		"				// keep searching\n" +
274 		"			}\n" +
275 		"		}\n" +
276 		"		File file= locate(name);\n" +
277 		"		if (file == null)\n" +
278 		"			throw new ClassNotFoundException();\n" +
279 		"		byte data[]= loadClassData(file);\n" +
280 		"		c= defineClass(name, data, 0, data.length);\n" +
281 		"		if (resolve)\n" +
282 		"			resolveClass(c);\n" +
283 		"		return c;\n" +
284 		"	}\n" +
285 		"	private byte[] loadClassData(File f) throws ClassNotFoundException {\n" +
286 		"		FileInputStream stream = null;\n" +
287 		"		try {\n" +
288 		"			//System.out.println(\"loading: \"+f.getPath());\n" +
289 		"			stream = new FileInputStream(f);\n" +
290 		"\n" +
291 		"			try {\n" +
292 		"				byte[] b= new byte[stream.available()];\n" +
293 		"				stream.read(b);\n" +
294 		"				return b;\n" +
295 		"			}\n" +
296 		"			catch (IOException e) {\n" +
297 		"				throw new ClassNotFoundException();\n" +
298 		"			}\n" +
299 		"		}\n" +
300 		"		catch (FileNotFoundException e) {\n" +
301 		"			throw new ClassNotFoundException();\n" +
302 		"		} finally {\n" +
303 		"			if (stream != null) {\n" +
304 		"				try {\n" +
305 		"					stream.close();\n" +
306 		"				} catch (IOException e) {\n" +
307 		"					/* ignore */\n" +
308 		"				}\n" +
309 		"			}\n" +
310 		"		}\n" +
311 		"	}\n" +
312 		"	/**\n" +
313 		"	 * Locate the given file.\n" +
314 		"	 * @return Returns null if file couldn't be found.\n" +
315 		"	 */\n" +
316 		"	private File locate(String fileName) {\n" +
317 		"		if (fileName != null) {\n" +
318 		"			fileName= fileName.replace('.', '/')+\".class\";\n" +
319 		"			File path= null;\n" +
320 		"			for (int i= 0; i < this.pathItems.length; i++) {\n" +
321 		"				path= new File(this.pathItems[i], fileName);\n" +
322 		"				if (path.exists())\n" +
323 		"					return path;\n" +
324 		"			}\n" +
325 		"		}\n" +
326 		"		return null;\n" +
327 		"	}\n" +
328 		"}\n" +
329 		"\n" +
330 		"public void loadAndRun(String className) throws Throwable {\n" +
331 		"	//System.out.println(\"Loading \" + className + \"...\");\n" +
332 		"	Class testClass = new VerifyClassLoader().loadClass(className);\n" +
333 		"	//System.out.println(\"Loaded \" + className);\n" +
334 		"	try {\n" +
335 		"		Method main = testClass.getMethod(\"main\", new Class[] {String[].class});\n" +
336 		"		//System.out.println(\"Running \" + className);\n" +
337 		"		main.invoke(null, new Object[] {new String[] {}});\n" +
338 		"		//System.out.println(\"Finished running \" + className);\n" +
339 		"	} catch (NoSuchMethodException e) {\n" +
340 		"		return;\n" +
341 		"	} catch (InvocationTargetException e) {\n" +
342 		"		throw e.getTargetException();\n" +
343 		"	}\n" +
344 		"}\n" +
345 		"public static void main(String[] args) throws IOException {\n" +
346 		"	VerifyTests verify = new VerifyTests();\n" +
347 		"	verify.portNumber = Integer.parseInt(args[0]);\n" +
348 		"	verify.run();\n" +
349 		"}\n" +
350 		"public void run() throws IOException {\n" +
351 		"	this.socket = new Socket(\"localhost\", this.portNumber);\n" +
352 		"	this.socket.setTcpNoDelay(true);\n" +
353 		"\n" +
354 		"	DataInputStream in = new DataInputStream(this.socket.getInputStream());\n" +
355 		"	final DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());\n" +
356 		"	while (true) {\n" +
357 		"		final String className = in.readUTF();\n" +
358 		"		Thread thread = new Thread() {\n" +
359 		"			public void run() {\n" +
360 		"				try {\n" +
361 		"					loadAndRun(className);\n" +
362 		"					out.writeBoolean(true);\n" +
363 		"					System.err.println(VerifyTests.class.getName());\n" +
364 		"					System.out.println(VerifyTests.class.getName());\n" +
365 		"				} catch (Throwable e) {\n" +
366 		"					e.printStackTrace();\n" +
367 		"					try {\n" +
368 		"						System.err.println(VerifyTests.class.getName());\n" +
369 		"						System.out.println(VerifyTests.class.getName());\n" +
370 		"						out.writeBoolean(false);\n" +
371 		"					} catch (IOException e1) {\n" +
372 		"						e1.printStackTrace();\n" +
373 		"					}\n" +
374 		"				}\n" +
375 		"				try {\n" +
376 		"					out.flush();\n" +
377 		"				} catch (IOException e) {\n" +
378 		"					e.printStackTrace();\n" +
379 		"				}\n" +
380 		"			}\n" +
381 		"		};\n" +
382 		"		thread.start();\n" +
383 		"	}\n" +
384 		"}\n" +
385 		"}";
386 }
launchAndRun(String className, String[] classpaths, String[] programArguments, String[] vmArguments)387 private void launchAndRun(String className, String[] classpaths, String[] programArguments, String[] vmArguments) {
388 	// we won't reuse the vm, shut the existing one if running
389 	if (this.vm != null) {
390 		try {
391 			this.vm.shutDown();
392 		} catch (TargetException e) {
393 		}
394 	}
395 	this.classpathCache = null;
396 
397 	// launch a new one
398 	LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
399 	launcher.setClassPath(classpaths);
400 	launcher.setVMPath(Util.getJREDirectory());
401 	if (vmArguments != null) {
402 		String[] completeVmArguments = new String[vmArguments.length + 1];
403 		System.arraycopy(vmArguments, 0, completeVmArguments, 1, vmArguments.length);
404 		completeVmArguments[0] = "-verify";
405 		launcher.setVMArguments(completeVmArguments);
406 	} else {
407 		launcher.setVMArguments(new String[] {"-verify"});
408 	}
409 	launcher.setProgramClass(className);
410 	launcher.setProgramArguments(programArguments);
411 	Thread outputThread;
412 	Thread errorThread;
413 	try {
414 		this.vm = launcher.launch();
415 		final InputStream input = this.vm.getInputStream();
416 		outputThread = new Thread(new Runnable() {
417 			@Override
418 			public void run() {
419 				try {
420 					int c = input.read();
421 					while (c != -1) {
422 						TestVerifier.this.outputBuffer.append((char) c);
423 						c = input.read();
424 					}
425 				} catch(IOException e) {
426 				}
427 			}
428 		});
429 		final InputStream errorStream = this.vm.getErrorStream();
430 		errorThread = new Thread(new Runnable() {
431 			@Override
432 			public void run() {
433 				try {
434 					int c = errorStream.read();
435 					while (c != -1) {
436 						TestVerifier.this.errorBuffer.append((char) c);
437 						c = errorStream.read();
438 					}
439 				} catch(IOException e) {
440 				}
441 			}
442 		});
443 		outputThread.start();
444 		errorThread.start();
445 	} catch(TargetException e) {
446 		throw new Error(e.getMessage());
447 	}
448 
449 	// wait for vm to shut down by itself
450 	try {
451 		outputThread.join(10000); // we shut VMs down forcefully downstream,
452 		errorThread.join(10000);  // hence let's have some slack here
453 	} catch (InterruptedException e) {
454 	}
455 }
launchVerifyTestsIfNeeded(String[] classpaths, String[] vmArguments)456 private void launchVerifyTestsIfNeeded(String[] classpaths, String[] vmArguments) {
457 	// determine if we can reuse the vm
458 	if (this.vm != null && this.vm.isRunning() && this.classpathCache != null) {
459 		if (classpaths.length == this.classpathCache.length) {
460 			boolean sameClasspaths = true;
461 			for (int i = 0; i < classpaths.length; i++) {
462 				if (!this.classpathCache[i].equals(classpaths[i])) {
463 					sameClasspaths = false;
464 					break;
465 				}
466 			}
467 			if (sameClasspaths) {
468 				return;
469 			}
470 		}
471 	}
472 
473 	// we could not reuse the vm, shut the existing one if running
474 	if (this.vm != null) {
475 		try {
476 			this.vm.shutDown();
477 		} catch (TargetException e) {
478 		}
479 	}
480 
481 	this.classpathCache = classpaths;
482 
483 	// launch a new one
484 	LocalVMLauncher launcher = LocalVMLauncher.getLauncher();
485 	int length = classpaths.length;
486 	String[] cp = new String[length + 1];
487 	System.arraycopy(classpaths, 0, cp, 0, length);
488 	String verifierDir = Util.getOutputDirectory() + File.separator + "verifier";
489 	compileVerifyTests(verifierDir);
490 	cp[length] = verifierDir;
491 	launcher.setClassPath(cp);
492 	launcher.setVMPath(Util.getJREDirectory());
493 	if (vmArguments != null) {
494 		String[] completeVmArguments = new String[vmArguments.length + 1];
495 		System.arraycopy(vmArguments, 0, completeVmArguments, 1, vmArguments.length);
496 		completeVmArguments[0] = "-verify";
497 		launcher.setVMArguments(completeVmArguments);
498 	} else {
499 		launcher.setVMArguments(new String[] {"-verify"});
500 	}
501 	launcher.setProgramClass(VerifyTests.class.getName());
502 	try (ServerSocket server = new ServerSocket(0)) {
503 		int portNumber = server.getLocalPort();
504 
505 		launcher.setProgramArguments(new String[] {Integer.toString(portNumber)});
506 		try {
507 			this.vm = launcher.launch();
508 			final InputStream input = this.vm.getInputStream();
509 			Thread outputThread = new Thread(new Runnable() {
510 				@Override
511 				public void run() {
512 					try {
513 						int c = input.read();
514 						while (c != -1) {
515 							TestVerifier.this.outputBuffer.append((char) c);
516 							c = input.read();
517 						}
518 					} catch(IOException ioEx) {
519 					}
520 				}
521 			});
522 			final InputStream errorStream = this.vm.getErrorStream();
523 			Thread errorThread = new Thread(new Runnable() {
524 				@Override
525 				public void run() {
526 					try {
527 						int c = errorStream.read();
528 						while (c != -1) {
529 							TestVerifier.this.errorBuffer.append((char) c);
530 							c = errorStream.read();
531 						}
532 					} catch(IOException ioEx) {
533 					}
534 				}
535 			});
536 			outputThread.start();
537 			errorThread.start();
538 		} catch(TargetException e) {
539 			throw new Error(e.getMessage());
540 		}
541 
542 		// connect to the vm
543 		this.socket = null;
544 		boolean isVMRunning = false;
545 		do {
546 			try {
547 				this.socket = server.accept();
548 				this.socket.setTcpNoDelay(true);
549 				break;
550 			} catch (UnknownHostException e) {
551 			} catch (IOException e) {
552 			}
553 			if (this.socket == null) {
554 				try {
555 					Thread.sleep(100);
556 				} catch (InterruptedException e) {
557 				}
558 				isVMRunning = this.vm.isRunning();
559 			}
560 		} while (this.socket == null && isVMRunning);
561 	} catch (IOException e) {
562 		throw new Error(e.getMessage());
563 	}
564 }
565 /**
566  * Loads and runs the given class.
567  * Return whether no exception was thrown while running the class.
568  */
loadAndRun(String className)569 private boolean loadAndRun(String className) {
570 	if (this.socket != null) {
571 		try {
572 			DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
573 			out.writeUTF(className);
574 			DataInputStream in = new DataInputStream(this.socket.getInputStream());
575 			try {
576 				boolean result = in.readBoolean();
577 				waitForFullBuffers();
578 				return result;
579 			} catch (SocketException e) {
580 				// connection was reset because target program has exited
581 				return true;
582 			}
583 		} catch (IOException e) {
584 			e.printStackTrace();
585 		}
586 	}
587 	return true;
588 }
shutDown()589 public void shutDown() {
590 	// Close the socket first so that the OS resource has a chance to be freed.
591 	if (this.socket != null) {
592 		try {
593 			this.socket.close();
594 		} catch (IOException e) {
595 			e.printStackTrace();
596 		}
597 	}
598 	// Wait for the vm to shut down by itself for 2 seconds. If not succesfull, force the shut down.
599 	if (this.vm != null) {
600 		try {
601 			int retry = 0;
602 			while (this.vm.isRunning() && (++retry < 20)) {
603 				try {
604 					Thread.sleep(100);
605 				} catch (InterruptedException e) {
606 				}
607 			}
608 			if (this.vm.isRunning()) {
609 				this.vm.shutDown();
610 			}
611 		} catch (TargetException e) {
612 			e.printStackTrace();
613 		}
614 	}
615 }
616 /**
617  * Verify that the class files created for the given test file can be loaded by
618  * a virtual machine.
619  */
verifyClassFiles(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths)620 public boolean verifyClassFiles(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths) {
621 	return verifyClassFiles(sourceFilePath, className, expectedSuccessOutputString, "", classpaths, null, null);
622 }
623 /**
624  * Verify that the class files created for the given test file can be loaded by
625  * a virtual machine.
626  */
verifyClassFiles(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths, String[] programArguments, String[] vmArguments)627 public boolean verifyClassFiles(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths, String[] programArguments, String[] vmArguments) {
628 	return verifyClassFiles(sourceFilePath, className, expectedSuccessOutputString, "", classpaths, programArguments, vmArguments);
629 }
verifyClassFiles(String sourceFilePath, String className, String expectedOutputString, String expectedErrorStringStart, String[] classpaths, String[] programArguments, String[] vmArguments)630 public boolean verifyClassFiles(String sourceFilePath, String className, String expectedOutputString,
631 		String expectedErrorStringStart, String[] classpaths, String[] programArguments, String[] vmArguments) {
632 	this.outputBuffer = new StringBuffer();
633 	this.errorBuffer = new StringBuffer();
634 	if (this.reuseVM && programArguments == null) {
635 		launchVerifyTestsIfNeeded(classpaths, vmArguments);
636 		loadAndRun(className);
637 	} else {
638 		launchAndRun(className, classpaths, programArguments, vmArguments);
639 	}
640 
641 	this.failureReason = null;
642 	return checkBuffers(this.outputBuffer.toString(), this.errorBuffer.toString(), sourceFilePath, expectedOutputString, expectedErrorStringStart);
643 }
644 
645 /**
646  * Verify that the class files created for the given test file can be loaded and run with an expected error contained
647  * in the expectedSuccessOutputString string.
648  */
verifyClassFilesThrowingError(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths, String[] programArguments, String[] vmArguments)649 public boolean verifyClassFilesThrowingError(String sourceFilePath, String className, String expectedSuccessOutputString, String[] classpaths, String[] programArguments, String[] vmArguments) {
650 	this.outputBuffer = new StringBuffer();
651 	this.errorBuffer = new StringBuffer();
652 	if (this.reuseVM && programArguments == null) {
653 		launchVerifyTestsIfNeeded(classpaths, vmArguments);
654 		loadAndRun(className);
655 	} else {
656 		launchAndRun(className, classpaths, programArguments, vmArguments);
657 	}
658 
659 	this.failureReason = null;
660 	return checkBuffersThrowingError(this.errorBuffer.toString(), sourceFilePath, expectedSuccessOutputString);
661 }
662 
663 /**
664  * Wait until there is nothing more to read from the stdout or sterr.
665  */
waitForFullBuffers()666 private void waitForFullBuffers() {
667 	String endString = VerifyTests.class.getName();
668 	int count = 60;
669 	int waitMs = 1;
670 	int errorEndStringStart = this.errorBuffer.toString().indexOf(endString);
671 	int outputEndStringStart = this.outputBuffer.toString().indexOf(endString);
672 	while (errorEndStringStart == -1 || outputEndStringStart == -1) {
673 		try {
674 			Thread.sleep(waitMs);
675 		} catch (InterruptedException e) {
676 		} finally {
677 			if(waitMs < 100) waitMs *= 2;
678 		}
679 		if (--count == 0) return;
680 		errorEndStringStart = this.errorBuffer.toString().indexOf(endString);
681 		outputEndStringStart = this.outputBuffer.toString().indexOf(endString);
682 	}
683 	this.errorBuffer.setLength(errorEndStringStart);
684 	this.outputBuffer.setLength(outputEndStringStart);
685 }
686 }
687