2 * Copyright 2000-2015 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.diagnostic.logging.LogConfigurationPanel;
20 import com.intellij.execution.*;
21 import com.intellij.execution.actions.RunConfigurationProducer;
22 import com.intellij.execution.configuration.EnvironmentVariablesComponent;
23 import com.intellij.execution.configurations.*;
24 import com.intellij.execution.executors.DefaultRunExecutor;
25 import com.intellij.execution.junit2.configuration.JUnitConfigurable;
26 import com.intellij.execution.junit2.info.MethodLocation;
27 import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
28 import com.intellij.execution.runners.ExecutionEnvironment;
29 import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
30 import com.intellij.execution.testframework.TestSearchScope;
31 import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties;
32 import com.intellij.openapi.components.PathMacroManager;
33 import com.intellij.openapi.module.Module;
34 import com.intellij.openapi.module.ModuleManager;
35 import com.intellij.openapi.options.SettingsEditor;
36 import com.intellij.openapi.options.SettingsEditorGroup;
37 import com.intellij.openapi.project.Project;
38 import com.intellij.openapi.util.Comparing;
39 import com.intellij.openapi.util.DefaultJDOMExternalizer;
40 import com.intellij.openapi.util.InvalidDataException;
41 import com.intellij.openapi.util.WriteExternalException;
42 import com.intellij.openapi.util.io.FileUtil;
43 import com.intellij.openapi.util.text.StringUtil;
44 import com.intellij.psi.*;
45 import com.intellij.refactoring.listeners.RefactoringElementListener;
46 import com.intellij.rt.execution.junit.RepeatCount;
47 import org.jdom.Element;
48 import org.jetbrains.annotations.NonNls;
49 import org.jetbrains.annotations.NotNull;
53 public class JUnitConfiguration extends JavaTestConfigurationBase {
54 public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
56 @NonNls public static final String TEST_CLASS = "class";
57 @NonNls public static final String TEST_PACKAGE = "package";
58 @NonNls public static final String TEST_DIRECTORY = "directory";
59 @NonNls public static final String TEST_CATEGORY = "category";
60 @NonNls public static final String TEST_METHOD = "method";
63 @NonNls public static final String FORK_NONE = "none";
64 @NonNls public static final String FORK_METHOD = "method";
65 @NonNls public static final String FORK_KLASS = "class";
67 @NonNls public static final String JUNIT_START_CLASS = "com.intellij.rt.execution.junit.JUnitStarter";
68 @NonNls private static final String PATTERN_EL_NAME = "pattern";
69 @NonNls public static final String TEST_PATTERN = PATTERN_EL_NAME;
70 @NonNls private static final String TEST_CLASS_ATT_NAME = "testClass";
71 @NonNls private static final String PATTERNS_EL_NAME = "patterns";
72 private final Data myData;
73 final RefactoringListeners.Accessor<PsiPackage> myPackage = new RefactoringListeners.Accessor<PsiPackage>() {
75 public void setName(final String qualifiedName) {
76 final boolean generatedName = isGeneratedName();
77 myData.PACKAGE_NAME = qualifiedName;
78 if (generatedName) setGeneratedName();
82 public PsiPackage getPsiElement() {
83 final String qualifiedName = myData.getPackageName();
84 return qualifiedName != null ? JavaPsiFacade.getInstance(getProject()).findPackage(qualifiedName)
89 public void setPsiElement(final PsiPackage psiPackage) {
90 setName(psiPackage.getQualifiedName());
93 final RefactoringListeners.Accessor<PsiClass> myClass = new RefactoringListeners.Accessor<PsiClass>() {
95 public void setName(@NotNull final String qualifiedName) {
96 final boolean generatedName = isGeneratedName();
97 myData.MAIN_CLASS_NAME = qualifiedName;
98 if (generatedName) setGeneratedName();
102 public PsiClass getPsiElement() {
103 return getConfigurationModule().findClass(myData.getMainClassName());
107 public void setPsiElement(final PsiClass psiClass) {
108 final Module originalModule = getConfigurationModule().getModule();
109 setMainClass(psiClass);
110 restoreOriginalModule(originalModule);
114 final RefactoringListeners.Accessor<PsiClass> myCategory = new RefactoringListeners.Accessor<PsiClass>() {
116 public void setName(@NotNull final String qualifiedName) {
117 setCategory(qualifiedName);
121 public PsiClass getPsiElement() {
122 return getConfigurationModule().findClass(myData.getCategory());
126 public void setPsiElement(final PsiClass psiClass) {
127 setCategory(JavaExecutionUtil.getRuntimeQualifiedName(psiClass));
130 public boolean ALTERNATIVE_JRE_PATH_ENABLED;
131 public String ALTERNATIVE_JRE_PATH;
133 public JUnitConfiguration(final String name, final Project project, ConfigurationFactory configurationFactory) {
134 this(name, project, new Data(), configurationFactory);
137 protected JUnitConfiguration(final String name, final Project project, final Data data, ConfigurationFactory configurationFactory) {
138 super(name, new JavaRunConfigurationModule(project, false), configurationFactory);
143 public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
144 return TestObject.fromString(myData.TEST_OBJECT, this, env);
149 public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
150 SettingsEditorGroup<JUnitConfiguration> group = new SettingsEditorGroup<JUnitConfiguration>();
151 group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new JUnitConfigurable(getProject()));
152 JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
153 group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<JUnitConfiguration>());
157 public Data getPersistentData() {
162 public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
163 final RefactoringElementListener listener = myData.getTestObject(this).getListener(element, this);
164 return RunConfigurationExtension.wrapRefactoringElementListener(element, this, listener);
168 public void checkConfiguration() throws RuntimeConfigurationException {
169 myData.getTestObject(this).checkConfiguration();
170 JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
174 public Collection<Module> getValidModules() {
175 if (TEST_PACKAGE.equals(myData.TEST_OBJECT) || TEST_PATTERN.equals(myData.TEST_OBJECT)) {
176 return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
179 myData.getTestObject(this).checkConfiguration();
181 catch (RuntimeConfigurationError e) {
182 return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
184 catch (RuntimeConfigurationException e) {
188 return JavaRunConfigurationModule.getModulesForClass(getProject(), myData.getMainClassName());
192 protected ModuleBasedConfiguration createInstance() {
193 return new JUnitConfiguration(getName(), getProject(), myData.clone(), JUnitConfigurationType.getInstance().getConfigurationFactories()[0]);// throw new RuntimeException("Should not call");
197 public String suggestedName() {
198 return myData.getGeneratedName(getConfigurationModule());
202 public String getActionName() {
203 return getTestObject().suggestActionName();
207 public String getVMParameters() {
208 return myData.getVMParameters();
212 public void setVMParameters(String value) {
213 myData.setVMParameters(value);
217 public String getProgramParameters() {
218 return myData.getProgramParameters();
222 public void setProgramParameters(String value) {
223 myData.setProgramParameters(value);
227 public String getWorkingDirectory() {
228 return myData.getWorkingDirectory();
232 public void setWorkingDirectory(String value) {
233 myData.setWorkingDirectory(value);
238 public Map<String, String> getEnvs() {
239 return myData.getEnvs();
243 public void setEnvs(@NotNull Map<String, String> envs) {
244 myData.setEnvs(envs);
248 public boolean isPassParentEnvs() {
249 return myData.PASS_PARENT_ENVS;
253 public void setPassParentEnvs(boolean passParentEnvs) {
254 myData.PASS_PARENT_ENVS = passParentEnvs;
258 public boolean isAlternativeJrePathEnabled() {
259 return ALTERNATIVE_JRE_PATH_ENABLED;
263 public void setAlternativeJrePathEnabled(boolean enabled) {
264 ALTERNATIVE_JRE_PATH_ENABLED = enabled;
268 public String getAlternativeJrePath() {
269 return ALTERNATIVE_JRE_PATH;
273 public void setAlternativeJrePath(String path) {
274 ALTERNATIVE_JRE_PATH = path;
278 public String getRunClass() {
279 final Data data = getPersistentData();
280 return data.TEST_OBJECT != TEST_CLASS && data.TEST_OBJECT != TEST_METHOD ? null : data.getMainClassName();
284 public String getPackage() {
285 final Data data = getPersistentData();
286 return !Comparing.strEqual(data.TEST_OBJECT, TEST_PACKAGE) ? null : data.getPackageName();
289 public void beClassConfiguration(final PsiClass testClass) {
290 setMainClass(testClass);
291 myData.TEST_OBJECT = TEST_CLASS;
295 public void setMainClass(final PsiClass testClass) {
296 final boolean shouldUpdateName = isGeneratedName();
297 setModule(myData.setMainClass(testClass));
298 if (shouldUpdateName) setGeneratedName();
301 public void setCategory(String categoryName) {
302 final boolean shouldUpdateName = isGeneratedName();
303 myData.setCategoryName(categoryName);
304 if (shouldUpdateName) setGeneratedName();
307 public void beMethodConfiguration(final Location<PsiMethod> methodLocation) {
308 setModule(myData.setTestMethod(methodLocation));
314 public Module[] getModules() {
315 if (TEST_PACKAGE.equals(myData.TEST_OBJECT) &&
316 getPersistentData().getScope() == TestSearchScope.WHOLE_PROJECT) {
317 return Module.EMPTY_ARRAY;
319 return super.getModules();
322 public TestObject getTestObject() {
323 return myData.getTestObject(this);
327 public void readExternal(final Element element) throws InvalidDataException {
328 PathMacroManager.getInstance(getProject()).expandPaths(element);
329 super.readExternal(element);
330 JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
332 DefaultJDOMExternalizer.readExternal(this, element);
333 DefaultJDOMExternalizer.readExternal(getPersistentData(), element);
334 EnvironmentVariablesComponent.readExternal(element, getPersistentData().getEnvs());
335 final Element patternsElement = element.getChild(PATTERNS_EL_NAME);
336 if (patternsElement != null) {
337 final LinkedHashSet<String> tests = new LinkedHashSet<String>();
338 for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) {
339 Element patternElement = (Element)o;
340 tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME));
342 myData.setPatterns(tests);
344 final Element forkModeElement = element.getChild("fork_mode");
345 if (forkModeElement != null) {
346 final String mode = forkModeElement.getAttributeValue("value");
351 final String count = element.getAttributeValue("repeat_count");
354 setRepeatCount(Integer.parseInt(count));
356 catch (NumberFormatException e) {
360 final String repeatMode = element.getAttributeValue("repeat_mode");
361 if (repeatMode != null) {
362 setRepeatMode(repeatMode);
364 final Element dirNameElement = element.getChild("dir");
365 if (dirNameElement != null) {
366 final String dirName = dirNameElement.getAttributeValue("value");
367 getPersistentData().setDirName(FileUtil.toSystemDependentName(dirName));
370 final Element categoryNameElement = element.getChild("category");
371 if (categoryNameElement != null) {
372 final String categoryName = categoryNameElement.getAttributeValue("value");
373 getPersistentData().setCategoryName(categoryName);
378 public void writeExternal(final Element element) throws WriteExternalException {
379 super.writeExternal(element);
380 JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
381 writeModule(element);
382 DefaultJDOMExternalizer.writeExternal(this, element);
383 final Data persistentData = getPersistentData();
384 DefaultJDOMExternalizer.writeExternal(persistentData, element);
385 EnvironmentVariablesComponent.writeExternal(element, persistentData.getEnvs());
386 final String dirName = persistentData.getDirName();
387 if (!dirName.isEmpty()) {
388 final Element dirNameElement = new Element("dir");
389 dirNameElement.setAttribute("value", FileUtil.toSystemIndependentName(dirName));
390 element.addContent(dirNameElement);
393 final String categoryName = persistentData.getCategory();
394 if (!categoryName.isEmpty()) {
395 final Element categoryNameElement = new Element("category");
396 categoryNameElement.setAttribute("value", categoryName);
397 element.addContent(categoryNameElement);
400 final Element patternsElement = new Element(PATTERNS_EL_NAME);
401 for (String o : persistentData.getPatterns()) {
402 final Element patternElement = new Element(PATTERN_EL_NAME);
403 patternElement.setAttribute(TEST_CLASS_ATT_NAME, o);
404 patternsElement.addContent(patternElement);
406 final String forkMode = getForkMode();
407 if (!forkMode.equals("none")) {
408 final Element forkModeElement = new Element("fork_mode");
409 forkModeElement.setAttribute("value", forkMode);
410 element.addContent(forkModeElement);
412 if (getRepeatCount() != 1) {
413 element.setAttribute("repeat_count", String.valueOf(getRepeatCount()));
415 final String repeatMode = getRepeatMode();
416 if (!RepeatCount.ONCE.equals(repeatMode)) {
417 element.setAttribute("repeat_mode", repeatMode);
419 element.addContent(patternsElement);
422 public String getForkMode() {
423 return myData.FORK_MODE;
426 public void setForkMode(@NotNull String forkMode) {
427 myData.FORK_MODE = forkMode;
431 public boolean collectOutputFromProcessHandler() {
435 public void bePatternConfiguration(List<PsiClass> classes, PsiMethod method) {
436 myData.TEST_OBJECT = TEST_PATTERN;
437 final LinkedHashSet<String> patterns = new LinkedHashSet<String>();
438 final String methodSufiix;
439 if (method != null) {
440 myData.METHOD_NAME = method.getName();
441 methodSufiix = "," + myData.METHOD_NAME;
445 for (PsiClass pattern : classes) {
446 patterns.add(JavaExecutionUtil.getRuntimeQualifiedName(pattern) + methodSufiix);
448 myData.setPatterns(patterns);
449 final Module module = RunConfigurationProducer.getInstance(PatternConfigurationProducer.class).findModule(this, getConfigurationModule()
450 .getModule(), patterns);
451 if (module == null) {
452 myData.setScope(TestSearchScope.WHOLE_PROJECT);
460 public int getRepeatCount() {
461 return myData.REPEAT_COUNT;
464 public void setRepeatCount(int repeatCount) {
465 myData.REPEAT_COUNT = repeatCount;
468 public String getRepeatMode() {
469 return myData.REPEAT_MODE;
472 public void setRepeatMode(String repeatMode) {
473 myData.REPEAT_MODE = repeatMode;
477 public SMTRunnerConsoleProperties createTestConsoleProperties(Executor executor) {
478 return new JUnitConsoleProperties(this, executor);
483 public String getFrameworkPrefix() {
487 public static class Data implements Cloneable {
488 public String PACKAGE_NAME;
489 public String MAIN_CLASS_NAME;
490 public String METHOD_NAME;
491 public String TEST_OBJECT = TEST_CLASS;
492 public String VM_PARAMETERS;
493 public String PARAMETERS;
494 public String WORKING_DIRECTORY;
495 //iws/ipr compatibility
496 public String ENV_VARIABLES;
497 public boolean PASS_PARENT_ENVS = true;
498 public TestSearchScope.Wrapper TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
499 private String DIR_NAME;
500 private String CATEGORY_NAME;
501 private String FORK_MODE = "none";
502 private int REPEAT_COUNT = 1;
503 private String REPEAT_MODE = RepeatCount.ONCE;
504 private LinkedHashSet<String> myPattern = new LinkedHashSet<String>();
505 private Map<String, String> myEnvs = new LinkedHashMap<String, String>();
507 public boolean equals(final Object object) {
508 if (!(object instanceof Data)) return false;
509 final Data second = (Data)object;
510 return Comparing.equal(TEST_OBJECT, second.TEST_OBJECT) &&
511 Comparing.equal(getMainClassName(), second.getMainClassName()) &&
512 Comparing.equal(getPackageName(), second.getPackageName()) &&
513 Comparing.equal(getMethodName(), second.getMethodName()) &&
514 Comparing.equal(getWorkingDirectory(), second.getWorkingDirectory()) &&
515 Comparing.equal(VM_PARAMETERS, second.VM_PARAMETERS) &&
516 Comparing.equal(PARAMETERS, second.PARAMETERS) &&
517 Comparing.equal(myPattern, second.myPattern) &&
518 Comparing.equal(FORK_MODE, second.FORK_MODE) &&
519 Comparing.equal(DIR_NAME, second.DIR_NAME) &&
520 Comparing.equal(CATEGORY_NAME, second.CATEGORY_NAME) &&
521 Comparing.equal(REPEAT_MODE, second.REPEAT_MODE) &&
522 REPEAT_COUNT == second.REPEAT_COUNT;
525 public int hashCode() {
526 return Comparing.hashcode(TEST_OBJECT) ^
527 Comparing.hashcode(getMainClassName()) ^
528 Comparing.hashcode(getPackageName()) ^
529 Comparing.hashcode(getMethodName()) ^
530 Comparing.hashcode(getWorkingDirectory()) ^
531 Comparing.hashcode(VM_PARAMETERS) ^
532 Comparing.hashcode(PARAMETERS) ^
533 Comparing.hashcode(myPattern) ^
534 Comparing.hashcode(FORK_MODE) ^
535 Comparing.hashcode(DIR_NAME) ^
536 Comparing.hashcode(CATEGORY_NAME) ^
537 Comparing.hashcode(REPEAT_MODE) ^
538 Comparing.hashcode(REPEAT_COUNT);
541 public TestSearchScope getScope() {
542 return TEST_SEARCH_SCOPE.getScope();
545 public void setScope(final TestSearchScope scope) {
546 TEST_SEARCH_SCOPE.setScope(scope);
550 public Data clone() {
552 Data data = (Data)super.clone();
553 data.TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
554 data.setScope(getScope());
555 data.myEnvs = new LinkedHashMap<String, String>(myEnvs);
558 catch (CloneNotSupportedException e) {
559 throw new RuntimeException(e);
563 public String getVMParameters() {
564 return VM_PARAMETERS;
567 public void setVMParameters(String value) {
568 VM_PARAMETERS = value;
571 public String getProgramParameters() {
575 public void setProgramParameters(String value) {
579 public String getWorkingDirectory() {
580 return ExternalizablePath.localPathValue(WORKING_DIRECTORY);
583 public void setWorkingDirectory(String value) {
584 WORKING_DIRECTORY = ExternalizablePath.urlValue(value);
587 public Module setTestMethod(final Location<PsiMethod> methodLocation) {
588 final PsiMethod method = methodLocation.getPsiElement();
589 METHOD_NAME = method.getName();
590 TEST_OBJECT = TEST_METHOD;
591 return setMainClass(methodLocation instanceof MethodLocation ? ((MethodLocation)methodLocation).getContainingClass() : method.getContainingClass());
594 public String getGeneratedName(final JavaRunConfigurationModule configurationModule) {
595 if (TEST_PACKAGE.equals(TEST_OBJECT) || TEST_DIRECTORY.equals(TEST_OBJECT)) {
596 final String moduleName = TEST_SEARCH_SCOPE.getScope() == TestSearchScope.WHOLE_PROJECT ? "" : configurationModule.getModuleName();
597 final String packageName = TEST_PACKAGE.equals(TEST_OBJECT) ? getPackageName() : StringUtil.getShortName(getDirName(), '/');
598 if (packageName.length() == 0) {
599 if (moduleName.length() > 0) {
600 return ExecutionBundle.message("default.junit.config.name.all.in.module", moduleName);
602 return DEFAULT_PACKAGE_NAME;
604 if (moduleName.length() > 0) {
605 return ExecutionBundle.message("default.junit.config.name.all.in.package.in.module", packageName, moduleName);
609 if (TEST_PATTERN.equals(TEST_OBJECT)) {
610 final int size = myPattern.size();
611 if (size == 0) return "Temp suite";
612 final String fqName = myPattern.iterator().next();
613 return (fqName.contains("*") ? fqName : StringUtil.getShortName(fqName)) + (size > 1 ? " and " + (size - 1) + " more" : "");
615 final String className = JavaExecutionUtil.getPresentableClassName(getMainClassName());
616 if (TEST_METHOD.equals(TEST_OBJECT)) {
617 return className + '.' + getMethodName();
623 public String getMainClassName() {
624 return MAIN_CLASS_NAME != null ? MAIN_CLASS_NAME : "";
627 public String getPackageName() {
628 return PACKAGE_NAME != null ? PACKAGE_NAME : "";
631 public String getMethodName() {
632 return METHOD_NAME != null ? METHOD_NAME : "";
635 public String getDirName() {
636 return DIR_NAME != null ? DIR_NAME : "";
639 public void setDirName(String dirName) {
643 public Set<String> getPatterns() {
647 public void setPatterns(LinkedHashSet<String> pattern) {
651 public String getPatternPresentation() {
652 final List<String> enabledTests = new ArrayList<String>();
653 for (String pattern : myPattern) {
654 enabledTests.add(pattern);
656 return StringUtil.join(enabledTests, "||");
659 public TestObject getTestObject(@NotNull JUnitConfiguration configuration) {
661 return TestObject.fromString(TEST_OBJECT, configuration, ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), configuration).build());
664 public Module setMainClass(final PsiClass testClass) {
665 MAIN_CLASS_NAME = JavaExecutionUtil.getRuntimeQualifiedName(testClass);
666 PsiPackage containingPackage = JUnitUtil.getContainingPackage(testClass);
667 PACKAGE_NAME = containingPackage != null ? containingPackage.getQualifiedName() : "";
668 return JavaExecutionUtil.findModule(testClass);
671 public Map<String, String> getEnvs() {
675 public void setEnvs(final Map<String, String> envs) {
679 public String getCategory() {
680 return CATEGORY_NAME != null ? CATEGORY_NAME : "";
683 public void setCategoryName(String categoryName) {
684 CATEGORY_NAME = categoryName;