From 216011c59bb2644e31f8efb7c03ef460a9329cc8 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Tue, 10 Oct 2017 12:08:28 +0200 Subject: [PATCH] junit 5: run tests by unique id (IDEA-169198; IDEA-179139) --- .../actions/JavaRerunFailedTestsAction.java | 9 +- ...eralIdBasedToSMTRunnerEventsConvertor.java | 1 + .../testframework/sm/runner/SMTestProxy.java | 5 +- .../testframework/AbstractTestProxy.java | 1 + .../testframework/CompositePrintable.java | 3 +- .../execution/testframework/TestTreeView.java | 13 +- plugins/junit/src/META-INF/plugin.xml | 1 + .../execution/junit/JUnitConfiguration.java | 31 ++++- .../intellij/execution/junit/TestMethods.java | 7 +- .../intellij/execution/junit/TestObject.java | 3 + .../execution/junit/TestUniqueId.java | 112 ++++++++++++++++++ .../junit/UniqueIdConfigurationProducer.java | 59 +++++++++ .../configuration/JUnitConfigurable.form | 22 +++- .../configuration/JUnitConfigurable.java | 40 ++++++- .../JUnitConfigurationModel.java | 6 +- .../intellij/junit5/JUnit5TestRunnerUtil.java | 10 +- 16 files changed, 301 insertions(+), 22 deletions(-) create mode 100644 plugins/junit/src/com/intellij/execution/junit/TestUniqueId.java create mode 100644 plugins/junit/src/com/intellij/execution/junit/UniqueIdConfigurationProducer.java diff --git a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java index 6896dcdbea1f..779a10d21d45 100644 --- a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java +++ b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java @@ -15,8 +15,8 @@ */ package com.intellij.execution.actions; +import com.intellij.execution.testframework.AbstractTestProxy; import com.intellij.execution.testframework.Filter; -import com.intellij.execution.testframework.JavaAwareFilter; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction; import com.intellij.openapi.project.Project; @@ -37,6 +37,11 @@ public class JavaRerunFailedTestsAction extends AbstractRerunFailedTestsAction { @NotNull @Override protected Filter getFilter(@NotNull Project project, @NotNull GlobalSearchScope searchScope) { - return super.getFilter(project, searchScope).and(JavaAwareFilter.METHOD(project, searchScope)); + return super.getFilter(project, searchScope).and(new Filter() { + @Override + public boolean shouldAccept(AbstractTestProxy test) { + return test.isLeaf(); + } + }); } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index 6d4ca628f7f2..53f814ac1bee 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -135,6 +135,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP String nodeName = startedNodeEvent.getName(); SMTestProxy childProxy = new SMTestProxy(nodeName, suite, startedNodeEvent.getLocationUrl(), startedNodeEvent.getMetainfo(), true); + childProxy.putUserData(SMTestProxy.NODE_ID, startedNodeEvent.getId()); childProxy.setTreeBuildBeforeStart(); TestProxyPrinterProvider printerProvider = myTestProxyPrinterProvider; String nodeType = startedNodeEvent.getNodeType(); diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index b951b574ae15..d2af3784ef2a 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -16,9 +16,7 @@ package com.intellij.execution.testframework.sm.runner; import com.intellij.execution.Location; -import com.intellij.execution.process.BaseOSProcessHandler; import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.process.ProcessOutputTypes; import com.intellij.execution.testframework.*; import com.intellij.execution.testframework.sm.SMStacktraceParser; import com.intellij.execution.testframework.sm.SMStacktraceParserEx; @@ -26,7 +24,6 @@ import com.intellij.execution.testframework.sm.runner.events.TestFailedEvent; import com.intellij.execution.testframework.sm.runner.states.*; import com.intellij.execution.testframework.sm.runner.ui.TestsPresentationUtil; import com.intellij.execution.testframework.stacktrace.DiffHyperlink; -import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.ide.util.EditSourceUtil; import com.intellij.openapi.application.ApplicationManager; @@ -55,6 +52,8 @@ import java.util.List; * @author Roman Chernyatchik */ public class SMTestProxy extends AbstractTestProxy { + public static final Key NODE_ID = Key.create("test.proxy.id"); + private static final Logger LOG = Logger.getInstance(SMTestProxy.class.getName()); private final String myName; diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java index a839b5add0fa..f6a865bd370d 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java @@ -34,6 +34,7 @@ import java.util.List; */ public abstract class AbstractTestProxy extends CompositePrintable { public static final DataKey DATA_KEY = DataKey.create("testProxy"); + public static final DataKey DATA_KEYS = DataKey.create("testProxies"); protected Printer myPrinter = null; diff --git a/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java b/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java index f80842aef2ef..2c9b969f7362 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/CompositePrintable.java @@ -22,6 +22,7 @@ import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.ContainerUtil; @@ -35,7 +36,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; -public class CompositePrintable implements Printable, Disposable { +public class CompositePrintable extends UserDataHolderBase implements Printable, Disposable { public static final String NEW_LINE = "\n"; protected final List myNestedPrintables = new ArrayList<>(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java index 241a443ed803..2bf72cae5a35 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java @@ -43,8 +43,7 @@ import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.datatransfer.StringSelection; -import java.util.ArrayList; -import java.util.Collection; +import java.util.*; import java.util.List; public abstract class TestTreeView extends Tree implements DataProvider, CopyProvider { @@ -132,6 +131,16 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro } } + if (AbstractTestProxy.DATA_KEYS.is(dataId)) { + TreePath[] paths = getSelectionPaths(); + if (paths != null) { + return Arrays.stream(paths) + .map(path -> getSelectedTest(path)) + .filter(Objects::nonNull) + .toArray(AbstractTestProxy[]::new); + } + } + if (MODEL_DATA_KEY.is(dataId)) { return myModel; } diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index 65e4abf6541d..cf41f0c7d03a 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -35,6 +35,7 @@ + diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index 29e1d7052581..e235fc62cd73 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -46,6 +46,7 @@ import com.intellij.psi.util.ClassUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.rt.execution.junit.RepeatCount; +import com.intellij.util.ArrayUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -60,6 +61,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { @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 public static final String TEST_UNIQUE_ID = "uniqueId"; @NonNls public static final String BY_SOURCE_POSITION = "source location"; @NonNls public static final String BY_SOURCE_CHANGES = "changes"; @@ -413,6 +415,13 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { final String categoryName = categoryNameElement.getAttributeValue("value"); getPersistentData().setCategoryName(categoryName); } + + Element idsElement = element.getChild("uniqueIds"); + if (idsElement != null) { + List ids = new ArrayList<>(); + idsElement.getChildren("uniqueId").forEach(uniqueIdElement -> ids.add(uniqueIdElement.getAttributeValue("value"))); + getPersistentData().setUniqueIds(ArrayUtil.toStringArray(ids)); + } } @Override @@ -444,6 +453,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { patternElement.setAttribute(TEST_CLASS_ATT_NAME, o); patternsElement.addContent(patternElement); } + element.addContent(patternsElement); final String forkMode = getForkMode(); if (!forkMode.equals("none")) { final Element forkModeElement = new Element("fork_mode"); @@ -457,7 +467,12 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { if (!RepeatCount.ONCE.equals(repeatMode)) { element.setAttribute("repeat_mode", repeatMode); } - element.addContent(patternsElement); + String[] ids = persistentData.getUniqueIds(); + if (ids != null) { + Element uniqueIds = new Element("uniqueIds"); + Arrays.stream(ids).forEach(id -> uniqueIds.addContent(new Element("uniqueId").setAttribute("value", id))); + element.addContent(uniqueIds); + } } public String getForkMode() { @@ -529,6 +544,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { public String PACKAGE_NAME; public String MAIN_CLASS_NAME; public String METHOD_NAME; + private String[] UNIQUE_ID; public String TEST_OBJECT = TEST_CLASS; public String VM_PARAMETERS; public String PARAMETERS; @@ -560,6 +576,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { Comparing.equal(FORK_MODE, second.FORK_MODE) && Comparing.equal(DIR_NAME, second.DIR_NAME) && Comparing.equal(CATEGORY_NAME, second.CATEGORY_NAME) && + Comparing.equal(UNIQUE_ID, second.UNIQUE_ID) && Comparing.equal(REPEAT_MODE, second.REPEAT_MODE) && REPEAT_COUNT == second.REPEAT_COUNT; } @@ -576,6 +593,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { Comparing.hashcode(FORK_MODE) ^ Comparing.hashcode(DIR_NAME) ^ Comparing.hashcode(CATEGORY_NAME) ^ + Comparing.hashcode(UNIQUE_ID) ^ Comparing.hashcode(REPEAT_MODE) ^ Comparing.hashcode(REPEAT_COUNT); } @@ -626,6 +644,14 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { WORKING_DIRECTORY = ExternalizablePath.urlValue(value); } + public void setUniqueIds(String... uniqueId) { + UNIQUE_ID = uniqueId; + } + + public String[] getUniqueIds() { + return UNIQUE_ID; + } + public Module setTestMethod(final Location methodLocation) { final PsiMethod method = methodLocation.getPsiElement(); METHOD_NAME = getMethodPresentation(method); @@ -705,6 +731,9 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { if (TEST_CATEGORY.equals(TEST_OBJECT)) { return "@Category(" + (StringUtil.isEmpty(CATEGORY_NAME) ? "Invalid" : CATEGORY_NAME) + ")"; } + if (TEST_UNIQUE_ID.equals(TEST_OBJECT)) { + return UNIQUE_ID != null ? StringUtil.join(UNIQUE_ID, " ") : "Temp suite"; + } final String className = JavaExecutionUtil.getPresentableClassName(getMainClassName()); if (TEST_METHOD.equals(TEST_OBJECT)) { return className + '.' + getMethodName(); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java index 0f1bb8d5d86e..bd8339c4c3fa 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java @@ -84,7 +84,12 @@ public class TestMethods extends TestMethod { final Location location = testInfo.getLocation(project, searchScope); final PsiElement element = location != null ? location.getPsiElement() : null; if (element instanceof PsiMethod) { - final PsiClass containingClass = location instanceof MethodLocation ? ((MethodLocation)location).getContainingClass() + String nodeId = TestUniqueId.getEffectiveNodeId(testInfo, project, searchScope); + if (nodeId != null) { + return TestUniqueId.getUniqueIdPresentation().fun(nodeId); + } + + final PsiClass containingClass = location instanceof MethodLocation ? ((MethodLocation)location).getContainingClass() : location instanceof PsiMemberParameterizedLocation ? ((PsiMemberParameterizedLocation)location).getContainingClass() : ((PsiMethod)element).getContainingClass(); if (containingClass != null) { diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index fb1c9e9db95f..d74219df118d 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -105,6 +105,9 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState getUniqueIdPresentation() { + return s -> "\u001B" + s; + } + + /** + * Return nodeId for the cases where containing method or class do not represent tests (IDEA fails to detect them as tests), + * or if parent node provides the same location, the case of parameterized/dynamic tests + */ + public static String getEffectiveNodeId(AbstractTestProxy testInfo, Project project, GlobalSearchScope searchScope) { + String nodeId = testInfo.getUserData(SMTestProxy.NODE_ID); + if (nodeId != null) { + Location location = testInfo.getLocation(project, searchScope); + if (location == null) return nodeId; + PsiElement psiElement = location.getPsiElement(); + PsiMethod method = PsiTreeUtil.getParentOfType(psiElement, PsiMethod.class); + if (method != null) { + PsiClass containingClass = method.getContainingClass(); + TestFramework testFramework = containingClass != null ? TestFrameworks.detectFramework(containingClass) : null; + if (testFramework == null || !testFramework.isTestMethod(psiElement)) { + return nodeId; + } + } + else { + PsiClass containingClass = PsiTreeUtil.getParentOfType(psiElement, PsiClass.class); + if (containingClass != null && TestFrameworks.detectFramework(containingClass) == null) { + return nodeId; + } + } + + AbstractTestProxy parent = testInfo.getParent(); + if (parent != null) { + Location parentLocation = parent.getLocation(project, searchScope); + if (parentLocation != null && parentLocation.getPsiElement() == psiElement) { + return nodeId; + } + } + } + return null; + } + + @NotNull + @Override + protected String getForkMode() { + return super.getForkMode(); + } + + @Override + public String suggestActionName() { + String[] ids = getConfiguration().getPersistentData().getUniqueIds(); + return JavaExecutionUtil.getShortClassName(ids.length > 0 ? ids[0] : ""); + } + + @Override + public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) { + return null; + } + + @Override + public boolean isConfiguredByElement(final JUnitConfiguration configuration, + PsiClass testClass, + PsiMethod testMethod, + PsiPackage testPackage, + PsiDirectory testDir) { + + return false; + } + + @Override + public void checkConfiguration() throws RuntimeConfigurationException { + super.checkConfiguration(); + String[] ids = getConfiguration().getPersistentData().getUniqueIds(); + if (ids == null || ids.length == 0) { + throw new RuntimeConfigurationException("No unique id specified"); + } + } +} diff --git a/plugins/junit/src/com/intellij/execution/junit/UniqueIdConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/UniqueIdConfigurationProducer.java new file mode 100644 index 000000000000..ea142c04291a --- /dev/null +++ b/plugins/junit/src/com/intellij/execution/junit/UniqueIdConfigurationProducer.java @@ -0,0 +1,59 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.execution.junit; + +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.ConfigurationFromContext; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.testframework.AbstractTestProxy; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Objects; + + +public class UniqueIdConfigurationProducer extends JUnitConfigurationProducer { + + protected UniqueIdConfigurationProducer() { + super(JUnitConfigurationType.getInstance()); + } + + @Override + protected boolean setupConfigurationFromContext(JUnitConfiguration configuration, + ConfigurationContext context, + Ref sourceElement) { + final Project project = configuration.getProject(); + DataContext dataContext = context.getDataContext(); + AbstractTestProxy[] testProxies = dataContext.getData(AbstractTestProxy.DATA_KEYS); + if (testProxies == null) return false; + RunConfiguration runConfiguration = dataContext.getData(RunConfiguration.DATA_KEY); + if (!(runConfiguration instanceof JUnitConfiguration)) return false; + Module module = ((JUnitConfiguration)runConfiguration).getConfigurationModule().getModule(); + configuration.setModule(module); + GlobalSearchScope searchScope = + module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(project); + String[] nodeIds = + Arrays.stream(testProxies).map(testProxy -> TestUniqueId.getEffectiveNodeId(testProxy, project, searchScope)) + .filter(Objects::nonNull) + .toArray(String[]::new); + if (nodeIds == null) return false; + final JUnitConfiguration.Data data = configuration.getPersistentData(); + data.setUniqueIds(nodeIds); + data.TEST_OBJECT = JUnitConfiguration.TEST_UNIQUE_ID; + configuration.setGeneratedName(); + return true; + } + + + //prefer to method + @Override + public boolean shouldReplace(@NotNull ConfigurationFromContext self, @NotNull ConfigurationFromContext other) { + return self.isProducedBy(UniqueIdConfigurationProducer.class) && (other.isProducedBy(TestInClassConfigurationProducer.class) || other.isProducedBy(PatternConfigurationProducer.class)); + } +} diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.form b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.form index c562c44c12a7..5530c48e606d 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.form +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.form @@ -3,7 +3,7 @@ - + @@ -158,7 +158,7 @@ - + @@ -168,7 +168,7 @@ - + @@ -226,10 +226,20 @@ - + + + + + + + + + + + @@ -238,7 +248,7 @@ - + @@ -249,7 +259,7 @@ - + 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 cc125632cea0..2e90fba0ae88 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java @@ -45,6 +45,7 @@ import com.intellij.openapi.ui.ex.MessagesEx; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vfs.VirtualFile; @@ -113,6 +114,7 @@ public class JUnitConfigurable extends SettingsEdi private JComboBox myRepeatCb; private JTextField myRepeatCountField; private LabeledComponent> myChangeListLabeledComponent; + private LabeledComponent myUniqueIdField; private Project myProject; private JComponent anchor; @@ -158,7 +160,8 @@ public class JUnitConfigurable extends SettingsEdi return null; } }, - new CategoryBrowser(project) + new CategoryBrowser(project), + null }; // Garbage support final DefaultComboBoxModel aModel = new DefaultComboBoxModel(); @@ -168,6 +171,7 @@ public class JUnitConfigurable extends SettingsEdi aModel.addElement(JUnitConfigurationModel.CLASS); aModel.addElement(JUnitConfigurationModel.METHOD); aModel.addElement(JUnitConfigurationModel.CATEGORY); + aModel.addElement(JUnitConfigurationModel.UNIQUE_ID); if (Registry.is("testDiscovery.enabled")) { aModel.addElement(JUnitConfigurationModel.BY_SOURCE_POSITION); aModel.addElement(JUnitConfigurationModel.BY_SOURCE_CHANGES); @@ -195,6 +199,9 @@ public class JUnitConfigurable extends SettingsEdi case JUnitConfigurationModel.CATEGORY: setText("Category"); break; + case JUnitConfigurationModel.UNIQUE_ID: + setText("UniqueId"); + break; case JUnitConfigurationModel.BY_SOURCE_POSITION: setText("Through source location"); break; @@ -300,6 +307,7 @@ public class JUnitConfigurable extends SettingsEdi configuration.setRepeatCount(1); } myModel.apply(getModuleSelector().getModule(), configuration); + configuration.getPersistentData().setUniqueIds(myUniqueIdField.getComponent().getText().split(" ")); configuration.getPersistentData().setChangeList((String)myChangeListLabeledComponent.getComponent().getSelectedItem()); applyHelpersTo(configuration); final JUnitConfiguration.Data data = configuration.getPersistentData(); @@ -328,6 +336,8 @@ public class JUnitConfigurable extends SettingsEdi myModel.reset(configuration); myChangeListLabeledComponent.getComponent().setSelectedItem(configuration.getPersistentData().getChangeList()); + String[] ids = configuration.getPersistentData().getUniqueIds(); + myUniqueIdField.getComponent().setText(ids != null ? StringUtil.join(ids, " ") : null); myCommonJavaParameters.reset(configuration); getModuleSelector().reset(configuration); final TestSearchScope scope = configuration.getPersistentData().getScope(); @@ -358,6 +368,7 @@ public class JUnitConfigurable extends SettingsEdi myPattern.setVisible(false); myClass.setVisible(false); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myMethod.setVisible(false); myDir.setVisible(false); myChangeListLabeledComponent.setVisible(false); @@ -371,6 +382,7 @@ public class JUnitConfigurable extends SettingsEdi myPattern.setVisible(false); myClass.setVisible(false); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myChangeListLabeledComponent.setVisible(false); myMethod.setVisible(false); myForkCb.setEnabled(true); @@ -384,6 +396,7 @@ public class JUnitConfigurable extends SettingsEdi myDir.setVisible(false); myClass.setVisible(true); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myChangeListLabeledComponent.setVisible(false); myMethod.setVisible(false); myForkCb.setEnabled(true); @@ -397,6 +410,7 @@ public class JUnitConfigurable extends SettingsEdi myDir.setVisible(false); myClass.setVisible(true); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myMethod.setVisible(true); myChangeListLabeledComponent.setVisible(false); myForkCb.setEnabled(false); @@ -408,6 +422,7 @@ public class JUnitConfigurable extends SettingsEdi myPattern.setVisible(false); myClass.setVisible(false); myCategory.setVisible(true); + myUniqueIdField.setVisible(false); myMethod.setVisible(false); myChangeListLabeledComponent.setVisible(false); myForkCb.setEnabled(true); @@ -421,12 +436,27 @@ public class JUnitConfigurable extends SettingsEdi myPattern.setVisible(false); myClass.setVisible(false); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myMethod.setVisible(false); myChangeListLabeledComponent.setVisible(true); myForkCb.setEnabled(true); myForkCb.setModel(new DefaultComboBoxModel(FORK_MODE_ALL)); myForkCb.setSelectedItem(selectedItem); } + else if (selectedType == JUnitConfigurationModel.UNIQUE_ID) { + myPackagePanel.setVisible(false); + myScopesPanel.setVisible(false); + myDir.setVisible(false); + myPattern.setVisible(false); + myClass.setVisible(false); + myCategory.setVisible(false); + myUniqueIdField.setVisible(true); + myMethod.setVisible(false); + myChangeListLabeledComponent.setVisible(false); + myForkCb.setEnabled(true); + myForkCb.setModel(new DefaultComboBoxModel(FORK_MODE_ALL)); + myForkCb.setSelectedItem(selectedItem); + } else { myPackagePanel.setVisible(false); myScopesPanel.setVisible(true); @@ -434,6 +464,7 @@ public class JUnitConfigurable extends SettingsEdi myDir.setVisible(false); myClass.setVisible(false); myCategory.setVisible(false); + myUniqueIdField.setVisible(false); myMethod.setVisible(true); myChangeListLabeledComponent.setVisible(false); myForkCb.setEnabled(true); @@ -545,6 +576,7 @@ public class JUnitConfigurable extends SettingsEdi myPattern.setAnchor(anchor); myPackage.setAnchor(anchor); myCategory.setAnchor(anchor); + myUniqueIdField.setAnchor(anchor); myChangeListLabeledComponent.setAnchor(anchor); } @@ -557,7 +589,8 @@ public class JUnitConfigurable extends SettingsEdi myModule.setEnabled(false); } else */if (newType != JUnitConfigurationModel.ALL_IN_PACKAGE && newType != JUnitConfigurationModel.PATTERN && - newType != JUnitConfigurationModel.CATEGORY) { + newType != JUnitConfigurationModel.CATEGORY && + newType != JUnitConfigurationModel.UNIQUE_ID) { myModule.setEnabled(true); } else { @@ -569,7 +602,8 @@ public class JUnitConfigurable extends SettingsEdi final Integer selectedItem = (Integer)myTypeChooser.getSelectedItem(); final boolean allInPackageAllInProject = (selectedItem == JUnitConfigurationModel.ALL_IN_PACKAGE || selectedItem == JUnitConfigurationModel.PATTERN || - selectedItem == JUnitConfigurationModel.CATEGORY) && myWholeProjectScope.isSelected(); + selectedItem == JUnitConfigurationModel.CATEGORY || + selectedItem == JUnitConfigurationModel.UNIQUE_ID ) && myWholeProjectScope.isSelected(); myModule.setEnabled(!allInPackageAllInProject); if (allInPackageAllInProject) { myModule.getComponent().setSelectedItem(null); diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java index dc8964a41e2f..b07f6e302fce 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java @@ -43,8 +43,9 @@ public class JUnitConfigurationModel { public static final int PATTERN = 3; public static final int DIR = 4; public static final int CATEGORY = 5; - public static final int BY_SOURCE_POSITION = 6; - public static final int BY_SOURCE_CHANGES = 7; + public static final int UNIQUE_ID = 6; + public static final int BY_SOURCE_POSITION = 7; + public static final int BY_SOURCE_CHANGES = 8; private static final List ourTestObjects; @@ -55,6 +56,7 @@ public class JUnitConfigurationModel { JUnitConfiguration.TEST_PATTERN, JUnitConfiguration.TEST_DIRECTORY, JUnitConfiguration.TEST_CATEGORY, + JUnitConfiguration.TEST_UNIQUE_ID, JUnitConfiguration.BY_SOURCE_POSITION, JUnitConfiguration.BY_SOURCE_CHANGES); } diff --git a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java index 8f9ea839c1be..dbf0e87ee9c8 100644 --- a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java +++ b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java @@ -111,8 +111,16 @@ public class JUnit5TestRunnerUtil { return disableDisabledCondition; } + /** + * Unique id is prepended with prefix: @see com.intellij.execution.junit.TestUniqueId#getUniqueIdPresentation() + * Method contains ',' + */ protected static DiscoverySelector createSelector(String line) { - if (line.contains(",")) { + if (line.startsWith("\u001B")) { + String uniqueId = line.substring("\u001B".length()); + return DiscoverySelectors.selectUniqueId(uniqueId); + } + else if (line.contains(",")) { return DiscoverySelectors.selectMethod(line.replaceFirst(",", "#")); } else {