2 * Copyright 2000-2011 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.execution.junit;
19 import com.intellij.ExtensionPoints;
20 import com.intellij.execution.*;
21 import com.intellij.execution.configurations.*;
22 import com.intellij.execution.junit2.TestProxy;
23 import com.intellij.execution.junit2.segments.DeferredActionsQueue;
24 import com.intellij.execution.junit2.segments.DeferredActionsQueueImpl;
25 import com.intellij.execution.junit2.segments.DispatchListener;
26 import com.intellij.execution.junit2.segments.Extractor;
27 import com.intellij.execution.junit2.ui.JUnitTreeConsoleView;
28 import com.intellij.execution.junit2.ui.TestsPacketsReceiver;
29 import com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction;
30 import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
31 import com.intellij.execution.junit2.ui.model.RootTestInfo;
32 import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
33 import com.intellij.execution.process.ProcessAdapter;
34 import com.intellij.execution.process.ProcessEvent;
35 import com.intellij.execution.runners.ProgramRunner;
36 import com.intellij.execution.testframework.*;
37 import com.intellij.execution.ui.ConsoleViewContentType;
38 import com.intellij.execution.util.JavaParametersUtil;
39 import com.intellij.execution.util.ProgramParametersUtil;
40 import com.intellij.openapi.Disposable;
41 import com.intellij.openapi.application.ApplicationManager;
42 import com.intellij.openapi.diagnostic.Logger;
43 import com.intellij.openapi.extensions.Extensions;
44 import com.intellij.openapi.module.Module;
45 import com.intellij.openapi.project.Project;
46 import com.intellij.openapi.projectRoots.JavaSdkType;
47 import com.intellij.openapi.projectRoots.Sdk;
48 import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
49 import com.intellij.openapi.roots.ModuleRootManager;
50 import com.intellij.openapi.roots.ProjectRootManager;
51 import com.intellij.openapi.util.Comparing;
52 import com.intellij.openapi.util.Disposer;
53 import com.intellij.openapi.util.Getter;
54 import com.intellij.openapi.util.Key;
55 import com.intellij.openapi.util.io.FileUtil;
56 import com.intellij.psi.PsiClass;
57 import com.intellij.psi.PsiElement;
58 import com.intellij.psi.PsiMethod;
59 import com.intellij.psi.PsiPackage;
60 import com.intellij.refactoring.listeners.RefactoringElementListener;
61 import com.intellij.rt.execution.junit.IDEAJUnitListener;
62 import com.intellij.rt.execution.junit.JUnitStarter;
63 import com.intellij.util.Function;
64 import com.intellij.util.IJSwingUtilities;
65 import com.intellij.util.PathUtil;
66 import org.jetbrains.annotations.NotNull;
69 import java.io.IOException;
70 import java.io.PrintWriter;
71 import java.util.ArrayList;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.List;
76 public abstract class TestObject implements JavaCommandLine {
77 protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject");
79 private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message");
81 protected JavaParameters myJavaParameters;
82 private final Project myProject;
83 protected final JUnitConfiguration myConfiguration;
84 private final RunnerSettings myRunnerSettings;
85 private final ConfigurationPerRunnerSettings myConfigurationSettings;
86 protected File myTempFile = null;
87 public File myListenersFile;
89 public static TestObject fromString(final String id,
90 final Project project,
91 final JUnitConfiguration configuration,
92 RunnerSettings runnerSettings, ConfigurationPerRunnerSettings configurationSettings) {
93 if (JUnitConfiguration.TEST_METHOD.equals(id))
94 return new TestMethod(project, configuration, runnerSettings, configurationSettings);
95 if (JUnitConfiguration.TEST_CLASS.equals(id))
96 return new TestClass(project, configuration, runnerSettings, configurationSettings);
97 if (JUnitConfiguration.TEST_PACKAGE.equals(id))
98 return new TestPackage(project, configuration, runnerSettings, configurationSettings);
99 else if (JUnitConfiguration.TEST_DIRECTORY.equals(id)) {
100 return new TestDirectory(project, configuration, runnerSettings, configurationSettings);
102 if (JUnitConfiguration.TEST_PATTERN.equals(id)) {
103 return new TestsPattern(project, configuration, runnerSettings, configurationSettings);
105 return NOT_CONFIGURED;
108 public Module[] getModulesToCompile() {
109 final SourceScope sourceScope = getSourceScope();
110 return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY;
113 protected TestObject(final Project project,
114 final JUnitConfiguration configuration,
115 RunnerSettings runnerSettings,
116 ConfigurationPerRunnerSettings configurationSettings) {
118 myConfiguration = configuration;
119 myRunnerSettings = runnerSettings;
120 myConfigurationSettings = configurationSettings;
123 public abstract String suggestActionName();
125 public RunnerSettings getRunnerSettings() {
126 return myRunnerSettings;
129 public ConfigurationPerRunnerSettings getConfigurationSettings() {
130 return myConfigurationSettings;
133 public abstract RefactoringElementListener getListener(PsiElement element, JUnitConfiguration configuration);
135 public abstract boolean isConfiguredByElement(JUnitConfiguration configuration,
137 PsiMethod testMethod,
138 PsiPackage testPackage);
140 protected void configureModule(final JavaParameters parameters, final RunConfigurationModule configurationModule, final String mainClassName)
141 throws CantRunException {
142 int classPathType = JavaParametersUtil.getClasspathType(configurationModule, mainClassName, true);
143 JavaParametersUtil.configureModule(configurationModule, parameters, classPathType,
144 myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null);
147 private static final TestObject NOT_CONFIGURED = new TestObject(null, null, null, null) {
148 public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
153 public String suggestActionName() {
154 throw new RuntimeException(String.valueOf(myConfiguration));
158 public boolean isConfiguredByElement(final JUnitConfiguration configuration,
160 PsiMethod testMethod,
161 PsiPackage testPackage) {
166 public void checkConfiguration() throws RuntimeConfigurationException {
167 throw new RuntimeConfigurationError(MESSAGE);
171 public JavaParameters getJavaParameters() throws ExecutionException {
172 throw new ExecutionException(MESSAGE);
176 protected void initialize() throws ExecutionException {
177 throw new ExecutionException(MESSAGE);
181 public void checkConfiguration() throws RuntimeConfigurationException{
182 JavaParametersUtil.checkAlternativeJRE(myConfiguration);
183 ProgramParametersUtil.checkWorkingDirectoryExist(myConfiguration, myConfiguration.getProject(), myConfiguration.getConfigurationModule().getModule());
186 public SourceScope getSourceScope() {
187 return SourceScope.modulesWithDependencies(myConfiguration.getModules());
190 protected void initialize() throws ExecutionException {
191 JavaParametersUtil.configureConfiguration(myJavaParameters, myConfiguration);
192 myJavaParameters.setMainClass(JUnitConfiguration.JUNIT_START_CLASS);
193 final Module module = myConfiguration.getConfigurationModule().getModule();
194 if (myJavaParameters.getJdk() == null){
195 myJavaParameters.setJdk(module != null
196 ? ModuleRootManager.getInstance(module).getSdk()
197 : ProjectRootManager.getInstance(myProject).getProjectSdk());
200 myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath());
201 myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class));
202 myJavaParameters.getProgramParametersList().add(JUnitStarter.IDE_VERSION + JUnitStarter.VERSION);
203 for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
204 ext.updateJavaParameters(myConfiguration, myJavaParameters, myRunnerSettings);
207 final Object[] listeners = Extensions.getExtensions(IDEAJUnitListener.EP_NAME);
208 final StringBuilder buf = new StringBuilder();
209 for (final Object listener : listeners) {
210 boolean enabled = true;
211 for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
212 if (ext.isListenerDisabled(myConfiguration, listener, myRunnerSettings)) {
218 final Class classListener = listener.getClass();
219 buf.append(classListener.getName()).append("\n");
220 myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(classListener));
223 if (buf.length() > 0) {
225 myListenersFile = FileUtil.createTempFile("junit_listeners_", "");
226 myListenersFile.deleteOnExit();
227 myJavaParameters.getProgramParametersList().add("@@" + myListenersFile.getPath());
228 FileUtil.writeToFile(myListenersFile, buf.toString().getBytes());
230 catch (IOException e) {
236 public JavaParameters getJavaParameters() throws ExecutionException {
237 if (myJavaParameters == null) {
238 myJavaParameters = new JavaParameters();
240 final Module module = myConfiguration.getConfigurationModule().getModule();
241 final Object[] patchers = Extensions.getExtensions(ExtensionPoints.JUNIT_PATCHER);
242 for (Object patcher : patchers) {
243 ((JUnitPatcher)patcher).patchJavaParameters(module, myJavaParameters);
246 return myJavaParameters;
249 public ExecutionResult execute(final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
250 final JUnitProcessHandler handler = createHandler();
251 final RunnerSettings runnerSettings = getRunnerSettings();
252 JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings);
253 final TestProxy unboundOutputRoot = new TestProxy(new RootTestInfo());
254 final JUnitConsoleProperties consoleProperties = new JUnitConsoleProperties(myConfiguration, executor);
255 final JUnitTreeConsoleView consoleView = new JUnitTreeConsoleView(consoleProperties, runnerSettings, getConfigurationSettings(), unboundOutputRoot);
256 consoleView.initUI();
257 consoleView.attachToProcess(handler);
258 unboundOutputRoot.setPrinter(consoleView.getPrinter());
259 Disposer.register(consoleView, unboundOutputRoot);
260 final TestsPacketsReceiver packetsReceiver = new TestsPacketsReceiver(consoleView, unboundOutputRoot) {
262 public void notifyStart(TestProxy root) {
263 super.notifyStart(root);
264 unboundOutputRoot.addChild(root);
265 if (myConfiguration.isSaveOutputToFile()) {
266 unboundOutputRoot.setOutputFilePath(myConfiguration.getOutputFilePath());
268 final JUnitRunningModel model = getModel();
270 handler.getOut().setDispatchListener(model.getNotifier());
271 Disposer.register(model, new Disposable() {
272 public void dispose() {
273 handler.getOut().setDispatchListener(DispatchListener.DEAF);
276 consoleView.attachToModel(model);
281 final DeferredActionsQueue queue = new DeferredActionsQueueImpl();
282 handler.getOut().setPacketDispatcher(packetsReceiver, queue);
283 handler.getErr().setPacketDispatcher(packetsReceiver, queue);
285 handler.addProcessListener(new ProcessAdapter() {
287 public void processTerminated(ProcessEvent event) {
288 handler.removeProcessListener(this);
289 if (myTempFile != null) {
290 FileUtil.delete(myTempFile);
292 if (myListenersFile != null) {
293 FileUtil.delete(myListenersFile);
295 IJSwingUtilities.invoke(new Runnable() {
297 unboundOutputRoot.flush();
298 packetsReceiver.checkTerminated();
299 final JUnitRunningModel model = packetsReceiver.getModel();
300 notifyByBalloon(model, consoleProperties);
306 public void onTextAvailable(final ProcessEvent event, final Key outputType) {
307 final String text = event.getText();
308 final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
309 final Printable printable = new Printable() {
310 public void printOn(final Printer printer) {
311 printer.print(text, consoleViewType);
314 final Extractor extractor;
315 if (consoleViewType == ConsoleViewContentType.ERROR_OUTPUT ||
316 consoleViewType == ConsoleViewContentType.SYSTEM_OUTPUT) {
317 extractor = handler.getErr();
320 extractor = handler.getOut();
322 extractor.getEventsDispatcher().processOutput(printable);
326 if (ApplicationManager.getApplication().isUnitTestMode()) {
327 return new DefaultExecutionResult(null, handler);
330 final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView.getComponent());
331 rerunFailedTestsAction.init(consoleProperties, myRunnerSettings, myConfigurationSettings);
332 rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
333 public TestFrameworkRunningModel get() {
334 return packetsReceiver.getModel();
338 final DefaultExecutionResult result = new DefaultExecutionResult(consoleView, handler);
339 result.setRestartActions(rerunFailedTestsAction);
343 protected void notifyByBalloon(JUnitRunningModel model, JUnitConsoleProperties consoleProperties) {
344 TestsUIUtil.notifyByBalloon(myProject, model != null ? model.getRoot() : null, consoleProperties);
347 protected JUnitProcessHandler createHandler() throws ExecutionException {
349 return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myProject, true));
352 private void appendForkInfo() throws ExecutionException {
353 final String forkMode = myConfiguration.getForkMode();
354 if (Comparing.strEqual(forkMode, "none")) {
358 if (myRunnerSettings.getData() instanceof DebuggingRunnerData) {
359 throw new CantRunException("Debug is disabled in fork mode.<br/>Please change fork mode to <none> to debug.");
362 final JavaParameters javaParameters = getJavaParameters();
363 final Sdk jdk = javaParameters.getJdk();
365 throw new ExecutionException(ExecutionBundle.message("run.configuration.error.no.jdk.specified"));
369 final File tempFile = FileUtil.createTempFile("command.line", "", true);
370 final PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
372 writer.println(((JavaSdkType)jdk.getSdkType()).getVMExecutablePath(jdk));
373 for (String vmParameter : javaParameters.getVMParametersList().getList()) {
374 writer.println(vmParameter);
376 writer.println("-classpath");
377 writer.println(javaParameters.getClassPath().getPathsString());
383 myJavaParameters.getProgramParametersList().add("@@@" + forkMode + ',' + tempFile.getAbsolutePath());
385 catch (Exception e) {
390 protected <T> void addClassesListToJavaParameters(Collection<? extends T> elements, Function<T, String> nameFunction, String packageName,
391 boolean createTempFile,
394 if (createTempFile) {
395 myTempFile = FileUtil.createTempFile("idea_junit", ".tmp");
396 myTempFile.deleteOnExit();
397 myJavaParameters.getProgramParametersList().add("@" + myTempFile.getAbsolutePath());
400 final PrintWriter writer = new PrintWriter(myTempFile, "UTF-8");
402 writer.println(junit4 ? JUnitStarter.JUNIT4_PARAMETER : "-junit3");
403 writer.println(packageName);
404 final List<String> testNames = new ArrayList<String>();
405 for (final T element : elements) {
406 final String name = nameFunction.fun(element);
408 LOG.error("invalid element " + element);
413 Collections.sort(testNames); //sort tests in FQN order
414 for (String testName : testNames) {
415 writer.println(testName);
422 catch (IOException e) {
427 public void clear() {
428 myJavaParameters = null;