junit/testng: restore abstract method name to run
[idea/community.git] / plugins / junit / src / com / intellij / execution / junit / JUnitConfiguration.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.execution.junit;
18
19 import com.intellij.diagnostic.logging.LogConfigurationPanel;
20 import com.intellij.execution.*;
21 import com.intellij.execution.configuration.EnvironmentVariablesComponent;
22 import com.intellij.execution.configurations.*;
23 import com.intellij.execution.junit2.configuration.JUnitConfigurable;
24 import com.intellij.execution.junit2.info.MethodLocation;
25 import com.intellij.execution.runners.ExecutionEnvironment;
26 import com.intellij.execution.testframework.TestSearchScope;
27 import com.intellij.execution.util.JavaParametersUtil;
28 import com.intellij.openapi.components.PathMacroManager;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.module.Module;
31 import com.intellij.openapi.module.ModuleManager;
32 import com.intellij.openapi.options.SettingsEditor;
33 import com.intellij.openapi.options.SettingsEditorGroup;
34 import com.intellij.openapi.project.Project;
35 import com.intellij.openapi.util.Comparing;
36 import com.intellij.openapi.util.DefaultJDOMExternalizer;
37 import com.intellij.openapi.util.InvalidDataException;
38 import com.intellij.openapi.util.WriteExternalException;
39 import com.intellij.openapi.util.io.FileUtil;
40 import com.intellij.openapi.util.text.StringUtil;
41 import com.intellij.psi.*;
42 import com.intellij.refactoring.listeners.RefactoringElementListener;
43 import org.jdom.Element;
44 import org.jetbrains.annotations.NonNls;
45 import org.jetbrains.annotations.NotNull;
46
47 import java.util.*;
48
49 public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
50   implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider {
51   private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.JUnitConfiguration");
52   public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
53
54   @NonNls public static final String TEST_CLASS = "class";
55   @NonNls public static final String TEST_PACKAGE = "package";
56   @NonNls public static final String TEST_DIRECTORY = "directory";
57   @NonNls public static final String TEST_METHOD = "method";
58   @NonNls private static final String PATTERN_EL_NAME = "pattern";
59   @NonNls public static final String TEST_PATTERN = PATTERN_EL_NAME;
60
61   @NonNls private static final String TEST_CLASS_ATT_NAME = "testClass";
62   @NonNls private static final String PATTERNS_EL_NAME = "patterns";
63
64   private final Data myData;
65   // See #26522
66   @NonNls public static final String JUNIT_START_CLASS = "com.intellij.rt.execution.junit.JUnitStarter";
67
68   public boolean ALTERNATIVE_JRE_PATH_ENABLED;
69   public String ALTERNATIVE_JRE_PATH;
70
71   public JUnitConfiguration(final String name, final Project project, ConfigurationFactory configurationFactory) {
72     this(name, project, new Data(), configurationFactory);
73   }
74
75   private JUnitConfiguration(final String name, final Project project, final Data data, ConfigurationFactory configurationFactory) {
76     super(name, new JavaRunConfigurationModule(project, false), configurationFactory);
77     myData = data;
78   }
79
80   public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
81     return TestObject.fromString(myData.TEST_OBJECT, getProject(), this, env.getRunnerSettings(), env.getConfigurationSettings());
82   }
83
84
85   public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
86     SettingsEditorGroup<JUnitConfiguration> group = new SettingsEditorGroup<JUnitConfiguration>();
87     group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new JUnitConfigurable(getProject()));
88     JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
89     group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<JUnitConfiguration>());
90     return group;
91   }
92
93   public Data getPersistentData() {
94     return myData;
95   }
96
97   public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
98     final RefactoringElementListener listener = myData.getTestObject(getProject(), this).getListener(element, this);
99     return RunConfigurationExtension.wrapRefactoringElementListener(element, this, listener);
100   }
101
102   public String getGeneratedName() {
103     return myData.getGeneratedName(getConfigurationModule());
104   }
105
106   public void checkConfiguration() throws RuntimeConfigurationException {
107     myData.getTestObject(getProject(), this).checkConfiguration();
108     JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
109   }
110
111   public Collection<Module> getValidModules() {
112     if (TEST_PACKAGE.equals(myData.TEST_OBJECT) || TEST_PATTERN.equals(myData.TEST_OBJECT)) {
113       return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
114     }
115     try {
116       myData.getTestObject(getProject(), this).checkConfiguration();
117     }
118     catch (RuntimeConfigurationError e) {
119       return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
120     }
121     catch (RuntimeConfigurationException e) {
122       //ignore
123     }
124
125     return JavaRunConfigurationModule.getModulesForClass(getProject(), myData.getMainClassName());
126   }
127
128   protected ModuleBasedConfiguration createInstance() {
129     return new JUnitConfiguration(getName(), getProject(), myData.clone(), JUnitConfigurationType.getInstance().getConfigurationFactories()[0]);// throw new RuntimeException("Should not call");
130   }
131
132   public boolean isGeneratedName() {
133     final String name = getName();
134     return myData.isGeneratedName(name, getConfigurationModule());
135   }
136
137   public String suggestedName() {
138     return getTestObject().suggestActionName();
139   }
140
141   public void setVMParameters(String value) {
142     myData.setVMParameters(value);
143   }
144
145   public String getVMParameters() {
146     return myData.getVMParameters();
147   }
148
149   public void setProgramParameters(String value) {
150     myData.setProgramParameters(value);
151   }
152
153   public String getProgramParameters() {
154     return myData.getProgramParameters();
155   }
156
157   public void setWorkingDirectory(String value) {
158     myData.setWorkingDirectory(value);
159   }
160
161   public String getWorkingDirectory() {
162     return myData.getWorkingDirectory();
163   }
164
165   public void setEnvs(@NotNull Map<String, String> envs) {
166     myData.setEnvs(envs);
167   }
168
169   @NotNull
170   public Map<String, String> getEnvs() {
171     return myData.getEnvs();
172   }
173
174   public void setPassParentEnvs(boolean passParentEnvs) {
175     myData.PASS_PARENT_ENVS = passParentEnvs;
176   }
177
178   public boolean isPassParentEnvs() {
179     return myData.PASS_PARENT_ENVS;
180   }
181
182   public boolean isAlternativeJrePathEnabled() {
183     return ALTERNATIVE_JRE_PATH_ENABLED;
184   }
185
186   public void setAlternativeJrePathEnabled(boolean enabled) {
187     this.ALTERNATIVE_JRE_PATH_ENABLED = enabled;
188   }
189
190   public String getAlternativeJrePath() {
191     return ALTERNATIVE_JRE_PATH;
192   }
193
194   public void setAlternativeJrePath(String path) {
195     this.ALTERNATIVE_JRE_PATH = path;
196   }
197
198   public String getRunClass() {
199     final Data data = getPersistentData();
200     return data.TEST_OBJECT != TEST_CLASS && data.TEST_OBJECT != TEST_METHOD ? null : data.getMainClassName();
201   }
202
203   public String getPackage() {
204     final Data data = getPersistentData();
205     return !Comparing.strEqual(data.TEST_OBJECT, TEST_PACKAGE) ? null : data.getPackageName();
206   }
207
208
209   public void beClassConfiguration(final PsiClass testClass) {
210     setMainClass(testClass);
211     myData.TEST_OBJECT = TEST_CLASS;
212     setGeneratedName();
213   }
214
215   public void setMainClass(final PsiClass testClass) {
216     final boolean shouldUpdateName = isGeneratedName();
217     setModule(myData.setMainClass(testClass));
218     if (shouldUpdateName) setGeneratedName();
219   }
220
221   public void setGeneratedName() {
222     setName(getGeneratedName());
223   }
224
225   public void beMethodConfiguration(final Location<PsiMethod> methodLocation) {
226     setModule(myData.setTestMethod(methodLocation));
227     setGeneratedName();
228   }
229
230   @NotNull
231   public Module[] getModules() {
232     if (TEST_PACKAGE.equals(myData.TEST_OBJECT) &&
233         getPersistentData().getScope() == TestSearchScope.WHOLE_PROJECT) {
234       return Module.EMPTY_ARRAY;
235     }
236     return super.getModules();
237   }
238
239   final RefactoringListeners.Accessor<PsiPackage> myPackage = new RefactoringListeners.Accessor<PsiPackage>() {
240     public void setName(final String qualifiedName) {
241       final boolean generatedName = isGeneratedName();
242       myData.PACKAGE_NAME = qualifiedName;
243       if (generatedName) setGeneratedName();
244     }
245
246     public PsiPackage getPsiElement() {
247       final String qualifiedName = myData.getPackageName();
248       return qualifiedName != null ? JavaPsiFacade.getInstance(getProject()).findPackage(qualifiedName)
249              : null;
250     }
251
252     public void setPsiElement(final PsiPackage psiPackage) {
253       setName(psiPackage.getQualifiedName());
254     }
255   };
256
257   final RefactoringListeners.Accessor<PsiClass> myClass = new RefactoringListeners.Accessor<PsiClass>() {
258     public void setName(@NotNull final String qualifiedName) {
259       final boolean generatedName = isGeneratedName();
260       myData.MAIN_CLASS_NAME = qualifiedName;
261       if (generatedName) setGeneratedName();
262     }
263
264     public PsiClass getPsiElement() {
265       return getConfigurationModule().findClass(myData.getMainClassName());
266     }
267
268     public void setPsiElement(final PsiClass psiClass) {
269       final Module originalModule = getConfigurationModule().getModule();
270       setMainClass(psiClass);
271       restoreOriginalModule(originalModule);
272     }
273   };
274
275   public TestObject getTestObject() {
276     return myData.getTestObject(getProject(), this);
277   }
278
279   public void readExternal(final Element element) throws InvalidDataException {
280     PathMacroManager.getInstance(getProject()).expandPaths(element);
281     super.readExternal(element);
282     JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
283     readModule(element);
284     DefaultJDOMExternalizer.readExternal(this, element);
285     DefaultJDOMExternalizer.readExternal(getPersistentData(), element);
286     EnvironmentVariablesComponent.readExternal(element, getPersistentData().getEnvs());
287     final Element patternsElement = element.getChild(PATTERNS_EL_NAME);
288     if (patternsElement != null) {
289       final Set<String> tests = new LinkedHashSet<String>();
290       for (Object o : patternsElement.getChildren(PATTERN_EL_NAME)) {
291         Element patternElement = (Element)o;
292         tests.add(patternElement.getAttributeValue(TEST_CLASS_ATT_NAME));
293       }
294       myData.setPatterns(tests);
295     }
296     final Element forkModeElement = element.getChild("fork_mode");
297     if (forkModeElement != null) {
298       final String mode = forkModeElement.getAttributeValue("value");
299       if (mode != null) {
300         setForkMode(mode);
301       }
302     }
303     final Element dirNameElement = element.getChild("dir");
304     if (dirNameElement != null) {
305       final String dirName = dirNameElement.getAttributeValue("value");
306       getPersistentData().setDirName(FileUtil.toSystemDependentName(dirName));
307     }
308   }
309
310   public void writeExternal(final Element element) throws WriteExternalException {
311     super.writeExternal(element);
312     JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
313     writeModule(element);
314     DefaultJDOMExternalizer.writeExternal(this, element);
315     final Data persistentData = getPersistentData();
316     DefaultJDOMExternalizer.writeExternal(persistentData, element);
317     EnvironmentVariablesComponent.writeExternal(element, persistentData.getEnvs());
318     final String dirName = persistentData.getDirName();
319     if (!dirName.isEmpty()) {
320       final Element dirNameElement = new Element("dir");
321       dirNameElement.setAttribute("value", FileUtil.toSystemIndependentName(dirName));
322       element.addContent(dirNameElement);
323     }
324     final Element patternsElement = new Element(PATTERNS_EL_NAME);
325     for (String o : persistentData.getPatterns()) {
326       final Element patternElement = new Element(PATTERN_EL_NAME);
327       patternElement.setAttribute(TEST_CLASS_ATT_NAME, o);
328       patternsElement.addContent(patternElement);
329     }
330     final String forkMode = getForkMode();
331     if (!forkMode.equals("none")) {
332       final Element forkModeElement = new Element("fork_mode");
333       forkModeElement.setAttribute("value", forkMode);
334       element.addContent(forkModeElement);
335     }
336     element.addContent(patternsElement);
337     PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
338   }
339
340   public void configureClasspath(final JavaParameters javaParameters) throws CantRunException {
341     RunConfigurationModule module = getConfigurationModule();
342     final String jreHome = isAlternativeJrePathEnabled() ? getAlternativeJrePath() : null;
343     final int pathType = JavaParameters.JDK_AND_CLASSES_AND_TESTS;
344     if (myData.getScope() == TestSearchScope.WHOLE_PROJECT) {
345       JavaParametersUtil.configureProject(module.getProject(), javaParameters, pathType, jreHome);
346     }
347     else {
348       JavaParametersUtil.configureModule(module, javaParameters, pathType, jreHome);
349     }
350   }
351
352   public void setForkMode(@NotNull String forkMode) {
353     myData.FORK_MODE = forkMode;
354   }
355
356   public String getForkMode() {
357     return myData.FORK_MODE;
358   }
359
360   @Override
361   public boolean collectOutputFromProcessHandler() {
362     return false;
363   }
364
365   public void bePatternConfiguration(List<PsiClass> classes, PsiMethod method) {
366     myData.TEST_OBJECT = TEST_PATTERN;
367     final Set<String> patterns = new HashSet<String>();
368     myData.METHOD_NAME = method.getName();
369     for (PsiClass pattern : classes) {
370       patterns.add(JavaExecutionUtil.getRuntimeQualifiedName(pattern) + "," + myData.METHOD_NAME);
371     }
372     myData.setPatterns(patterns);
373     setGeneratedName();
374   }
375
376   public static class Data implements Cloneable {
377     public String PACKAGE_NAME;
378     private String DIR_NAME;
379     public String MAIN_CLASS_NAME;
380     public String METHOD_NAME;
381     public String TEST_OBJECT = TEST_CLASS;
382     public String VM_PARAMETERS;
383     public String PARAMETERS;
384     public String WORKING_DIRECTORY;
385     private String FORK_MODE = "none";
386     private Set<String> myPattern = new LinkedHashSet<String>();
387
388     //iws/ipr compatibility
389     public String ENV_VARIABLES;
390     private Map<String, String> myEnvs = new LinkedHashMap<String, String>();
391     public boolean PASS_PARENT_ENVS = true;
392
393     public TestSearchScope.Wrapper TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
394
395     public boolean equals(final Object object) {
396       if (!(object instanceof Data)) return false;
397       final Data second = (Data)object;
398       return Comparing.equal(TEST_OBJECT, second.TEST_OBJECT) &&
399              Comparing.equal(getMainClassName(), second.getMainClassName()) &&
400              Comparing.equal(getPackageName(), second.getPackageName()) &&
401              Comparing.equal(getMethodName(), second.getMethodName()) &&
402              Comparing.equal(getWorkingDirectory(), second.getWorkingDirectory()) &&
403              Comparing.equal(VM_PARAMETERS, second.VM_PARAMETERS) &&
404              Comparing.equal(PARAMETERS, second.PARAMETERS) &&
405              Comparing.equal(myPattern, second.myPattern) &&
406              Comparing.equal(FORK_MODE, second.FORK_MODE) &&
407              Comparing.equal(DIR_NAME, second.DIR_NAME);
408     }
409
410     public int hashCode() {
411       return Comparing.hashcode(TEST_OBJECT) ^
412              Comparing.hashcode(getMainClassName()) ^
413              Comparing.hashcode(getPackageName()) ^
414              Comparing.hashcode(getMethodName()) ^
415              Comparing.hashcode(getWorkingDirectory()) ^
416              Comparing.hashcode(VM_PARAMETERS) ^
417              Comparing.hashcode(PARAMETERS) ^
418              Comparing.hashcode(myPattern) ^
419              Comparing.hashcode(FORK_MODE) ^
420              Comparing.hashcode(DIR_NAME);
421     }
422
423     public TestSearchScope getScope() {
424       return TEST_SEARCH_SCOPE.getScope();
425     }
426
427     public Data clone() {
428       try {
429         Data data = (Data)super.clone();
430         data.TEST_SEARCH_SCOPE = new TestSearchScope.Wrapper();
431         data.setScope(getScope());
432         data.myEnvs = new LinkedHashMap<String, String>(myEnvs);
433         return data;
434       }
435       catch (CloneNotSupportedException e) {
436         throw new RuntimeException(e);
437       }
438     }
439
440     public void setVMParameters(String value) {
441       VM_PARAMETERS = value;
442     }
443
444     public String getVMParameters() {
445       return VM_PARAMETERS;
446     }
447
448     public void setProgramParameters(String value) {
449       PARAMETERS = value;
450     }
451
452     public String getProgramParameters() {
453       return PARAMETERS;
454     }
455
456     public void setWorkingDirectory(String value) {
457       WORKING_DIRECTORY = ExternalizablePath.urlValue(value);
458     }
459
460     public String getWorkingDirectory() {
461       return ExternalizablePath.localPathValue(WORKING_DIRECTORY);
462     }
463
464     public Module setTestMethod(final Location<PsiMethod> methodLocation) {
465       final PsiMethod method = methodLocation.getPsiElement();
466       METHOD_NAME = method.getName();
467       TEST_OBJECT = TEST_METHOD;
468       return setMainClass(methodLocation instanceof MethodLocation ? ((MethodLocation)methodLocation).getContainingClass() : method.getContainingClass());
469     }
470
471     public boolean isGeneratedName(final String name, final JavaRunConfigurationModule configurationModule) {
472       if (TEST_OBJECT == null) return true;
473       if ((TEST_CLASS.equals(TEST_OBJECT) || TEST_METHOD.equals(TEST_OBJECT)) && getMainClassName().length() == 0) {
474         return JavaExecutionUtil.isNewName(name);
475       }
476       if (TEST_METHOD.equals(TEST_OBJECT) && getMethodName().length() == 0) {
477         return JavaExecutionUtil.isNewName(name);
478       }
479       return Comparing.equal(name, getGeneratedName(configurationModule));
480     }
481
482     public String getGeneratedName(final JavaRunConfigurationModule configurationModule) {
483       if (TEST_PACKAGE.equals(TEST_OBJECT) || TEST_DIRECTORY.equals(TEST_OBJECT)) {
484         final String moduleName = TEST_SEARCH_SCOPE.getScope() == TestSearchScope.WHOLE_PROJECT ? "" : configurationModule.getModuleName();
485         final String packageName = getPackageName();
486         if (packageName.length() == 0) {
487           if (moduleName.length() > 0) {
488             return ExecutionBundle.message("default.junit.config.name.all.in.module", moduleName);
489           }
490           return DEFAULT_PACKAGE_NAME;
491         }
492         if (moduleName.length() > 0) {
493           return ExecutionBundle.message("default.junit.config.name.all.in.package.in.module", packageName, moduleName);
494         }
495         return packageName;
496       }
497       if (TEST_PATTERN.equals(TEST_OBJECT)) {
498         final int size = myPattern.size();
499         if (size == 0) return "Temp suite";
500         return StringUtil.getShortName(myPattern.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
501       }
502       final String className = JavaExecutionUtil.getPresentableClassName(getMainClassName(), configurationModule);
503       if (TEST_METHOD.equals(TEST_OBJECT)) {
504         return className + '.' + getMethodName();
505       }
506
507       return className;
508     }
509
510     public String getMainClassName() {
511       return MAIN_CLASS_NAME != null ? MAIN_CLASS_NAME : "";
512     }
513
514     public String getPackageName() {
515       return PACKAGE_NAME != null ? PACKAGE_NAME : "";
516     }
517
518     public String getMethodName() {
519       return METHOD_NAME != null ? METHOD_NAME : "";
520     }
521
522     public String getDirName() {
523       return DIR_NAME != null ? DIR_NAME : "";
524     }
525
526     public Set<String> getPatterns() {
527       return myPattern;
528     }
529
530     public String getPatternPresentation() {
531       final List<String> enabledTests = new ArrayList<String>();
532       for (String pattern : myPattern) {
533         enabledTests.add(pattern);
534       }
535       return StringUtil.join(enabledTests, "||");
536     }
537
538     public void setPatterns(Set<String> pattern) {
539       myPattern = pattern;
540     }
541
542     public TestObject getTestObject(final Project project, final JUnitConfiguration configuration) {
543       //TODO[dyoma]!
544       return TestObject.fromString(TEST_OBJECT, project, configuration, null, null);
545     }
546
547     public Module setMainClass(final PsiClass testClass) {
548       MAIN_CLASS_NAME = JavaExecutionUtil.getRuntimeQualifiedName(testClass);
549       PsiPackage containingPackage = JUnitUtil.getContainingPackage(testClass);
550       PACKAGE_NAME = containingPackage != null ? containingPackage.getQualifiedName() : "";
551       return JavaExecutionUtil.findModule(testClass);
552     }
553
554     public void setScope(final TestSearchScope scope) {
555       TEST_SEARCH_SCOPE.setScope(scope);
556     }
557
558     public Map<String, String> getEnvs() {
559       return myEnvs;
560     }
561
562     public void setEnvs(final Map<String, String> envs) {
563       myEnvs = envs;
564     }
565
566     public void setDirName(String dirName) {
567       DIR_NAME = dirName;
568     }
569   }
570
571 }