1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 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.debug.jdi.tests;
15 
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.ListIterator;
22 import java.util.Map;
23 import java.util.StringTokenizer;
24 import java.util.Vector;
25 
26 import org.eclipse.jdi.Bootstrap;
27 
28 import com.sun.jdi.AbsentInformationException;
29 import com.sun.jdi.ArrayReference;
30 import com.sun.jdi.ArrayType;
31 import com.sun.jdi.ClassLoaderReference;
32 import com.sun.jdi.ClassNotLoadedException;
33 import com.sun.jdi.ClassType;
34 import com.sun.jdi.Field;
35 import com.sun.jdi.IncompatibleThreadStateException;
36 import com.sun.jdi.InterfaceType;
37 import com.sun.jdi.InvalidTypeException;
38 import com.sun.jdi.LocalVariable;
39 import com.sun.jdi.Location;
40 import com.sun.jdi.Method;
41 import com.sun.jdi.ObjectReference;
42 import com.sun.jdi.ReferenceType;
43 import com.sun.jdi.StackFrame;
44 import com.sun.jdi.StringReference;
45 import com.sun.jdi.ThreadReference;
46 import com.sun.jdi.VMDisconnectedException;
47 import com.sun.jdi.Value;
48 import com.sun.jdi.VirtualMachineManager;
49 import com.sun.jdi.connect.AttachingConnector;
50 import com.sun.jdi.connect.Connector.Argument;
51 import com.sun.jdi.connect.IllegalConnectorArgumentsException;
52 import com.sun.jdi.event.Event;
53 import com.sun.jdi.event.ExceptionEvent;
54 import com.sun.jdi.event.StepEvent;
55 import com.sun.jdi.request.AccessWatchpointRequest;
56 import com.sun.jdi.request.BreakpointRequest;
57 import com.sun.jdi.request.EventRequest;
58 import com.sun.jdi.request.ExceptionRequest;
59 import com.sun.jdi.request.ModificationWatchpointRequest;
60 import com.sun.jdi.request.StepRequest;
61 
62 import junit.framework.Test;
63 import junit.framework.TestCase;
64 
65 /**
66  * Tests for com.sun.jdi.* and JDWP commands.
67  * These tests assume that the target program is
68  * "org.eclipse.debug.jdi.tests.program.MainClass".
69  *
70  * Examples of arguments:
71  *   -launcher SunVMLauncher -address c:\jdk1.2.2\ -cp d:\target
72  *   -launcher J9VMLauncher -address d:\ive\ -cp d:\target
73  */
74 public abstract class AbstractJDITest extends TestCase {
75 	static int TIMEOUT = 10000; //ms
76 	static protected int fBackEndPort = 9900;
77 	// We want subsequent connections to use different ports.
78 	protected static String fVMLauncherName;
79 	protected static String fTargetAddress;
80 	protected static String fClassPath;
81 	protected static String fBootPath;
82 	protected static String fVMType;
83 	protected com.sun.jdi.VirtualMachine fVM;
84 	protected Process fLaunchedProxy;
85 	protected Process fLaunchedVM;
86 	protected static int fVMTraceFlags = com.sun.jdi.VirtualMachine.TRACE_NONE;
87 	protected EventReader fEventReader;
88 	protected AbstractReader fConsoleReader;
89 	protected AbstractReader fConsoleErrorReader;
90 	protected AbstractReader fProxyReader;
91 	protected AbstractReader fProxyErrorReader;
92 	protected boolean fInControl = true;
93 	// Whether this test should control the VM (ie. starting it and shutting it down)
94 	protected static boolean fVerbose;
95 	protected static String fStdoutFile;
96 	protected static String fStderrFile;
97 	protected static String fProxyoutFile;
98 	protected static String fProxyerrFile;
99 	protected static String fVmCmd;
100 	protected static String fVmArgs;
101 	protected static String fProxyCmd;
102 
103 	// Stack offset to the MainClass.run() method
104 	protected static final int RUN_FRAME_OFFSET = 1;
105 
106 	/**
107 	 * Constructs a test case with a default name.
108 	 */
AbstractJDITest()109 	public AbstractJDITest() {
110 		super("JDI Test");
111 	}
112 	/**
113 	 * Returns the names of the tests that are known to not work
114 	 * By default, none are excluded.
115 	 */
excludedTests()116 	protected String[] excludedTests() {
117 		return new String[] {
118 		};
119 	}
120 	/**
121 	 * Creates and returns an access watchpoint request
122 	 * for the field "fBool" in
123 	 * org.eclipse.debug.jdi.tests.program.MainClass
124 	 * NOTE: This assumes that the VM can watch field access.
125 	 */
getAccessWatchpointRequest()126 	protected AccessWatchpointRequest getAccessWatchpointRequest() {
127 		// Get the field
128 		Field field = getField("fBool");
129 
130 		// Create an access watchpoint for this field
131 		return fVM.eventRequestManager().createAccessWatchpointRequest(field);
132 	}
133 	/**
134 	 * Returns all tests that start with the given string.
135 	 * Returns a vector of String.
136 	 */
getAllMatchingTests(String match)137 	protected Vector<String> getAllMatchingTests(String match) {
138 		Class<? extends AbstractJDITest> theClass = this.getClass();
139 		java.lang.reflect.Method[] methods = theClass.getDeclaredMethods();
140 		Vector<String> result = new Vector<>();
141 		for (int i = 0; i < methods.length; i++) {
142 			java.lang.reflect.Method m = methods[i];
143 			String name = m.getName();
144 			Class<?>[] parameters = m.getParameterTypes();
145 			if (parameters.length == 0 && name.startsWith(match)) {
146 				if (!isExcludedTest(name)) {
147 					result.add(name);
148 				} else {
149 					System.out.println(name + " is excluded.");
150 				}
151 			}
152 		}
153 		return result;
154 	}
155 
156 	/**
157 	 * Returns if the current VM version is greater than or equal to 1.6
158 	 * @return <code>true</code> if a 1.6 or higher VM
159 	 * @since 3.8
160 	 */
is16OrGreater()161 	protected boolean is16OrGreater() {
162 		String ver = fVM.version();
163 		return ver.indexOf("1.6") > -1 || ver.indexOf("1.7") > -1;
164 	}
165 
166 	/**
167 	 * Returns an array reference.
168 	 */
getObjectArrayReference()169 	protected ArrayReference getObjectArrayReference() {
170 		// Get static field "fArray"
171 		Field field = getField("fArray");
172 
173 		// Get value of "fArray"
174 		return (ArrayReference) getMainClass().getValue(field);
175 	}
176 
177 	/**
178 	 * Returns another array reference.
179 	 */
getNonEmptyDoubleArrayReference()180 	protected ArrayReference getNonEmptyDoubleArrayReference() {
181 		// Get static field "fDoubleArray"
182 		Field field = getField("fDoubleArray");
183 
184 		// Get value of "fDoubleArray"
185 		return (ArrayReference) getMainClass().getValue(field);
186 	}
187 
188 	/**
189 	 * One-dimensional empty array reference getters
190 	 */
getByteArrayReference()191 	protected ArrayReference getByteArrayReference() {
192 		Field field = getField("byteArray");
193 		return (ArrayReference) getMainClass().getValue(field);
194 	}
getShortArrayReference()195 	protected ArrayReference getShortArrayReference() {
196 		Field field = getField("shortArray");
197 		return (ArrayReference) getMainClass().getValue(field);
198 	}
getIntArrayReference()199 	protected ArrayReference getIntArrayReference() {
200 		Field field = getField("intArray");
201 		return (ArrayReference) getMainClass().getValue(field);
202 	}
getLongArrayReference()203 	protected ArrayReference getLongArrayReference() {
204 		Field field = getField("longArray");
205 		return (ArrayReference) getMainClass().getValue(field);
206 	}
getDoubleArrayReference()207 	protected ArrayReference getDoubleArrayReference() {
208 		Field field = getField("doubleArray");
209 		return (ArrayReference) getMainClass().getValue(field);
210 	}
getFloatArrayReference()211 	protected ArrayReference getFloatArrayReference() {
212 		Field field = getField("floatArray");
213 		return (ArrayReference) getMainClass().getValue(field);
214 	}
getCharArrayReference()215 	protected ArrayReference getCharArrayReference() {
216 		Field field = getField("charArray");
217 		return (ArrayReference) getMainClass().getValue(field);
218 	}
getBooleanArrayReference()219 	protected ArrayReference getBooleanArrayReference() {
220 		Field field = getField("booleanArray");
221 		return (ArrayReference) getMainClass().getValue(field);
222 	}
223 	/**
224 	 * Two-dimensional array reference getters
225 	 */
getByteDoubleArrayReference()226 	protected ArrayReference getByteDoubleArrayReference() {
227 		Field field = getField("byteDoubleArray");
228 		return (ArrayReference) getMainClass().getValue(field);
229 	}
getShortDoubleArrayReference()230 	protected ArrayReference getShortDoubleArrayReference() {
231 		Field field = getField("shortDoubleArray");
232 		return (ArrayReference) getMainClass().getValue(field);
233 	}
getIntDoubleArrayReference()234 	protected ArrayReference getIntDoubleArrayReference() {
235 		Field field = getField("intDoubleArray");
236 		return (ArrayReference) getMainClass().getValue(field);
237 	}
getLongDoubleArrayReference()238 	protected ArrayReference getLongDoubleArrayReference() {
239 		Field field = getField("longDoubleArray");
240 		return (ArrayReference) getMainClass().getValue(field);
241 	}
getFloatDoubleArrayReference()242 	protected ArrayReference getFloatDoubleArrayReference() {
243 		Field field = getField("floatDoubleArray");
244 		return (ArrayReference) getMainClass().getValue(field);
245 	}
getDoubleDoubleArrayReference()246 	protected ArrayReference getDoubleDoubleArrayReference() {
247 		Field field = getField("doubleDoubleArray");
248 		return (ArrayReference) getMainClass().getValue(field);
249 	}
getCharDoubleArrayReference()250 	protected ArrayReference getCharDoubleArrayReference() {
251 		Field field = getField("charDoubleArray");
252 		return (ArrayReference) getMainClass().getValue(field);
253 	}
getBooleanDoubleArrayReference()254 	protected ArrayReference getBooleanDoubleArrayReference() {
255 		Field field = getField("booleanDoubleArray");
256 		return (ArrayReference) getMainClass().getValue(field);
257 	}
258 
259 	/**
260 	 * Returns the array type.
261 	 */
getArrayType()262 	protected ArrayType getArrayType() {
263 		// Get array reference
264 		ArrayReference value = getObjectArrayReference();
265 
266 		// Get reference type of "fArray"
267 		return (ArrayType) value.referenceType();
268 	}
269 	/**
270 	 * One-dimensional primitive array getters
271 	 */
getByteArrayType()272 	protected ArrayType getByteArrayType() {
273 		ArrayReference value = getByteArrayReference();
274 		return (ArrayType) value.referenceType();
275 	}
getShortArrayType()276 	protected ArrayType getShortArrayType() {
277 		ArrayReference value = getShortArrayReference();
278 		return (ArrayType) value.referenceType();
279 	}
getIntArrayType()280 	protected ArrayType getIntArrayType() {
281 		ArrayReference value = getIntArrayReference();
282 		return (ArrayType) value.referenceType();
283 	}
getLongArrayType()284 	protected ArrayType getLongArrayType() {
285 		ArrayReference value = getLongArrayReference();
286 		return (ArrayType) value.referenceType();
287 	}
getFloatArrayType()288 	protected ArrayType getFloatArrayType() {
289 		ArrayReference value = getFloatArrayReference();
290 		return (ArrayType) value.referenceType();
291 	}
getDoubleArrayType()292 	protected ArrayType getDoubleArrayType() {
293 		ArrayReference value = getDoubleArrayReference();
294 		return (ArrayType) value.referenceType();
295 	}
getCharArrayType()296 	protected ArrayType getCharArrayType() {
297 		ArrayReference value = getCharArrayReference();
298 		return (ArrayType) value.referenceType();
299 	}
getBooleanArrayType()300 	protected ArrayType getBooleanArrayType() {
301 		ArrayReference value = getBooleanArrayReference();
302 		return (ArrayType) value.referenceType();
303 	}
304 	/**
305 	 * Two-dimensional primitive array getters
306 	 */
getByteDoubleArrayType()307 	protected ArrayType getByteDoubleArrayType() {
308 		ArrayReference value = getByteDoubleArrayReference();
309 		return (ArrayType) value.referenceType();
310 	}
getShortDoubleArrayType()311 	protected ArrayType getShortDoubleArrayType() {
312 		ArrayReference value = getShortDoubleArrayReference();
313 		return (ArrayType) value.referenceType();
314 	}
getIntDoubleArrayType()315 	protected ArrayType getIntDoubleArrayType() {
316 		ArrayReference value = getIntDoubleArrayReference();
317 		return (ArrayType) value.referenceType();
318 	}
getLongDoubleArrayType()319 	protected ArrayType getLongDoubleArrayType() {
320 		ArrayReference value = getLongDoubleArrayReference();
321 		return (ArrayType) value.referenceType();
322 	}
getFloatDoubleArrayType()323 	protected ArrayType getFloatDoubleArrayType() {
324 		ArrayReference value = getFloatDoubleArrayReference();
325 		return (ArrayType) value.referenceType();
326 	}
getDoubleDoubleArrayType()327 	protected ArrayType getDoubleDoubleArrayType() {
328 		ArrayReference value = getDoubleDoubleArrayReference();
329 		return (ArrayType) value.referenceType();
330 	}
getCharDoubleArrayType()331 	protected ArrayType getCharDoubleArrayType() {
332 		ArrayReference value = getCharDoubleArrayReference();
333 		return (ArrayType) value.referenceType();
334 	}
getBooleanDoubleArrayType()335 	protected ArrayType getBooleanDoubleArrayType() {
336 		ArrayReference value = getBooleanDoubleArrayReference();
337 		return (ArrayType) value.referenceType();
338 	}
339 
340 	/**
341 	 * Creates and returns a breakpoint request in the first
342 	 * instruction of the MainClass.triggerBreakpointEvent() method.
343 	 */
getBreakpointRequest()344 	protected BreakpointRequest getBreakpointRequest() {
345 		// Create a breakpoint request
346 		return fVM.eventRequestManager().createBreakpointRequest(getLocation());
347 	}
348 
349 	/**
350 	 * Creates a new breakpoint request for a user specified position
351 	 * @param loc the location to set the breakpoint on
352 	 * @return a new breakpoint request or null if the location is invalid
353 	 * @since 3.3
354 	 */
getBreakpointRequest(Location loc)355 	protected BreakpointRequest getBreakpointRequest(Location loc) {
356 		return fVM.eventRequestManager().createBreakpointRequest(loc);
357 	}
358 	/**
359 	 * Returns the class with the given name or null if not loaded.
360 	 */
getClass(String name)361 	protected ClassType getClass(String name) {
362 		List<?> classes = fVM.classesByName(name);
363 		if (classes.size() == 0) {
364 			return null;
365 		}
366 
367 		return (ClassType) classes.get(0);
368 	}
369 	/**
370 	 * Returns the class loader of
371 	 * org.eclipse.debug.jdi.tests.program.MainClass
372 	 */
getClassLoaderReference()373 	protected ClassLoaderReference getClassLoaderReference() {
374 		// Get main class
375 		ClassType type = getMainClass();
376 
377 		// Get its class loader
378 		return type.classLoader();
379 	}
380 	/**
381 	 * Creates and returns an exception request for uncaught exceptions.
382 	 */
getExceptionRequest()383 	protected ExceptionRequest getExceptionRequest() {
384 		return fVM.eventRequestManager().createExceptionRequest(null, false, true);
385 	}
386 	/**
387 	 * Returns the static field "fObject" in
388 	 * org.eclipse.debug.jdi.tests.program.MainClass
389 	 */
getField()390 	protected Field getField() {
391 		return getField("fObject");
392 	}
393 	/**
394 	 * Returns the field with the given name in
395 	 * org.eclipse.debug.jdi.tests.program.MainClass.
396 	 */
getField(String fieldName)397 	protected Field getField(String fieldName) {
398 		// Get main class
399 		ClassType type = getMainClass();
400 
401 		// Get field
402 		Field result = type.fieldByName(fieldName);
403 		if (result == null) {
404 			throw new Error("Unknown field: " + fieldName);
405 		}
406 
407 		return result;
408 	}
409 	/**
410 	 * Returns the n frame (starting at the top of the stack) of the thread
411 	 * contained in the static field "fThread" of org.eclipse.debug.jdi.tests.program.MainClass.
412 	 */
getFrame(int n)413 	protected StackFrame getFrame(int n) {
414 		// Make sure the thread is suspended
415 		ThreadReference thread = getThread();
416 		assertTrue(thread.isSuspended());
417 
418 		// Get the frame
419 		StackFrame frame = null;
420 		try {
421 			List<?> frames = thread.frames();
422 			frame = (StackFrame) frames.get(n);
423 		} catch (IncompatibleThreadStateException e) {
424 			throw new Error("Thread was not suspended");
425 		}
426 
427 		return frame;
428 	}
429 	/**
430 	 * Returns the interface type org.eclipse.debug.jdi.tests.program.Printable.
431 	 */
getInterfaceType()432 	protected InterfaceType getInterfaceType() {
433 		List<?> types = fVM.classesByName("org.eclipse.debug.jdi.tests.program.Printable");
434 		return (InterfaceType) types.get(0);
435 	}
436 	/**
437 	 * Returns the variable "t" in the frame running MainClass.run().
438 	 */
getLocalVariable()439 	protected LocalVariable getLocalVariable() {
440 		try {
441 			return getFrame(RUN_FRAME_OFFSET).visibleVariableByName("t");
442 		} catch (AbsentInformationException e) {
443 			return null;
444 		}
445 	}
446 	/**
447 	 * Returns the first location in MainClass.print(OutputStream).
448 	 */
getLocation()449 	protected Location getLocation() {
450 		return getMethod().location();
451 	}
452 	/**
453 	 * Returns the class org.eclipse.debug.jdi.tests.program.MainClass.
454 	 */
getMainClass()455 	protected ClassType getMainClass() {
456 		return getClass( getMainClassName() );
457 	}
458 	/**
459 	 * Returns the method "print(Ljava/io/OutputStream;)V"
460 	 * in org.eclipse.debug.jdi.tests.program.MainClass
461 	 */
getMethod()462 	protected Method getMethod() {
463 		return getMethod("print", "(Ljava/io/OutputStream;)V");
464 	}
465 	/**
466 	 * Returns the method with the given name and signature
467 	 * in org.eclipse.debug.jdi.tests.program.MainClass
468 	 */
getMethod(String name, String signature)469 	protected Method getMethod(String name, String signature) {
470 		return getMethod(
471 			getMainClassName(),
472 			name,
473 			signature);
474 	}
475 	/**
476 	 * Returns the method with the given name and signature
477 	 * in the given class.
478 	 */
getMethod(String className, String name, String signature)479 	protected Method getMethod(String className, String name, String signature) {
480 		// Get main class
481 		ClassType type = getClass(className);
482 
483 		// Get method print(OutputStream)
484 		Method method = null;
485 		List<Method> methods = type.methods();
486 		ListIterator<Method> iterator = methods.listIterator();
487 		while (iterator.hasNext()) {
488 			Method m = iterator.next();
489 			if ((m.name().equals(name)) && (m.signature().equals(signature))) {
490 				method = m;
491 				break;
492 			}
493 		}
494 		if (method == null) {
495 			throw new Error("Unknown method: " + name + signature);
496 		}
497 
498 		return method;
499 	}
500 	/**
501 	 * Creates and returns a modification watchpoint request
502 	 * for the field "fBool" in
503 	 * org.eclipse.debug.jdi.tests.program.MainClass.
504 	 * NOTE: This assumes that the VM can watch field modification.
505 	 */
getModificationWatchpointRequest()506 	protected ModificationWatchpointRequest getModificationWatchpointRequest() {
507 		// Get the field
508 		Field field = getField("fBool");
509 
510 		// Create a modification watchpoint for this field
511 		return fVM.eventRequestManager().createModificationWatchpointRequest(field);
512 	}
513 	/**
514 	 * Returns the value of the static field "fObject" in
515 	 * org.eclipse.debug.jdi.tests.program.MainClass
516 	 */
getObjectReference()517 	protected ObjectReference getObjectReference() {
518 		// Get main class
519 		ClassType type = getMainClass();
520 
521 		// Get field "fObject"
522 		Field field = getField();
523 
524 		// Get value of "fObject"
525 		return (ObjectReference) type.getValue(field);
526 	}
527 	/**
528 	 * Creates and returns an access watchpoint request
529 	 * for the static field "fString" in
530 	 * org.eclipse.debug.jdi.tests.program.MainClass
531 	 * NOTE: This assumes that the VM can watch field access.
532 	 */
getStaticAccessWatchpointRequest()533 	protected AccessWatchpointRequest getStaticAccessWatchpointRequest() {
534 		// Get the static field
535 		Field field = getField("fString");
536 
537 		// Create an access watchpoint for this field
538 		return fVM.eventRequestManager().createAccessWatchpointRequest(field);
539 	}
540 	/**
541 	 * Creates and returns a modification watchpoint request
542 	 * for the static field "fString" in
543 	 * org.eclipse.debug.jdi.tests.program.MainClass.
544 	 * NOTE: This assumes that the VM can watch field modification.
545 	 */
getStaticModificationWatchpointRequest()546 	protected ModificationWatchpointRequest getStaticModificationWatchpointRequest() {
547 		// Get the field
548 		Field field = getField("fString");
549 
550 		// Create a modification watchpoint for this field
551 		return fVM.eventRequestManager().createModificationWatchpointRequest(field);
552 	}
553 	/**
554 	 * Returns the value of the static field "fString" in
555 	 * org.eclipse.debug.jdi.tests.program.MainClass
556 	 */
getStringReference()557 	protected StringReference getStringReference() {
558 		// Get field "fString"
559 		Field field = getField("fString");
560 
561 		// Get value of "fString"
562 		return (StringReference) getMainClass().getValue(field);
563 	}
564 	/**
565 	 * Returns the class java.lang.Object.
566 	 */
getSystemType()567 	protected ClassType getSystemType() {
568 		List<ReferenceType> classes = fVM.classesByName("java.lang.Object");
569 		if (classes.size() == 0) {
570 			return null;
571 		}
572 
573 		return (ClassType) classes.get(0);
574 	}
575 	/**
576 	 * Returns the thread contained in the static field "fThread" in
577 	 * org.eclipse.debug.jdi.tests.program.MainClass
578 	 */
getThread()579 	protected ThreadReference getThread() {
580 		return getThread("fThread");
581 	}
582 
getMainThread()583 	protected ThreadReference getMainThread() {
584 		return getThread("fMainThread");
585 	}
586 
getThread(String fieldName)587 	private ThreadReference getThread(String fieldName) {
588 		ClassType type = getMainClass();
589 		if (type == null) {
590 			return null;
591 		}
592 
593 		// Get static field "fThread"
594 		List<Field> fields = type.fields();
595 		ListIterator<Field> iterator = fields.listIterator();
596 		Field field = null;
597 		while (iterator.hasNext()) {
598 			field = iterator.next();
599 			if (field.name().equals(fieldName)) {
600 				break;
601 			}
602 		}
603 
604 		// Get value of "fThread"
605 		Value value = type.getValue(field);
606 		if (value == null) {
607 			return null;
608 		}
609 
610 		return (ThreadReference) value;
611 	}
612 	/**
613 	 * Returns the VM info for this test.
614 	 */
getVMInfo()615 	public VMInformation getVMInfo() {
616 		return new VMInformation(
617 			fVM,
618 			fVMType,
619 			fLaunchedVM,
620 			fEventReader,
621 			fConsoleReader);
622 	}
623 	/**
624 	 * Returns whether the given test is excluded for the VM we are testing.
625 	 */
isExcludedTest(String testName)626 	private boolean isExcludedTest(String testName) {
627 		String[] excludedTests = excludedTests();
628 		if (excludedTests == null) {
629 			return false;
630 		}
631 		for (int i = 0; i < excludedTests.length; i++) {
632 			if (testName.equals(excludedTests[i])) {
633 				return true;
634 			}
635 		}
636 		return false;
637 	}
638 
639 	/**
640 	 * Launches the target VM and connects to VM.
641 	 */
launchTargetAndConnectToVM()642 	protected void launchTargetAndConnectToVM() {
643 		launchTarget();
644 		connectToVM();
645 	}
646 
vmIsRunning()647 	protected boolean vmIsRunning() {
648 		boolean isRunning = false;
649 		try {
650 			if (fLaunchedVM != null) {
651 				fLaunchedVM.exitValue();
652 			}
653 		} catch (IllegalThreadStateException e) {
654 			isRunning = true;
655 		}
656 		return isRunning;
657 	}
658 
launchTarget()659 	protected void launchTarget() {
660 		if (fVmCmd != null) {
661 			launchCommandLineTarget();
662 		} else if (fVMLauncherName.equals("SunVMLauncher")) {
663 			launchSunTarget();
664 		} else if (fVMLauncherName.equals("IBMVMLauncher")) {
665 			launchIBMTarget();
666 		} else {
667 			launchJ9Target();
668 		}
669 	}
670 
671 	/**
672 	 * Launches the target VM specified on the command line.
673 	 */
launchCommandLineTarget()674 	private void launchCommandLineTarget() {
675 		try {
676 			if (fProxyCmd != null) {
677 				fLaunchedProxy = Runtime.getRuntime().exec(parseCommand(fProxyCmd));
678 			}
679 			fLaunchedVM = Runtime.getRuntime().exec(parseCommand(fVmCmd));
680 		} catch (IOException e) {
681 			throw new Error("Could not launch the VM because " + e.getMessage());
682 		}
683 	}
684 
685 	/**
686 	 * Parse the command {@link String} to make sure we use
687 	 * {@link Runtime#exec(String[])}.
688 	 *
689 	 * @param command
690 	 * @return the array of items from the command {@link String}
691 	 * @since 4.3
692 	 */
parseCommand(String command)693 	String[] parseCommand(String command) {
694 		StringTokenizer tokenizer = new StringTokenizer(command);
695 		String[] commandArray = new String[tokenizer.countTokens()];
696 		//first token is the command
697 		if(tokenizer.hasMoreTokens()) {
698 			commandArray[0] = tokenizer.nextToken();
699 		}
700 		for (int i= 1; tokenizer.hasMoreTokens(); i++) {
701 			commandArray[i] = tokenizer.nextToken();
702 		}
703 		return commandArray;
704 	}
705 
706 	/**
707 	 * Launches the target J9 VM.
708 	 */
launchJ9Target()709 	private void launchJ9Target() {
710 		try {
711 			// Launch proxy
712 			String proxyString[] = new String[3];
713 			int index = 0;
714 			String binDirectory =
715 				fTargetAddress
716 					+ File.separatorChar
717 					+ "bin"
718 					+ File.separatorChar;
719 
720 			proxyString[index++] = binDirectory + "j9proxy";
721 			proxyString[index++] = "localhost:" + (fBackEndPort - 1);
722 			proxyString[index++] = "" + fBackEndPort;
723 			fLaunchedProxy = Runtime.getRuntime().exec(proxyString);
724 
725 			// Launch target VM
726 			Vector<String> commandLine = new Vector<>();
727 
728 			String launcher = binDirectory + "j9w.exe";
729 			File vm= new File(launcher);
730 			if (!vm.exists()) {
731 				launcher = binDirectory + "j9";
732 			}
733 			commandLine.add(launcher);
734 
735 			if (fBootPath.length() > 0) {
736 				commandLine.add("-bp:" + fBootPath);
737 			}
738 			commandLine.add("-cp:" + fClassPath);
739 			commandLine.add("-debug:" + (fBackEndPort - 1));
740 			injectVMArgs(commandLine);
741 			commandLine.add(getMainClassName());
742 
743 			fLaunchedVM = exec(commandLine);
744 
745 		} catch (IOException e) {
746 			throw new Error("Could not launch the VM because " + e.getMessage());
747 		}
748 	}
749 
750 	/**
751 	 * Launches the target Sun VM.
752 	 */
launchSunTarget()753 	private void launchSunTarget() {
754 		try {
755 			// Launch target VM
756 			StringBuilder binDirectory= new StringBuilder();
757 			if (fTargetAddress.endsWith("jre")) {
758 				binDirectory.append(fTargetAddress.substring(0, fTargetAddress.length() - 4));
759 			} else {
760 				binDirectory.append(fTargetAddress);
761 			}
762 			binDirectory.append(File.separatorChar);
763 			binDirectory.append("bin").append(File.separatorChar);
764 
765 			Vector<String> commandLine = new Vector<>();
766 
767 			String launcher = binDirectory.toString() + "javaw.exe";
768 			File vm= new File(launcher);
769 			if (!vm.exists()) {
770 				launcher = binDirectory + "java";
771 			}
772 			commandLine.add(launcher);
773 
774 			if (fBootPath.length() > 0) {
775 				commandLine.add("-bootpath");
776 				commandLine.add(fBootPath);
777 			}
778 			commandLine.add("-classpath");
779 			commandLine.add(fClassPath);
780 			commandLine.add("-Xdebug");
781 			commandLine.add("-Xnoagent");
782 			commandLine.add("-Djava.compiler=NONE");
783 			commandLine.add("-Xrunjdwp:transport=dt_socket,address=" + fBackEndPort + ",suspend=y,server=y");
784 			injectVMArgs(commandLine);
785 			commandLine.add(getMainClassName());
786 
787 			fLaunchedVM = exec(commandLine);
788 
789 		} catch (IOException e) {
790 			throw new Error("Could not launch the VM because " + e.getMessage());
791 		}
792 	}
793 	/**
794 	 * Launches the target IBM VM.
795 	 */
launchIBMTarget()796 	private void launchIBMTarget() {
797 		try {
798 			// Launch target VM
799 			String binDirectory =
800 				fTargetAddress
801 					+ File.separatorChar
802 					+ "bin"
803 					+ File.separatorChar;
804 
805 			Vector<String> commandLine = new Vector<>();
806 
807 			commandLine.add(binDirectory + "javaw");
808 			if (fBootPath.length() > 0) {
809 				commandLine.add("-bootpath");
810 				commandLine.add(fBootPath);
811 			}
812 
813 			commandLine.add("-classpath");
814 			commandLine.add(fClassPath);
815 			commandLine.add("-Xdebug");
816 			commandLine.add("-Xnoagent");
817 			commandLine.add("-Djava.compiler=NONE");
818 			commandLine.add("-Xrunjdwp:transport=dt_socket,address=" + fBackEndPort + ",suspend=y,server=y");
819 			injectVMArgs(commandLine);
820 			commandLine.add(getMainClassName());
821 
822 			fLaunchedVM = exec(commandLine);
823 
824 		} catch (IOException e) {
825 			throw new Error("Could not launch the VM because " + e.getMessage());
826 		}
827 	}
828 
getMainClassName()829 	protected String getMainClassName() {
830 		return "org.eclipse.debug.jdi.tests.program.MainClass";
831 	}
832 
getTestPrefix()833 	protected String getTestPrefix() {
834 		return "testJDI";
835 	}
836 
837 	/**
838 	 * Injects arguments specified using -vmargs command line option into
839 	 * the provided commandLine.
840 	 * @param commandLine A vector of command line argument strings.
841 	 */
injectVMArgs(Vector<String> commandLine)842 	private void injectVMArgs(Vector<String> commandLine) {
843 		if (fVmArgs != null) {
844 			String[] args = fVmArgs.split(",");
845 			for (int i=0; i < args.length; i++) {
846 				commandLine.add(args[i]);
847 			}
848 		}
849 	}
850 
851 	/**
852 	 * Flattens the variable size command line and calls Runtime.exec().
853 	 * @param commandLine A vector of command line argument strings.
854 	 * @return The Process created by Runtime.exec()
855 	 * @throws IOException
856 	 */
exec(Vector<String> commandLine)857 	private Process exec(Vector<String> commandLine) throws IOException {
858 		String[] vmString = new String[commandLine.size()];
859 		commandLine.toArray(vmString);
860 		return Runtime.getRuntime().exec(vmString);
861 	}
862 
863 
864 	/**
865 	 * Connects to the target vm.
866 	 */
connectToVM()867 	protected void connectToVM() {
868 		// Start the console reader if possible so that the VM doesn't block when the stdout is full
869 		startConsoleReaders();
870 
871 
872 		// Contact the VM (try 10 times)
873 		for (int i = 0; i < 10; i++) {
874 			try {
875 				VirtualMachineManager manager = Bootstrap.virtualMachineManager();
876 				List<AttachingConnector> connectors = manager.attachingConnectors();
877 				if (connectors.size() == 0) {
878 					break;
879 				}
880 				AttachingConnector connector = connectors.get(0);
881 				Map<String, Argument> args = connector.defaultArguments();
882 				args.get("port").setValue(String.valueOf(fBackEndPort));
883 				args.get("hostname").setValue("localhost");
884 
885 				fVM = connector.attach(args);
886 				if (fVMTraceFlags != com.sun.jdi.VirtualMachine.TRACE_NONE) {
887 					fVM.setDebugTraceMode(fVMTraceFlags);
888 				}
889 				break;
890 			} catch (IllegalConnectorArgumentsException e) {
891 			} catch (IOException e) {
892 //				System.out.println("Got exception: " + e.getMessage());
893 				try {
894 					if (i == 9) {
895 						System.out.println(
896 							"Could not contact the VM at localhost" + ":" + fBackEndPort + ".");
897 					}
898 					Thread.sleep(200);
899 				} catch (InterruptedException e2) {
900 				}
901 			}
902 		}
903 		if (fVM == null) {
904 			if (fLaunchedVM != null) {
905 				// If the VM is not running, output error stream
906 				try {
907 					if (!vmIsRunning()) {
908 						InputStream in = fLaunchedVM.getErrorStream();
909 						int read;
910 						do {
911 							read = in.read();
912 							if (read != -1) {
913 								System.out.print((char) read);
914 							}
915 						} while (read != -1);
916 					}
917 				} catch (IOException e) {
918 				}
919 
920 				// Shut it down
921 				killVM();
922 			}
923 			throw new Error("Could not contact the VM");
924 		}
925 		startEventReader();
926 	}
927 	/**
928 	 * Initializes the fields that are used by this test only.
929 	 */
localSetUp()930 	public abstract void localSetUp();
931 	/**
932 	 * Makes sure the test leaves the VM in the same state it found it.
933 	 * Default is to do nothing.
934 	 */
localTearDown()935 	public void localTearDown() {
936 	}
937 	/**
938 	 * Parses the given arguments and store them in this tests
939 	 * fields.
940 	 * Returns whether the parsing was successful.
941 	 */
parseArgs(String[] args)942 	protected static boolean parseArgs(String[] args) {
943 		// Default values
944 		String vmVendor = System.getProperty("java.vm.vendor");
945 		String vmVersion = System.getProperty("java.vm.version");
946 		String targetAddress = System.getProperty("java.home");
947 		String vmLauncherName;
948 		if (vmVendor != null
949 			&& (vmVendor.indexOf("Sun") > -1 || vmVendor.indexOf("Oracle") > -1 || vmVendor.indexOf("Apple") > -1)
950 			&& vmVersion != null) {
951 			vmLauncherName = "SunVMLauncher";
952 		} else if (
953 			vmVendor != null && vmVendor.indexOf("IBM") > -1 && vmVersion != null) {
954 			vmLauncherName = "IBMVMLauncher";
955 		} else {
956 			vmLauncherName = "J9VMLauncher";
957 		}
958 		String classPath = System.getProperty("java.class.path");
959 		String bootPath = "";
960 		String vmType = "?";
961 		boolean verbose = false;
962 
963 		// Parse arguments
964 		for (int i = 0; i < args.length; ++i) {
965 			String arg = args[i];
966 			if (arg.startsWith("-")) {
967 				if (arg.equals("-verbose") || arg.equals("-v")) {
968 					verbose = true;
969 				} else {
970 					String next = (i < args.length - 1) ? args[++i] : null;
971 					// If specified, passed values override default values
972 					switch (arg) {
973 						case "-launcher":
974 							vmLauncherName = next;
975 							break;
976 						case "-address":
977 							targetAddress = next;
978 							break;
979 						case "-port":
980 							fBackEndPort = Integer.parseInt(next);
981 							break;
982 						case "-cp":
983 							classPath = next;
984 							break;
985 						case "-bp":
986 							bootPath = next;
987 							break;
988 						case "-vmtype":
989 							vmType = next;
990 							break;
991 						case "-stdout":
992 							fStdoutFile = next;
993 							break;
994 						case "-stderr":
995 							fStderrFile = next;
996 							break;
997 						case "-proxyout":
998 							fProxyoutFile = next;
999 							break;
1000 						case "-proxyerr":
1001 							fProxyerrFile = next;
1002 							break;
1003 						case "-vmcmd":
1004 							fVmCmd = next;
1005 							break;
1006 						case "-vmargs":
1007 							fVmArgs = next;
1008 							break;
1009 						case "-proxycmd":
1010 							fProxyCmd = next;
1011 							break;
1012 						case "-trace":
1013 							if (next.equals("all")) {
1014 								fVMTraceFlags = com.sun.jdi.VirtualMachine.TRACE_ALL;
1015 							} else {
1016 								fVMTraceFlags = Integer.decode(next).intValue();
1017 							}
1018 							break;
1019 						default:
1020 							System.out.println("Invalid option: " + arg);
1021 							printUsage();
1022 							return false;
1023 					}
1024 				}
1025 			}
1026 		}
1027 		fVMLauncherName = vmLauncherName;
1028 		fTargetAddress = targetAddress;
1029 		fClassPath = classPath;
1030 		fBootPath = bootPath;
1031 		fVMType = vmType;
1032 		fVerbose = verbose;
1033 		return true;
1034 	}
1035 	/**
1036 	 * Prints the various options to pass to the constructor.
1037 	 */
printUsage()1038 	protected static void printUsage() {
1039 		System.out.println("Possible options:");
1040 		System.out.println("-launcher <Name of the launcher class>");
1041 		System.out.println("-address <Address of the target VM>");
1042 		System.out.println("-port <Debug port number>");
1043 		System.out.println("-cp <Path to the test program>");
1044 		System.out.println("-bp <Boot classpath for the system class library>");
1045 		System.out.println("-vmtype <The type of VM: JDK, J9, ...>");
1046 		System.out.println("-verbose | -v");
1047 		System.out.println("-stdout <file where VM output is written to>");
1048 		System.out.println("-stderr <file where VM error output is written to>");
1049 		System.out.println("-proxyout <file where proxy output is written to>");
1050 		System.out.println("-proxyerr <file where proxy error output is written to>");
1051 		System.out.println("-vmcmd <exec string to start VM>");
1052 		System.out.println("-vmargs <comma-separated list of VM arguments>");
1053 		System.out.println("-proxycmd <exec string to start proxy>");
1054 	}
1055 	/**
1056 	 * Set the value of the "fBool" field back to its original value
1057 	 */
resetField()1058 	protected void resetField() {
1059 		Field field = getField("fBool");
1060 		Value value = null;
1061 		value = fVM.mirrorOf(false);
1062 		try {
1063 			getObjectReference().setValue(field, value);
1064 		} catch (ClassNotLoadedException e) {
1065 			assertTrue("resetField.2", false);
1066 		} catch (InvalidTypeException e) {
1067 			assertTrue("resetField.3", false);
1068 		}
1069 	}
1070 	/**
1071 	 * Set the value of the "fString" field back to its original value
1072 	 */
resetStaticField()1073 	protected void resetStaticField() {
1074 		Field field = getField("fString");
1075 		Value value = null;
1076 		value = fVM.mirrorOf("Hello World");
1077 		try {
1078 			getMainClass().setValue(field, value);
1079 		} catch (ClassNotLoadedException e) {
1080 			assertTrue("resetField.1", false);
1081 		} catch (InvalidTypeException e) {
1082 			assertTrue("resetField.2", false);
1083 		}
1084 	}
1085 	/**
1086 	 * Runs this test's suite with the given arguments.
1087 	 */
runSuite(String[] args)1088 	protected void runSuite(String[] args) {
1089 		// Check args
1090 		if (!parseArgs(args)) {
1091 			return;
1092 		}
1093 
1094 		// Run test
1095 		System.out.println(new java.util.Date());
1096 		System.out.println("Begin testing " + getName() + "...");
1097 		junit.textui.TestRunner.run(suite());
1098 		System.out.println("Done testing " + getName() + ".");
1099 	}
1100 	/**
1101 	 * Sets the 'in control of the VM' flag for this test.
1102 	 */
setInControl(boolean inControl)1103 	public void setInControl(boolean inControl) {
1104 		fInControl = inControl;
1105 	}
1106 	/**
1107 	 * Launch target VM and start program in target VM.
1108 	 */
launchTargetAndStartProgram()1109 	protected void launchTargetAndStartProgram() {
1110 		launchTargetAndConnectToVM();
1111 		startProgram();
1112 	}
1113 	/**
1114 	 * Init tests
1115 	 */
1116 	@Override
setUp()1117 	protected void setUp() {
1118 		if (fVM == null || fInControl) {
1119 			launchTargetAndStartProgram();
1120 		}
1121 		try {
1122 			verbose("Setting up the test");
1123 			localSetUp();
1124 		} catch (RuntimeException e) {
1125 			System.out.println("Runtime exception during set up:");
1126 			e.printStackTrace();
1127 		} catch (Error e) {
1128 			System.out.println("Error during set up:");
1129 			e.printStackTrace();
1130 		}
1131 	}
1132 	/**
1133 	 * Sets the VM info for this test.
1134 	 */
setVMInfo(VMInformation info)1135 	public void setVMInfo(VMInformation info) {
1136 		if (info != null) {
1137 			fVM = info.fVM;
1138 			fLaunchedVM = info.fLaunchedVM;
1139 			fEventReader = info.fEventReader;
1140 			fConsoleReader = info.fConsoleReader;
1141 		}
1142 	}
1143 	/**
1144 	 * Stop console and event readers.
1145 	 */
stopReaders()1146 	protected void stopReaders() {
1147 		stopEventReader();
1148 		stopConsoleReaders();
1149 	}
1150 	/**
1151 	 * Shut down the target.
1152 	 */
shutDownTarget()1153 	public void shutDownTarget() {
1154 		stopReaders();
1155 		if (fVM != null) {
1156 			try {
1157 				fVM.exit(0);
1158 			} catch (VMDisconnectedException e) {
1159 			}
1160 		}
1161 
1162 		fVM = null;
1163 		fLaunchedVM = null;
1164 
1165 		// We want subsequent connections to use different ports, unless a
1166 		// VM exec sting is given.
1167 		if (fVmCmd == null) {
1168 			fBackEndPort += 2;
1169 		}
1170 	}
1171 	/**
1172 	 * Starts the threads that reads from the VM and proxy input and error streams
1173 	 */
startConsoleReaders()1174 	private void startConsoleReaders() {
1175 		if (fStdoutFile != null) {
1176 			fConsoleReader =
1177 				new FileConsoleReader(
1178 					"JDI Tests Console Reader",
1179 					fStdoutFile,
1180 					fLaunchedVM.getInputStream());
1181 		} else {
1182 			fConsoleReader =
1183 				new NullConsoleReader("JDI Tests Console Reader", fLaunchedVM.getInputStream());
1184 		}
1185 		fConsoleReader.start();
1186 
1187 		if (fStderrFile != null) {
1188 			fConsoleErrorReader =
1189 				new FileConsoleReader(
1190 					"JDI Tests Console Error Reader",
1191 					fStderrFile,
1192 					fLaunchedVM.getErrorStream());
1193 		} else {
1194 			fConsoleErrorReader =
1195 				new NullConsoleReader(
1196 					"JDI Tests Console Error Reader",
1197 					fLaunchedVM.getErrorStream());
1198 		}
1199 		fConsoleErrorReader.start();
1200 
1201 		if (fLaunchedProxy == null) {
1202 			return;
1203 		}
1204 
1205 		if (fProxyoutFile != null) {
1206 			fProxyReader =
1207 				new FileConsoleReader(
1208 					"JDI Tests Proxy Reader",
1209 					fProxyoutFile,
1210 					fLaunchedProxy.getInputStream());
1211 		} else {
1212 			fProxyReader =
1213 				new NullConsoleReader(
1214 					"JDI Tests Proxy Reader",
1215 					fLaunchedProxy.getInputStream());
1216 		}
1217 		fProxyReader.start();
1218 
1219 		if (fProxyerrFile != null) {
1220 			fProxyErrorReader =
1221 				new FileConsoleReader(
1222 					"JDI Tests Proxy Error Reader",
1223 					fProxyerrFile,
1224 					fLaunchedProxy.getErrorStream());
1225 		} else {
1226 			fProxyErrorReader =
1227 				new NullConsoleReader(
1228 					"JDI Tests Proxy Error Reader",
1229 					fLaunchedProxy.getErrorStream());
1230 		}
1231 		fProxyErrorReader.start();
1232 	}
1233 	/**
1234 	 * Stops the console reader.
1235 	 */
stopConsoleReaders()1236 	private void stopConsoleReaders() {
1237 		if (fConsoleReader != null) {
1238 			fConsoleReader.stop();
1239 		}
1240 		if (fConsoleErrorReader != null) {
1241 			fConsoleErrorReader.stop();
1242 		}
1243 		if (fProxyReader != null) {
1244 			fProxyReader.stop();
1245 		}
1246 		if (fProxyErrorReader != null) {
1247 			fProxyErrorReader.stop();
1248 		}
1249 	}
1250 	/**
1251 	 * Starts event reader.
1252 	 */
startEventReader()1253 	private void startEventReader() {
1254 		// Create the VM event reader.
1255 		fEventReader = new EventReader("JDI Tests Event Reader", fVM.eventQueue());
1256 	}
1257 	/**
1258 	 * Stops the event reader.
1259 	 */
stopEventReader()1260 	private void stopEventReader() {
1261 		fEventReader.stop();
1262 	}
killVM()1263 	protected void killVM() {
1264 		if (fLaunchedVM != null) {
1265 			fLaunchedVM.destroy();
1266 		}
1267 		if (fLaunchedProxy != null) {
1268 			fLaunchedProxy.destroy();
1269 		}
1270 	}
1271 	/**
1272 	 * Starts the target program.
1273 	 */
startProgram()1274 	protected void startProgram() {
1275 		verbose("Starting target program");
1276 
1277 		// Request class prepare events
1278 		EventRequest classPrepareRequest =
1279 			fVM.eventRequestManager().createClassPrepareRequest();
1280 		classPrepareRequest.enable();
1281 
1282 		// Prepare to receive the token class prepare event
1283 		ClassPrepareEventWaiter waiter =
1284 			new ClassPrepareEventWaiter(
1285 				classPrepareRequest,
1286 				true,
1287 				getMainClassName());
1288 		fEventReader.addEventListener(waiter);
1289 
1290 		// Start the event reader (this will start the VM when the VMStartEvent is picked up)
1291 		fEventReader.start();
1292 
1293 		// Wait until the program has started
1294 		Event event = waitForEvent(waiter, 3 * TIMEOUT);
1295 		fEventReader.removeEventListener(waiter);
1296 		if (event == null) {
1297 //			try {
1298 				System.out.println(
1299 					"\nThe program doesn't seem to have started after " + (3 * TIMEOUT) + "ms");
1300 //				InputStream errorStream = fLaunchedVM.getErrorStream();
1301 //				int read;
1302 //				do {
1303 //					read = errorStream.read();
1304 //					if (read != -1)
1305 //						System.out.print((char) read);
1306 //				} while (read != -1);
1307 //			} catch (IOException e) {
1308 //			}
1309 		}
1310 
1311 		// Stop class prepare events
1312 		fVM.eventRequestManager().deleteEventRequest(classPrepareRequest);
1313 
1314 		// Wait for the program to be ready to be tested
1315 		waitUntilReady();
1316 	}
1317 	/**
1318 	 * Returns all tests
1319 	 */
suite()1320 	protected Test suite() {
1321 		JDITestSuite suite = new JDITestSuite(this);
1322 		Vector<String> testNames = getAllMatchingTests( getTestPrefix() );
1323 		Iterator<String> iterator = testNames.iterator();
1324 		while (iterator.hasNext()) {
1325 			String name = iterator.next();
1326 			suite.addTest(new JDITestCase(this, name));
1327 		}
1328 		return suite;
1329 	}
1330 	/**
1331 	 * Undo the initialization of the test.
1332 	 */
1333 	@Override
tearDown()1334 	protected void tearDown() {
1335 		try {
1336 			super.tearDown();
1337 		} catch (Exception e) {
1338 			System.out.println("Exception during tear down:");
1339 			e.printStackTrace();
1340 		}
1341 		try {
1342 			verbose("Tearing down the test");
1343 			localTearDown();
1344 
1345 			// Ensure that the test didn't leave a modification watchpoint that could change the expected state of the program
1346 			if (fVM != null) {
1347 				assertTrue(fVM.eventRequestManager().modificationWatchpointRequests().isEmpty());
1348 				if (fInControl) {
1349 					shutDownTarget();
1350 				}
1351 			}
1352 
1353 		} catch (RuntimeException e) {
1354 			System.out.println("Runtime exception during tear down:");
1355 			e.printStackTrace();
1356 		} catch (Error e) {
1357 			System.out.println("Error during tear down:");
1358 			e.printStackTrace();
1359 		}
1360 
1361 	}
1362 	/**
1363 	 * Triggers and waits for the given event to come in.
1364 	 * Let the thread go if asked.
1365 	 * Throws an Error if the event didn't come in after TIMEOUT ms
1366 	 */
triggerAndWait( EventRequest request, String eventType, boolean shouldGo)1367 	protected Event triggerAndWait(
1368 		EventRequest request,
1369 		String eventType,
1370 		boolean shouldGo) {
1371 		Event event = triggerAndWait(request, eventType, shouldGo, TIMEOUT);
1372 		if (event == null) {
1373 			throw new Error(
1374 				"Event for " + request + " didn't come in after " + TIMEOUT + "ms");
1375 		}
1376 
1377 		return event;
1378 	}
1379 	/**
1380 	 * Triggers and waits for the given event to come in.
1381 	 * Let the thread go if asked.
1382 	 * Returns null if the event didn't come in after the given amount of time (in ms)
1383 	 * @param time the time to wait
1384 	 */
triggerAndWait( EventRequest request, String eventType, boolean shouldGo, long time)1385 	protected Event triggerAndWait(
1386 		EventRequest request,
1387 		String eventType,
1388 		boolean shouldGo,
1389 		long time) {
1390 		// Suspend only if asked
1391 		if (shouldGo) {
1392 			request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
1393 		} else {
1394 			request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
1395 		}
1396 
1397 		// Enable request
1398 		request.enable();
1399 
1400 		// Prepare to receive the event
1401 		EventWaiter waiter = new EventWaiter(request, shouldGo);
1402 		fEventReader.addEventListener(waiter);
1403 
1404 		// Trigger the event
1405 		triggerEvent(eventType);
1406 
1407 		// Wait for the event to come in
1408 		Event event = waitForEvent(waiter, TIMEOUT);
1409 		fEventReader.removeEventListener(waiter);
1410 
1411 		if (shouldGo) {
1412 			// Wait for the program to be ready
1413 			waitUntilReady();
1414 		}
1415 
1416 		// Clear request
1417 		fVM.eventRequestManager().deleteEventRequest(request);
1418 
1419 		return event;
1420 	}
1421 	/**
1422 	 * Triggers the given type of event. See the MainClass for details on types of event.
1423 	 */
triggerEvent(String eventType)1424 	protected void triggerEvent(String eventType) {
1425 		// Set the "fEventType" field to the given eventType
1426 		ClassType type = getMainClass();
1427 		Field field = type.fieldByName("fEventType");
1428 		assertTrue("1", field != null);
1429 
1430 		Value value = null;
1431 		value = fVM.mirrorOf(eventType);
1432 		try {
1433 			type.setValue(field, value);
1434 		} catch (ClassNotLoadedException e) {
1435 			assertTrue("2", false);
1436 		} catch (InvalidTypeException e) {
1437 			assertTrue("3", false);
1438 		}
1439 
1440 		// Resume the test thread
1441 		ThreadReference thread = getThread();
1442 		int suspendCount = thread.suspendCount();
1443 		for (int i = 0; i < suspendCount; i++) {
1444 			thread.resume();
1445 		}
1446 	}
1447 	/**
1448 	 * Triggers a step event and waits for it to come in.
1449 	 */
triggerStepAndWait()1450 	protected StepEvent triggerStepAndWait() {
1451 		return triggerStepAndWait(
1452 			getThread(),
1453 			StepRequest.STEP_MIN,
1454 			StepRequest.STEP_OVER);
1455 	}
1456 
triggerStepAndWait( ThreadReference thread, int gran, int depth)1457 	protected StepEvent triggerStepAndWait(
1458 		ThreadReference thread,
1459 		int gran,
1460 		int depth) {
1461 		// Request for step events
1462 		EventRequest eventRequest =
1463 			fVM.eventRequestManager().createStepRequest(thread, gran, depth);
1464 		eventRequest.addCountFilter(1);
1465 		eventRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
1466 		eventRequest.enable();
1467 
1468 		return triggerStepAndWait(thread, eventRequest, TIMEOUT);
1469 	}
1470 
triggerStepAndWait( ThreadReference thread, EventRequest eventRequest, int timeout)1471 	protected StepEvent triggerStepAndWait(
1472 		ThreadReference thread,
1473 		EventRequest eventRequest,
1474 		int timeout) {
1475 		// Prepare to receive the event
1476 		EventWaiter waiter = new EventWaiter(eventRequest, true);
1477 		fEventReader.addEventListener(waiter);
1478 
1479 		// Trigger step event
1480 		int suspendCount = thread.suspendCount();
1481 		for (int i = 0; i < suspendCount; i++) {
1482 			thread.resume();
1483 		}
1484 
1485 		// Wait for the event to come in
1486 		StepEvent event = (StepEvent) waitForEvent(waiter, timeout);
1487 		fEventReader.removeEventListener(waiter);
1488 		if (event == null) {
1489 			throw new Error("StepEvent didn't come in after " + timeout + "ms");
1490 		}
1491 
1492 		// Stop getting step events
1493 		fVM.eventRequestManager().deleteEventRequest(eventRequest);
1494 
1495 		// Wait for the program to be ready
1496 		waitUntilReady();
1497 
1498 		return event;
1499 	}
1500 	/**
1501 	 * Output verbose string if asked for.
1502 	 */
verbose(String verboseString)1503 	protected void verbose(String verboseString) {
1504 		if (fVerbose) {
1505 			System.out.println(verboseString);
1506 		}
1507 	}
1508 	/**
1509 	 * Waits for an event to come in using the given waiter.
1510 	 * Waits for the given time. If it times out, returns null.
1511 	 */
waitForEvent(EventWaiter waiter, long time)1512 	protected Event waitForEvent(EventWaiter waiter, long time) {
1513 		Event event;
1514 		try {
1515 			event = waiter.waitEvent(time);
1516 		} catch (InterruptedException e) {
1517 			event = null;
1518 		}
1519 		return event;
1520 	}
1521 	/**
1522 	 * Waits until the program is ready to be tested.
1523 	 * The default behavior is to wait until the "Test Thread" throws and catches
1524 	 * an exception.
1525 	 */
waitUntilReady()1526 	protected void waitUntilReady() {
1527 		// Make sure the program is running
1528 		ThreadReference thread = getThread();
1529 		while (thread == null || thread.suspendCount() > 0) {
1530 			fVM.resume();
1531 			thread = getThread();
1532 		}
1533 
1534 		// Create exception request
1535 		EventRequest request =
1536 			fVM.eventRequestManager().createExceptionRequest(null, true, false);
1537 		request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
1538 
1539 		// Prepare to receive the event
1540 		EventWaiter waiter = new EventWaiter(request, false);
1541 		fEventReader.addEventListener(waiter);
1542 
1543 		request.enable();
1544 
1545 		while (true) {
1546 			// Wait for the event to come in
1547 			ExceptionEvent event = (ExceptionEvent) waitForEvent(waiter, TIMEOUT);
1548 
1549 			// Throw error if event is null
1550 			if (event == null) {
1551 				throw new Error("Target program was not ready after " + TIMEOUT + "ms");
1552 			}
1553 
1554 			// Get the method where the exception was thrown
1555 			Method meth = event.location().method();
1556 			if (meth == null || !meth.name().equals("printAndSignal")) {
1557 				fVM.resume();
1558 			} else {
1559 				break;
1560 			}
1561 		}
1562 
1563 		// Disable request
1564 		fEventReader.removeEventListener(waiter);
1565 		fVM.eventRequestManager().deleteEventRequest(request);
1566 	}
1567 }
1568