KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > junit > launcher > JUnitLaunchConfigurationDelegate


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * David Saff (saff@mit.edu) - bug 102632: [JUnit] Support for JUnit 4.
11  *******************************************************************************/

12 package org.eclipse.jdt.junit.launcher;
13
14 import java.io.BufferedWriter JavaDoc;
15 import java.io.File JavaDoc;
16 import java.io.FileWriter JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.net.MalformedURLException JavaDoc;
19 import java.net.URL JavaDoc;
20 import java.text.MessageFormat JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.eclipse.core.runtime.Assert;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.FileLocator;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.IStatus;
32 import org.eclipse.core.runtime.NullProgressMonitor;
33 import org.eclipse.core.runtime.Platform;
34 import org.eclipse.core.runtime.Status;
35 import org.eclipse.core.runtime.SubProgressMonitor;
36
37 import org.eclipse.core.variables.VariablesPlugin;
38
39 import org.eclipse.swt.widgets.Display;
40 import org.eclipse.swt.widgets.Shell;
41
42 import org.eclipse.jface.dialogs.MessageDialog;
43
44 import org.eclipse.debug.core.ILaunch;
45 import org.eclipse.debug.core.ILaunchConfiguration;
46 import org.eclipse.debug.core.ILaunchManager;
47
48 import org.eclipse.jdt.core.IJavaElement;
49 import org.eclipse.jdt.core.IJavaProject;
50 import org.eclipse.jdt.core.IMember;
51 import org.eclipse.jdt.core.IMethod;
52 import org.eclipse.jdt.core.IType;
53 import org.eclipse.jdt.core.JavaCore;
54
55 import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
56 import org.eclipse.jdt.launching.ExecutionArguments;
57 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
58 import org.eclipse.jdt.launching.IVMRunner;
59 import org.eclipse.jdt.launching.SocketUtil;
60 import org.eclipse.jdt.launching.VMRunnerConfiguration;
61
62 import org.eclipse.jdt.internal.junit.Messages;
63 import org.eclipse.jdt.internal.junit.launcher.ITestKind;
64 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
65 import org.eclipse.jdt.internal.junit.launcher.JUnitRuntimeClasspathEntry;
66 import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
67 import org.eclipse.jdt.internal.junit.ui.JUnitMessages;
68 import org.eclipse.jdt.internal.junit.ui.JUnitPlugin;
69 import org.eclipse.jdt.internal.junit.util.IJUnitStatusConstants;
70 import org.eclipse.jdt.internal.junit.util.TestSearchEngine;
71
72 import org.osgi.framework.Bundle;
73
74 /**
75  * Launch configuration delegate for a JUnit test as a Java application.
76  *
77  * <p>
78  * Clients can instantiate and extend this class.
79  * </p>
80  * @since 3.3
81  */

82 public class JUnitLaunchConfigurationDelegate extends AbstractJavaLaunchConfigurationDelegate {
83
84     private boolean fKeepAlive= false;
85     private int fPort;
86     private IMember[] fTestElements;
87     
88     /* (non-Javadoc)
89      * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
90      */

91     public void launch(ILaunchConfiguration configuration, String JavaDoc mode, ILaunch launch, IProgressMonitor monitor) throws CoreException {
92         if (monitor == null) {
93             monitor = new NullProgressMonitor();
94         }
95         
96         monitor.beginTask(MessageFormat.format("{0}...", new String JavaDoc[]{configuration.getName()}), 5); //$NON-NLS-1$
97
// check for cancellation
98
if (monitor.isCanceled()) {
99             return;
100         }
101         
102         try {
103             if (mode.equals(JUnitLaunchConfigurationConstants.MODE_RUN_QUIETLY_MODE)) {
104                 launch.setAttribute(JUnitLaunchConfigurationConstants.ATTR_NO_DISPLAY, "true"); //$NON-NLS-1$
105
mode = ILaunchManager.RUN_MODE;
106             }
107             
108             monitor.subTask(JUnitMessages.JUnitLaunchConfigurationDelegate_verifying_attriburtes_description);
109             
110             try {
111                 preLaunchCheck(configuration, launch, new SubProgressMonitor(monitor, 2));
112             } catch (CoreException e) {
113                 if (e.getStatus().getSeverity() == IStatus.CANCEL) {
114                     monitor.setCanceled(true);
115                     return;
116                 }
117                 throw e;
118             }
119             // check for cancellation
120
if (monitor.isCanceled()) {
121                 return;
122             }
123             
124             fKeepAlive= mode.equals(ILaunchManager.DEBUG_MODE) && configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_KEEPRUNNING, false);
125             fPort= evaluatePort();
126             launch.setAttribute(JUnitLaunchConfigurationConstants.ATTR_PORT, String.valueOf(fPort));
127                 
128             fTestElements= evaluateTests(configuration, new SubProgressMonitor(monitor, 1));
129
130             String JavaDoc mainTypeName= verifyMainTypeName(configuration);
131             IVMRunner runner= getVMRunner(configuration, mode);
132
133             File JavaDoc workingDir = verifyWorkingDirectory(configuration);
134             String JavaDoc workingDirName = null;
135             if (workingDir != null) {
136                 workingDirName= workingDir.getAbsolutePath();
137             }
138             
139             // Environment variables
140
String JavaDoc[] envp= getEnvironment(configuration);
141             
142             ArrayList JavaDoc vmArguments= new ArrayList JavaDoc();
143             ArrayList JavaDoc programArguments= new ArrayList JavaDoc();
144             collectExecutionArguments(configuration, vmArguments, programArguments);
145             
146             // VM-specific attributes
147
Map JavaDoc vmAttributesMap= getVMSpecificAttributesMap(configuration);
148             
149             // Classpath
150
String JavaDoc[] classpath= getClasspath(configuration);
151             
152             // Create VM config
153
VMRunnerConfiguration runConfig= new VMRunnerConfiguration(mainTypeName, classpath);
154             runConfig.setVMArguments((String JavaDoc[]) vmArguments.toArray(new String JavaDoc[vmArguments.size()]));
155             runConfig.setProgramArguments((String JavaDoc[]) programArguments.toArray(new String JavaDoc[programArguments.size()]));
156             runConfig.setEnvironment(envp);
157             runConfig.setWorkingDirectory(workingDirName);
158             runConfig.setVMSpecificAttributesMap(vmAttributesMap);
159
160             // Bootpath
161
runConfig.setBootClassPath(getBootpath(configuration));
162             
163             // check for cancellation
164
if (monitor.isCanceled()) {
165                 return;
166             }
167             
168             // done the verification phase
169
monitor.worked(1);
170             
171             monitor.subTask(JUnitMessages.JUnitLaunchConfigurationDelegate_create_source_locator_description);
172             // set the default source locator if required
173
setDefaultSourceLocator(launch, configuration);
174             monitor.worked(1);
175             
176             // Launch the configuration - 1 unit of work
177
runner.run(runConfig, launch, monitor);
178             
179             // check for cancellation
180
if (monitor.isCanceled()) {
181                 return;
182             }
183         } finally {
184             fTestElements= null;
185             monitor.done();
186         }
187     }
188     
189     private int evaluatePort() throws CoreException {
190         int port= SocketUtil.findFreePort();
191         if (port == -1) {
192             informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_no_socket, null, IJavaLaunchConfigurationConstants.ERR_NO_SOCKET_AVAILABLE);
193         }
194         return port;
195     }
196     
197     /**
198      * Performs a check on the launch configuration's attributes. If an attribute contains an invalid value, a {@link CoreException}
199      * with the error is thrown.
200      *
201      * @param configuration the launch configuration to verify
202      * @param launch the launch to verify
203      * @param monitor the progress monitor to use
204      * @throws CoreException an exception is thrown when the verification fails
205      */

206     protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor) throws CoreException {
207         try {
208             IJavaProject javaProject= getJavaProject(configuration);
209             if ((javaProject == null) || !javaProject.exists()) {
210                 informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_invalidproject, null, IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT);
211             }
212             if (!TestSearchEngine.hasTestCaseType(javaProject)) {
213                 informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junitnotonpath, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
214             }
215
216             ITestKind testKind= getTestRunnerKind(configuration);
217             boolean isJUnit4Configuration= TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId());
218             if (isJUnit4Configuration && ! TestSearchEngine.hasTestAnnotation(javaProject)) {
219                 informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junit4notonpath, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
220             }
221         } finally {
222             monitor.done();
223         }
224     }
225
226     private ITestKind getTestRunnerKind(ILaunchConfiguration configuration) {
227         ITestKind testKind= JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
228         if (testKind.isNull()) {
229             testKind= TestKindRegistry.getDefault().getKind(TestKindRegistry.JUNIT3_TEST_KIND_ID); // backward compatible for launch configurations with no runner
230
}
231         return testKind;
232     }
233     
234     /* (non-Javadoc)
235      * @see org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate#verifyMainTypeName(org.eclipse.debug.core.ILaunchConfiguration)
236      */

237     public String JavaDoc verifyMainTypeName(ILaunchConfiguration configuration) throws CoreException {
238         return "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner"; //$NON-NLS-1$
239
}
240
241     /**
242      * Evaluates all test elements selected by the given launch configuration. The elements are of type
243      * {@link IType} or {@link IMethod}. At the moment it is only possible to run a single method or a set of types, but not
244      * mixed or more than one method at a time.
245      *
246      * @param configuration the launch configuration to inspect
247      * @param monitor the progress monitor
248      * @return returns all types or methods that should be ran
249      * @throws CoreException an exception is thrown when the search for tests failed
250      */

251     protected IMember[] evaluateTests(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
252         IJavaProject javaProject= getJavaProject(configuration);
253         
254         IJavaElement testTarget= getTestTarget(configuration, javaProject);
255         String JavaDoc testMethodName= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, ""); //$NON-NLS-1$
256
if (testMethodName.length() > 0) {
257             if (testTarget instanceof IType) {
258                 return new IMember[] { ((IType) testTarget).getMethod(testMethodName, new String JavaDoc[0]) };
259             }
260         }
261         HashSet JavaDoc result= new HashSet JavaDoc();
262         ITestKind testKind= getTestRunnerKind(configuration);
263         testKind.getFinder().findTestsInContainer(testTarget, result, monitor);
264         if (result.isEmpty()) {
265             String JavaDoc msg= Messages.format(JUnitMessages.JUnitLaunchConfigurationDelegate_error_notests_kind, testKind.getDisplayName());
266             informAndAbort(msg, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
267         }
268         return (IMember[]) result.toArray(new IMember[result.size()]);
269     }
270
271     private void informAndAbort(String JavaDoc message, Throwable JavaDoc exception, int code) throws CoreException {
272         IStatus status= new Status(IStatus.INFO, JUnitPlugin.PLUGIN_ID, code, message, exception);
273         if (showStatusMessage(status)) {
274             // Status message successfully shown
275
// -> Abort with INFO exception
276
// -> Worker.run() will not write to log
277
throw new CoreException(status);
278         } else {
279             // Status message could not be shown
280
// -> Abort with original exception
281
// -> Will write WARNINGs and ERRORs to log
282
abort(message, exception, code);
283         }
284     }
285     
286     /**
287      * Collects all VM and program arguments. Implementors can modify and add arguments.
288      *
289      * @param configuration the configuration to collect the arguments for
290      * @param vmArguments a {@link List} of {@link String} representing the resulting VM arguments
291      * @param programArguments a {@link List} of {@link String} representing the resulting program arguments
292      * @exception CoreException if unable to collect the execution arguments
293      */

294     protected void collectExecutionArguments(ILaunchConfiguration configuration, List JavaDoc/*String*/ vmArguments, List JavaDoc/*String*/ programArguments) throws CoreException {
295
296         // add program & VM arguments provided by getProgramArguments and getVMArguments
297
String JavaDoc pgmArgs= getProgramArguments(configuration);
298         String JavaDoc vmArgs= getVMArguments(configuration);
299         ExecutionArguments execArgs= new ExecutionArguments(vmArgs, pgmArgs);
300         vmArguments.addAll(Arrays.asList(execArgs.getVMArgumentsArray()));
301         programArguments.addAll(Arrays.asList(execArgs.getProgramArgumentsArray()));
302         
303         String JavaDoc testFailureNames= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_FAILURES_NAMES, ""); //$NON-NLS-1$
304

305         programArguments.add("-version"); //$NON-NLS-1$
306
programArguments.add("3"); //$NON-NLS-1$
307

308         programArguments.add("-port"); //$NON-NLS-1$
309
programArguments.add(String.valueOf(fPort));
310
311         if (fKeepAlive)
312             programArguments.add(0, "-keepalive"); //$NON-NLS-1$
313

314         ITestKind testRunnerKind= getTestRunnerKind(configuration);
315         
316         programArguments.add("-testLoaderClass"); //$NON-NLS-1$
317
programArguments.add(testRunnerKind.getLoaderClassName());
318         programArguments.add("-loaderpluginname"); //$NON-NLS-1$
319
programArguments.add(testRunnerKind.getLoaderPluginId());
320         
321         IMember[] testElements = fTestElements;
322         
323         // a test name was specified just run the single test
324
if (testElements.length == 1) {
325             if (testElements[0] instanceof IMethod) {
326                 IMethod method= (IMethod) testElements[0];
327                 programArguments.add("-test"); //$NON-NLS-1$
328
programArguments.add(method.getDeclaringType().getFullyQualifiedName()+':'+method.getElementName());
329             } else if (testElements[0] instanceof IType) {
330                 IType type= (IType) testElements[0];
331                 programArguments.add("-classNames"); //$NON-NLS-1$
332
programArguments.add(type.getFullyQualifiedName());
333             } else {
334                 informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_wrong_input, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
335             }
336         } else if (testElements.length > 1) {
337             String JavaDoc fileName= createTestNamesFile(testElements);
338             programArguments.add("-testNameFile"); //$NON-NLS-1$
339
programArguments.add(fileName);
340         }
341         if (testFailureNames.length() > 0) {
342             programArguments.add("-testfailures"); //$NON-NLS-1$
343
programArguments.add(testFailureNames);
344         }
345     }
346
347     private String JavaDoc createTestNamesFile(IMember[] testElements) throws CoreException {
348         try {
349             File JavaDoc file= File.createTempFile("testNames", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$
350
file.deleteOnExit();
351             BufferedWriter JavaDoc bw= null;
352             try {
353                 bw= new BufferedWriter JavaDoc(new FileWriter JavaDoc(file));
354                 for (int i= 0; i < testElements.length; i++) {
355                     if (testElements[i] instanceof IType) {
356                         IType type= (IType) testElements[i];
357                         String JavaDoc testName= type.getFullyQualifiedName();
358                         bw.write(testName);
359                         bw.newLine();
360                     } else {
361                         informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_wrong_input, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
362                     }
363                 }
364             } finally {
365                 if (bw != null) {
366                     bw.close();
367                 }
368             }
369             return file.getAbsolutePath();
370         } catch (IOException JavaDoc e) {
371             throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
372
}
373     }
374     
375     /* (non-Javadoc)
376      * @see org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate#getClasspath(org.eclipse.debug.core.ILaunchConfiguration)
377      */

378     public String JavaDoc[] getClasspath(ILaunchConfiguration configuration) throws CoreException {
379         String JavaDoc[] cp= super.getClasspath(configuration);
380         
381         ITestKind kind= getTestRunnerKind(configuration);
382         List JavaDoc junitEntries = new ClasspathLocalizer(Platform.inDevelopmentMode()).localizeClasspath(kind);
383                 
384         String JavaDoc[] classPath= new String JavaDoc[cp.length + junitEntries.size()];
385         Object JavaDoc[] jea= junitEntries.toArray();
386         System.arraycopy(cp, 0, classPath, 0, cp.length);
387         System.arraycopy(jea, 0, classPath, cp.length, jea.length);
388         return classPath;
389     }
390
391     private static class ClasspathLocalizer {
392         
393         private boolean fInDevelopmentMode;
394     
395         protected ClasspathLocalizer() {
396             this(false);
397         }
398     
399         public ClasspathLocalizer(boolean inDevelopmentMode) {
400             fInDevelopmentMode = inDevelopmentMode;
401         }
402     
403         public List JavaDoc localizeClasspath(ITestKind kind) {
404             JUnitRuntimeClasspathEntry[] entries= kind.getClasspathEntries();
405             List JavaDoc junitEntries= new ArrayList JavaDoc();
406             
407             for (int i= 0; i < entries.length; i++) {
408                 try {
409                     addEntry(junitEntries, entries[i]);
410                 } catch (IOException JavaDoc e) {
411                     Assert.isTrue(false, entries[i].getPluginId() + " is available (required JAR)"); //$NON-NLS-1$
412
}
413             }
414             return junitEntries;
415         }
416     
417         private void addEntry(List JavaDoc junitEntries, final JUnitRuntimeClasspathEntry entry) throws IOException JavaDoc, MalformedURLException JavaDoc {
418             String JavaDoc entryString= entryString(entry);
419             if (entryString != null)
420                 junitEntries.add(entryString);
421         }
422     
423         private String JavaDoc entryString(final JUnitRuntimeClasspathEntry entry) throws IOException JavaDoc, MalformedURLException JavaDoc {
424             if (inDevelopmentMode()) {
425                 try {
426                     return localURL(entry.developmentModeEntry());
427                 } catch (IOException JavaDoc e3) {
428                     // fall through and try default
429
}
430             }
431             return localURL(entry);
432         }
433     
434         private boolean inDevelopmentMode() {
435             return fInDevelopmentMode;
436         }
437         
438         private String JavaDoc localURL(JUnitRuntimeClasspathEntry jar) throws IOException JavaDoc, MalformedURLException JavaDoc {
439             Bundle bundle= JUnitPlugin.getDefault().getBundle(jar.getPluginId());
440             URL JavaDoc url;
441             if (jar.getPluginRelativePath() == null)
442                 url= bundle.getEntry("/"); //$NON-NLS-1$
443
else
444                 url= bundle.getEntry(jar.getPluginRelativePath());
445             if (url == null)
446                 throw new IOException JavaDoc();
447             return FileLocator.toFileURL(url).getFile();
448         }
449     }
450
451     private final IJavaElement getTestTarget(ILaunchConfiguration configuration, IJavaProject javaProject) throws CoreException {
452         String JavaDoc containerHandle = configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$
453
if (containerHandle.length() != 0) {
454              IJavaElement element= JavaCore.create(containerHandle);
455              if (element == null || !element.exists()) {
456                  informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_input_element_deosn_not_exist, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
457              }
458              return element;
459         }
460         String JavaDoc testTypeName= configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, ""); //$NON-NLS-1$
461
if (testTypeName.length() != 0) {
462             testTypeName= performStringSubstitution(testTypeName);
463             IType type= javaProject.findType(testTypeName);
464             if (type != null && type.exists()) {
465                 return type;
466             }
467         }
468         informAndAbort(JUnitMessages.JUnitLaunchConfigurationDelegate_input_type_does_not_exist, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
469         return null; // not reachable
470
}
471     
472     private final String JavaDoc performStringSubstitution(String JavaDoc testTypeName) throws CoreException {
473         return VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(testTypeName);
474     }
475
476     private boolean showStatusMessage(final IStatus status) {
477         final boolean[] success= new boolean[] { false };
478         getDisplay().syncExec(
479                 new Runnable JavaDoc() {
480                     public void run() {
481                         Shell shell= JUnitPlugin.getActiveWorkbenchShell();
482                         if (shell == null)
483                             shell= getDisplay().getActiveShell();
484                         if (shell != null) {
485                             MessageDialog.openInformation(shell, JUnitMessages.JUnitLaunchConfigurationDelegate_dialog_title, status.getMessage());
486                             success[0]= true;
487                         }
488                     }
489                 }
490         );
491         return success[0];
492     }
493     
494     private Display getDisplay() {
495         Display display;
496         display= Display.getCurrent();
497         if (display == null)
498             display= Display.getDefault();
499         return display;
500     }
501     
502     /* (non-Javadoc)
503      * @see org.eclipse.jdt.internal.junit.launcher.ITestFindingAbortHandler#abort(java.lang.String, java.lang.Throwable, int)
504      */

505     protected void abort(String JavaDoc message, Throwable JavaDoc exception, int code) throws CoreException {
506         throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, code, message, exception));
507     }
508     
509 }
510
Popular Tags