diff --git a/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java b/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java index b38472a37a5b..40cf1f791019 100644 --- a/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java +++ b/platform/lang-api/src/com/intellij/execution/junit/RuntimeConfigurationProducer.java @@ -128,6 +128,10 @@ public abstract class RuntimeConfigurationProducer implements Comparable, Clonea public ConfigurationType getConfigurationType() { return myConfigurationFactory.getType(); } + + public void perform(ConfigurationContext context, Runnable performRunnable){ + performRunnable.run(); + } public static T getInstance(final Class aClass) { final RuntimeConfigurationProducer[] configurationProducers = Extensions.getExtensions(RUNTIME_CONFIGURATION_PRODUCER); diff --git a/platform/lang-impl/src/com/intellij/execution/actions/BaseRunConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/actions/BaseRunConfigurationAction.java index 4081008b010d..798b31326271 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/BaseRunConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/BaseRunConfigurationAction.java @@ -168,7 +168,12 @@ public abstract class BaseRunConfigurationAction extends ActionGroup { private void perform(final RuntimeConfigurationProducer producer, final ConfigurationContext context) { final RunnerAndConfigurationSettings configuration = context.updateConfiguration(producer); if (configuration != null) { - perform(context); + producer.perform(context, new Runnable() { + @Override + public void run() { + perform(context); + } + }); } } diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index f83067678aa6..8fbc94bbf542 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -362,6 +362,16 @@ public class JUnitConfiguration extends ModuleBasedConfiguration classes, PsiMethod method) { + Set patterns = new HashSet(); + for (PsiClass pattern : classes) { + patterns.add(pattern.getQualifiedName()); + } + myData.setPatterns(patterns); + myData.METHOD_NAME = method.getName(); + myData.TEST_OBJECT = TEST_PATTERN; + } + public static class Data implements Cloneable { public String PACKAGE_NAME; private String DIR_NAME; diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java index a78e9ce33e3e..9330be77d79d 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java @@ -59,7 +59,7 @@ public abstract class JUnitConfigurationProducer extends JavaRuntimeConfiguratio location = JavaExecutionUtil.stepIntoSingleClass(location); final PsiElement element = location.getPsiElement(); final PsiClass testClass = JUnitUtil.getTestClass(element); - final PsiMethod testMethod = JUnitUtil.getTestMethod(element); + final PsiMethod testMethod = JUnitUtil.getTestMethod(element, false); final PsiPackage testPackage; if (element instanceof PsiPackage) { testPackage = (PsiPackage)element; diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java index c3e384b9418c..ab93fa1232b9 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java @@ -21,10 +21,7 @@ import com.intellij.execution.*; import com.intellij.execution.configurations.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiPackage; +import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; @@ -108,9 +105,13 @@ class TestMethod extends TestObject { PsiClass testClass, PsiMethod testMethod, PsiPackage testPackage) { - if (testClass == null) return false; if (testMethod == null) return false; + final PsiClass containingClass = testMethod.getContainingClass(); + if (testClass == null && (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.ABSTRACT))) return false; final JUnitConfiguration.Data data = configuration.getPersistentData(); + if (containingClass != null && containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return Comparing.equal(testMethod.getName(), data.getMethodName()); + } return Comparing.equal(JavaExecutionUtil.getRuntimeQualifiedName(testClass), data.getMainClassName()) && Comparing.equal(testMethod.getName(), data.getMethodName()); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java index dabf13b9c65a..30b2837ac007 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java @@ -18,14 +18,29 @@ package com.intellij.execution.junit; import com.intellij.execution.JavaRunConfigurationExtensionManager; import com.intellij.execution.Location; +import com.intellij.execution.PsiLocation; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.junit2.info.MethodLocation; +import com.intellij.ide.util.PsiClassListCellRenderer; import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.components.JBList; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; +import javax.swing.*; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; public class TestMethodConfigurationProducer extends JUnitConfigurationProducer { private Location myMethodLocation; @@ -52,9 +67,117 @@ public class TestMethodConfigurationProducer extends JUnitConfigurationProducer private static Location getTestMethod(final Location location) { for (Iterator> iterator = location.getAncestors(PsiMethod.class, false); iterator.hasNext();) { final Location methodLocation = iterator.next(); - if (JUnitUtil.isTestMethod(methodLocation)) return methodLocation; + if (JUnitUtil.isTestMethod(methodLocation, false)) return methodLocation; } return null; } + + @Override + public void perform(final ConfigurationContext context, final Runnable performRunnable) { + final PsiMethod psiMethod = myMethodLocation.getPsiElement(); + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass != null && containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + final List classes = new ArrayList(); + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + @Override + public void run() { + ClassInheritorsSearch.search(containingClass).forEach(new Processor() { + @Override + public boolean process(PsiClass aClass) { + if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + classes.add(aClass); + } + return true; + } + }); + } + }, "Search for " + containingClass.getQualifiedName() + " inheritors", true, containingClass.getProject())) { + return; + } + + if (classes.size() == 1) { + runForClass(classes.get(0), psiMethod, context, performRunnable); + return; + } + //suggest to run all inherited tests + classes.add(0, null); + final JBList list = new JBList(classes); + list.setCellRenderer(new PsiClassListCellRenderer() { + @Override + protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer, + JList list, + Object value, + int index, + boolean selected, + boolean hasFocus) { + if (value == null) { + renderer.append("All"); + return true; + } + return super.customizeNonPsiElementLeftRenderer(renderer, list, value, index, selected, hasFocus); + } + }); + JBPopupFactory.getInstance().createListPopupBuilder(list) + .setTitle("Choose executable classes to run " + psiMethod.getName()) + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setItemChoosenCallback(new Runnable() { + public void run() { + final Object[] values = list.getSelectedValues(); + if (values == null) return; + runMethod(values, psiMethod, context, performRunnable, classes); + } + }).createPopup().showInBestPositionFor(context.getDataContext()); + return; + } + super.perform(context, performRunnable); + } + + private static void runMethod(Object[] values, + PsiMethod psiMethod, + ConfigurationContext context, + Runnable performRunnable, + List classes) { + if (values.length == 1) { + final Object value = values[0]; + if (value instanceof PsiClass) { + runForClass((PsiClass)value, psiMethod, context, performRunnable); + } + else { + runForClasses(classes, psiMethod, context, performRunnable); + } + return; + } + if (ArrayUtil.contains(null, values)) { + runForClasses(classes, psiMethod, context, performRunnable); + } + else { + final List selectedClasses = new ArrayList(); + for (Object value : values) { + if (value instanceof PsiClass) { + selectedClasses.add((PsiClass)value); + } + } + runForClasses(selectedClasses, psiMethod, context, performRunnable); + } + } + + private static void runForClasses(List classes, PsiMethod method, ConfigurationContext context, Runnable performRunnable) { + classes.remove(null); + ((JUnitConfiguration)context.getConfiguration().getConfiguration()).bePatternConfiguration(classes, method); + performRunnable.run(); + } + + private static void runForClass(final PsiClass aClass, + final PsiMethod psiMethod, + final ConfigurationContext context, + final Runnable performRunnable) { + final Project project = psiMethod.getProject(); + ((JUnitConfiguration)context.getConfiguration().getConfiguration()).beMethodConfiguration( + new MethodLocation(project, psiMethod, + new PsiLocation(project, aClass))); + performRunnable.run(); + } } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java index 64e2317e5193..6263fcea4926 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java @@ -27,12 +27,15 @@ import com.intellij.execution.util.JavaParametersUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.util.Function; import com.intellij.util.FunctionUtil; import org.jetbrains.annotations.Nullable; @@ -78,7 +81,12 @@ public class TestsPattern extends TestObject { } else { JavaParametersUtil.configureProject(project, myJavaParameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS, jreHome); } - addClassesListToJavaParameters(classNames, FunctionUtil.id(), "", true, isJUnit4); + addClassesListToJavaParameters(classNames, StringUtil.isEmpty(data.METHOD_NAME) ? FunctionUtil.id() : new Function() { + @Override + public String fun(String className) { + return className + "," + data.METHOD_NAME; + } + }, "", true, isJUnit4); } @Override @@ -100,6 +108,9 @@ public class TestsPattern extends TestObject { PsiClass testClass, PsiMethod testMethod, PsiPackage testPackage) { + if (testMethod != null && Comparing.strEqual(testMethod.getName(), configuration.getPersistentData().METHOD_NAME)) { + return true; + } return false; } diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java index 6aee88ac6ffd..5f615b0d8e5b 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java @@ -307,7 +307,7 @@ public class JUnitConfigurable extends SettingsEditor implem myPattern.setVisible(true); myDir.setVisible(false); myClass.setVisible(false); - myMethod.setVisible(false); + myMethod.setVisible(true); myForkCb.setEnabled(true); myForkCb.setModel(new DefaultComboBoxModel(FORK_MODE_ALL)); myForkCb.setSelectedItem(selectedItem); diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java index 1788a1afde4f..95cf1181ab5d 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestRunnerUtil.java @@ -103,7 +103,7 @@ public class JUnit4TestRunnerUtil { } public String describe() { - return "Failed tests"; + return "Tests"; } }); }