blob: 0b7ab14a151d8c7f92c47fd4dfa9ace37ddd12a7 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.junit;
import com.intellij.diagnostic.logging.LogConfigurationPanel;
import com.intellij.execution.*;
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.junit2.configuration.JUnitConfigurable;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider {
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
@NonNls public static final String TEST_CLASS = "class";
@NonNls public static final String TEST_PACKAGE = "package";
@NonNls public static final String TEST_DIRECTORY = "directory";
@NonNls public static final String TEST_CATEGORY = "category";
@NonNls public static final String TEST_METHOD = "method";
@NonNls private static final String PATTERN_EL_NAME = "pattern";
@NonNls public static final String TEST_PATTERN = PATTERN_EL_NAME;
@NonNls private static final String TEST_CLASS_ATT_NAME = "testClass";
@NonNls private static final String PATTERNS_EL_NAME = "patterns";
private final Data myData;
// See #26522
@NonNls public static final String JUNIT_START_CLASS = "com.intellij.rt.execution.junit.JUnitStarter";
public boolean ALTERNATIVE_JRE_PATH_ENABLED;
public String ALTERNATIVE_JRE_PATH;
public JUnitConfiguration(final String name, final Project project, ConfigurationFactory configurationFactory) {
this(name, project, new Data(), configurationFactory);
}
private JUnitConfiguration(final String name, final Project project, final Data data, ConfigurationFactory configurationFactory) {
super(name, new JavaRunConfigurationModule(project, false), configurationFactory);
myData = data;
}
@Override
public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
return TestObject.fromString(myData.TEST_OBJECT, this, env);
}
@Override
@NotNull
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
SettingsEditorGroup<JUnitConfiguration> group = new SettingsEditorGroup<JUnitConfiguration>();
group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new JUnitConfigurable(getProject()));
JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<JUnitConfiguration>());
return group;
}
public Data getPersistentData() {
return myData;
}
@Override
public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
final RefactoringElementListener listener = myData.getTestObject(this).getListener(element, this);
return RunConfigurationExtension.wrapRefactoringElementListener(element, this, listener);
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
myData.getTestObject(this).checkConfiguration();
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
}
@Override
public Collection<Module> getValidModules() {
if (TEST_PACKAGE.equals(myData.TEST_OBJECT) || TEST_PATTERN.equals(myData.TEST_OBJECT)) {
return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
}
try {
myData.getTestObject(this).checkConfiguration();
}
catch (RuntimeConfigurationError e) {
return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
}
catch (RuntimeConfigurationException e) {
//ignore
}
return JavaRunConfigurationModule.getModulesForClass(getProject(), myData.getMainClassName());
}
@Override
protected ModuleBasedConfiguration createInstance() {
return new JUnitConfiguration(getName(), getProject(), myData.clone(), JUnitConfigurationType.getInstance().getConfigurationFactories()[0]);// throw new RuntimeException("Should not call");
}
@Override
public String suggestedName() {
return myData.getGeneratedName(getConfigurationModule());
}
@Override
public String getActionName() {
return getTestObject().suggestActionName();
}
@Override
public void setVMParameters(String value) {
myData.setVMParameters(value);
}
@Override
public String getVMParameters() {
return myData.getVMParameters();
}
@Override
public void setProgramParameters(String value) {
myData.setProgramParameters(value);
}
@Override
public String getProgramParameters() {
return myData.getProgramParameters();
}
@Override
public void setWorkingDirectory(String value) {
myData.setWorkingDirectory(value);
}
@Override
public String getWorkingDirectory() {
return myData.getWorkingDirectory();
}
@Override
public void setEnvs(@NotNull Map<String, String> envs) {
myData.setEnvs(envs);
}
@Override
@NotNull
public Map<String, String> getEnvs() {
return myData.getEnvs();
}
@Override
public void setPassParentEnvs(boolean passParentEnvs) {
myData.PASS_PARENT_ENVS = passParentEnvs;
}
@Override
public boolean isPassParentEnvs() {
return myData.PASS_PARENT_ENVS;
}
@Override
public boolean isAlternativeJrePathEnabled() {
return ALTERNATIVE_JRE_PATH_ENABLED;
}
@Override
public void setAlternativeJrePathEnabled(boolean enabled) {
ALTERNATIVE_JRE_PATH_ENABLED = enabled;
}
@Override
public String getAlternativeJrePath() {
return ALTERNATIVE_JRE_PATH;
}
@Override
public void setAlternativeJrePath(String path) {
ALTERNATIVE_JRE_PATH = path;
}
@Override
public String getRunClass() {
final Data data = getPersistentData();
return data.TEST_OBJECT != TEST_CLASS && data.TEST_OBJECT != TEST_METHOD ? null : data.getMainClassName();
}
@Override
public String getPackage() {
final Data data = getPersistentData();
return !Comparing.strEqual(data.TEST_OBJECT, TEST_PACKAGE) ? null : data.getPackageName();
}
public void beClassConfiguration(final PsiClass testClass) {
setMainClass(testClass);
myData.TEST_OBJECT = TEST_CLASS;
setGeneratedName();
}
public void setMainClass(final PsiClass testClass) {
final boolean shouldUpdateName = isGeneratedName();
setModule(myData.setMainClass(testClass));
if (shouldUpdateName) setGeneratedName();
}
public void beMethodConfiguration(final Location<PsiMethod> methodLocation) {
setModule(myData.setTestMethod(methodLocation));
setGeneratedName();
}
@Override
@NotNull
public Module[] getModules() {
if (TEST_PACKAGE.equals(myData.TEST_OBJECT) &&
getPersistentData().getScope() == TestSearchScope.WHOLE_PROJECT) {
return Module.EMPTY_ARRAY;
}
return super.getModules();
}
final RefactoringListeners.Accessor<PsiPackage> myPackage = new RefactoringListeners.Accessor<PsiPackage>() {
@Override
public void setName(final String qualifiedName) {
final boolean generatedName = isGeneratedName();
myData.PACKAGE_NAME = qualifiedName;
if (generatedName) setGeneratedName();
}
@Override
public PsiPackage getPsiElement() {
final String qualifiedName = myData.getPackageName();
return qualifiedName != null ? JavaPsiFacade.getInstance(getProject()).findPackage(qualifiedName)
: null;
}
@Override
public void setPsiElement(final PsiPackage psiPackage) {
setName(psiPackage.getQualifiedName());
}
};
final RefactoringListeners.Accessor<PsiClass> myClass = new RefactoringListeners.Accessor<PsiClass>() {
@Override
public void setName(@NotNull final String qualifiedName) {
final boolean generatedName = isGeneratedName();
myData.MAIN_CLASS_NAME = qualifiedName;
if (generatedName) setGeneratedName();
}
@Override
public PsiClass getPsiElement() {
return getConfigurationModule().findClass(myData.getMainClassName());
}
@Override
public void setPsiElement(final PsiClass psiClass) {
final Module originalModule = getConfigurationModule().getModule();
setMainClass(psiClass);
restoreOriginalModule(originalModule);
}
};
public TestObject getTestObject() {
return myData.getTestObject(this);
}
@Override
public void readExternal(final Element element) throws InvalidDataException {
PathMacroManager.getInstance(getProject()).expandPaths(element);
super.readExternal(element);
JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
readModule(element);
DefaultJDOMExternalizer.readExternal(this, element);
DefaultJDOMExternalizer.readExternal(getPersistentData(), element);
EnvironmentVariablesComponent.readExternal(element, getPersistentData().getEnvs());
final Element patternsElement = element.getChild(PATTERNS_EL_NAME);
if (patternsElement != null) {
final Set<String> tests = new LinkedHashSet<String>();
for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) {
Element patternElement = (Element)o;
tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME));
}
myData.setPatterns(tests);
}
final Element forkModeElement = element.getChild("fork_mode");
if (forkModeElement != null) {
final String mode = forkModeElement.getAttributeValue("value");
if (mode != null) {
setForkMode(mode);
}
}
final Element dirNameElement = element.getChild("dir");
if (dirNameElement != null) {
final String dirName = dirNameElement.getAttributeValue("value");
getPersistentData().setDirName(FileUtil.toSystemDependentName(dirName));
}
final Element categoryNameElement = element.getChild("category");
if (categoryNameElement != null) {
final String categoryName = categoryNameElement.getAttributeValue("value");
getPersistentData().setCategoryName(categoryName);
}
}
@Override
public void writeExternal(final Element element) throws WriteExternalException {
super.writeExternal(element);
JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
writeModule(element);
DefaultJDOMExternalizer.writeExternal(this, element);
final Data persistentData = getPersistentData();
DefaultJDOMExternalizer.writeExternal(persistentData, element);
EnvironmentVariablesComponent.writeExternal(element, persistentData.getEnvs());
final String dirName = persistentData.getDirName();
if (!dirName.isEmpty()) {
final Element dirNameElement = new Element("dir");
dirNameElement.setAttribute("value", FileUtil.toSystemIndependentName(dirName));
element.addContent(dirNameElement);
}
final String categoryName = persistentData.getCategory();
if (!categoryName.isEmpty()) {
final Element categoryNameElement = new Element("category");
categoryNameElement.setAttribute("value", categoryName);
element.addContent(categoryNameElement);
}
final Element patternsElement = new Element(PATTERNS_EL_NAME);
for (String o : persistentData.getPatterns()) {
final Element patternElement = new Element(PATTERN_EL_NAME);
patternElement.setAttribute(TEST_CLASS_ATT_NAME, o);
patternsElement.addContent(patternElement);
}
final String forkMode = getForkMode();
if (!forkMode.equals("none")) {
final Element forkModeElement = new Element("fork_mode");
forkModeElement.setAttribute("value", forkMode);
element.addContent(forkModeElement);
}
element.addContent(patternsElement);
PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
}
public void configureClasspath(final JavaParameters javaParameters) throws CantRunException {
RunConfigurationModule module = getConfigurationModule();
final String jreHome = isAlternativeJrePathEnabled() ? getAlternativeJrePath() : null;
final int pathType = JavaParameters.JDK_AND_CLASSES_AND_TESTS;
if (myData.getScope() == TestSearchScope.WHOLE_PROJECT) {
JavaParametersUtil.configureProject(module.getProject(), javaParameters, pathType, jreHome);
}
else {
JavaParametersUtil.configureModule(module, javaParameters, pathType, jreHome);
}
}
public void setForkMode(@NotNull String forkMode) {
myData.FORK_MODE = forkMode;
}
public String getForkMode() {
return myData.FORK_MODE;
}
@Override
public boolean collectOutputFromProcessHandler() {
return false;
}
public void bePatternConfiguration(List<PsiClass> classes, PsiMethod method) {
myData.TEST_OBJECT = TEST_PATTERN;
final Set<String> patterns = new HashSet<String>();
final String methodSufiix;
if (method != null) {
myData.METHOD_NAME = method.getName();
methodSufiix = "," + myData.METHOD_NAME;
} else {
methodSufiix = "";
}
for (PsiClass pattern : classes) {
patterns.add(JavaExecutionUtil.getRuntimeQualifiedName(pattern) + methodSufiix);
}
myData.setPatterns(patterns);
final Module module = PatternConfigurationProducer.findModule(this, getConfigurationModule().getModule(), patterns);
if (module == null) {
myData.setScope(TestSearchScope.WHOLE_PROJECT);
setModule(null);
} else {
setModule(module);
}
setGeneratedName();
}
public static class Data implements Cloneable {
public String PACKAGE_NAME;
private String DIR_NAME;
private String CATEGORY_NAME;
public String MAIN_CLASS_NAME;
public String METHOD_NAME;
public String TEST_OBJECT = TEST_CLASS;
public String VM_PARAMETERS;
public String PARAMETERS;
public String WORKING_DIRECTORY;
private String FORK_MODE = "none";
private Set<String> myPattern = new LinkedHashSet<String>();
//iws/ipr compatibility
public String ENV_VARIABLES;
private Map<String, String> myEnvs = new LinkedHashMap<String, String>();
public boolean PASS_PARENT_ENVS = true;
public TestSearchScope.Wrapper TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
public boolean equals(final Object object) {
if (!(object instanceof Data)) return false;
final Data second = (Data)object;
return Comparing.equal(TEST_OBJECT, second.TEST_OBJECT) &&
Comparing.equal(getMainClassName(), second.getMainClassName()) &&
Comparing.equal(getPackageName(), second.getPackageName()) &&
Comparing.equal(getMethodName(), second.getMethodName()) &&
Comparing.equal(getWorkingDirectory(), second.getWorkingDirectory()) &&
Comparing.equal(VM_PARAMETERS, second.VM_PARAMETERS) &&
Comparing.equal(PARAMETERS, second.PARAMETERS) &&
Comparing.equal(myPattern, second.myPattern) &&
Comparing.equal(FORK_MODE, second.FORK_MODE) &&
Comparing.equal(DIR_NAME, second.DIR_NAME) &&
Comparing.equal(CATEGORY_NAME, second.CATEGORY_NAME);
}
public int hashCode() {
return Comparing.hashcode(TEST_OBJECT) ^
Comparing.hashcode(getMainClassName()) ^
Comparing.hashcode(getPackageName()) ^
Comparing.hashcode(getMethodName()) ^
Comparing.hashcode(getWorkingDirectory()) ^
Comparing.hashcode(VM_PARAMETERS) ^
Comparing.hashcode(PARAMETERS) ^
Comparing.hashcode(myPattern) ^
Comparing.hashcode(FORK_MODE) ^
Comparing.hashcode(DIR_NAME) ^
Comparing.hashcode(CATEGORY_NAME);
}
public TestSearchScope getScope() {
return TEST_SEARCH_SCOPE.getScope();
}
@Override
public Data clone() {
try {
Data data = (Data)super.clone();
data.TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
data.setScope(getScope());
data.myEnvs = new LinkedHashMap<String, String>(myEnvs);
return data;
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
public void setVMParameters(String value) {
VM_PARAMETERS = value;
}
public String getVMParameters() {
return VM_PARAMETERS;
}
public void setProgramParameters(String value) {
PARAMETERS = value;
}
public String getProgramParameters() {
return PARAMETERS;
}
public void setWorkingDirectory(String value) {
WORKING_DIRECTORY = ExternalizablePath.urlValue(value);
}
public String getWorkingDirectory() {
return ExternalizablePath.localPathValue(WORKING_DIRECTORY);
}
public Module setTestMethod(final Location<PsiMethod> methodLocation) {
final PsiMethod method = methodLocation.getPsiElement();
METHOD_NAME = method.getName();
TEST_OBJECT = TEST_METHOD;
return setMainClass(methodLocation instanceof MethodLocation ? ((MethodLocation)methodLocation).getContainingClass() : method.getContainingClass());
}
public String getGeneratedName(final JavaRunConfigurationModule configurationModule) {
if (TEST_PACKAGE.equals(TEST_OBJECT) || TEST_DIRECTORY.equals(TEST_OBJECT)) {
final String moduleName = TEST_SEARCH_SCOPE.getScope() == TestSearchScope.WHOLE_PROJECT ? "" : configurationModule.getModuleName();
final String packageName = getPackageName();
if (packageName.length() == 0) {
if (moduleName.length() > 0) {
return ExecutionBundle.message("default.junit.config.name.all.in.module", moduleName);
}
return DEFAULT_PACKAGE_NAME;
}
if (moduleName.length() > 0) {
return ExecutionBundle.message("default.junit.config.name.all.in.package.in.module", packageName, moduleName);
}
return packageName;
}
if (TEST_PATTERN.equals(TEST_OBJECT)) {
final int size = myPattern.size();
if (size == 0) return "Temp suite";
final String fqName = myPattern.iterator().next();
return (fqName.contains("*") ? fqName : StringUtil.getShortName(fqName)) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
final String className = JavaExecutionUtil.getPresentableClassName(getMainClassName());
if (TEST_METHOD.equals(TEST_OBJECT)) {
return className + '.' + getMethodName();
}
return className;
}
public String getMainClassName() {
return MAIN_CLASS_NAME != null ? MAIN_CLASS_NAME : "";
}
public String getPackageName() {
return PACKAGE_NAME != null ? PACKAGE_NAME : "";
}
public String getMethodName() {
return METHOD_NAME != null ? METHOD_NAME : "";
}
public String getDirName() {
return DIR_NAME != null ? DIR_NAME : "";
}
public Set<String> getPatterns() {
return myPattern;
}
public String getPatternPresentation() {
final List<String> enabledTests = new ArrayList<String>();
for (String pattern : myPattern) {
enabledTests.add(pattern);
}
return StringUtil.join(enabledTests, "||");
}
public void setPatterns(Set<String> pattern) {
myPattern = pattern;
}
public TestObject getTestObject(@NotNull JUnitConfiguration configuration) {
//TODO[dyoma]!
return TestObject.fromString(TEST_OBJECT, configuration, ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), configuration).build());
}
public Module setMainClass(final PsiClass testClass) {
MAIN_CLASS_NAME = JavaExecutionUtil.getRuntimeQualifiedName(testClass);
PsiPackage containingPackage = JUnitUtil.getContainingPackage(testClass);
PACKAGE_NAME = containingPackage != null ? containingPackage.getQualifiedName() : "";
return JavaExecutionUtil.findModule(testClass);
}
public void setScope(final TestSearchScope scope) {
TEST_SEARCH_SCOPE.setScope(scope);
}
public Map<String, String> getEnvs() {
return myEnvs;
}
public void setEnvs(final Map<String, String> envs) {
myEnvs = envs;
}
public void setDirName(String dirName) {
DIR_NAME = dirName;
}
public String getCategory() {
return CATEGORY_NAME != null ? CATEGORY_NAME : "";
}
public void setCategoryName(String categoryName) {
CATEGORY_NAME = categoryName;
}
}
}