From 87f6b96f8340a5d41e4b634f693d16cf50b3cf3d Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 20 Jul 2017 18:39:06 +0200 Subject: [PATCH] junit 5: move to id-based processing (IDEA-172141) --- .../execution/junit/JUnitConfiguration.java | 30 ++++++++++ .../intellij/execution/junit/TestClass.java | 18 ------ .../intellij/execution/junit/TestMethod.java | 30 ---------- .../intellij/execution/junit/TestMethods.java | 7 --- .../intellij/execution/junit/TestObject.java | 13 +++-- .../ui/properties/JUnitConsoleProperties.java | 3 + .../junit5/JUnit5TestExecutionListener.java | 56 ++++++++++++------- .../com/intellij/junit5/JUnit5EventsTest.java | 20 +++---- .../intellij/junit5/JUnit5NavigationTest.java | 7 +-- 9 files changed, 88 insertions(+), 96 deletions(-) diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index b798cee43c4f..e1aae2725b55 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -42,8 +42,10 @@ 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.psi.search.GlobalSearchScope; import com.intellij.psi.util.ClassUtil; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.rt.execution.junit.JUnitStarter; import com.intellij.rt.execution.junit.RepeatCount; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -520,6 +522,34 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { return "j"; } + public String getPreferredRunner(final GlobalSearchScope globalSearchScope) { + Data data = getPersistentData(); + Project project = getProject(); + boolean isMethodConfiguration = TEST_METHOD.equals(data.TEST_OBJECT); + boolean isClassConfiguration = TEST_CLASS.equals(data.TEST_OBJECT); + final PsiClass psiClass = isMethodConfiguration || isClassConfiguration + ? JavaExecutionUtil.findMainClass(project, data.getMainClassName(), globalSearchScope) : null; + if (psiClass != null) { + if (JUnitUtil.isJUnit5TestClass(psiClass, false)) { + return JUnitStarter.JUNIT5_PARAMETER; + } + + if (isClassConfiguration || JUnitUtil.isJUnit4TestClass(psiClass)) { + return JUnitStarter.JUNIT4_PARAMETER; + } + + final String methodName = data.getMethodName(); + final PsiMethod[] methods = psiClass.findMethodsByName(methodName, true); + for (PsiMethod method : methods) { + if (JUnitUtil.isTestAnnotated(method)) { + return JUnitStarter.JUNIT4_PARAMETER; + } + } + return JUnitStarter.JUNIT3_PARAMETER; + } + return JUnitUtil.isJUnit5(globalSearchScope, project) ? JUnitStarter.JUNIT5_PARAMETER : null; + } + public static class Data implements Cloneable { public String PACKAGE_NAME; public String MAIN_CLASS_NAME; diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClass.java b/plugins/junit/src/com/intellij/execution/junit/TestClass.java index 162690a34c44..bebb52345919 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClass.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClass.java @@ -24,14 +24,10 @@ import com.intellij.execution.configurations.JavaRunConfigurationModule; import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.execution.configurations.RuntimeConfigurationWarning; import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementListener; -import com.intellij.rt.execution.junit.JUnitStarter; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; class TestClass extends TestObject { public TestClass(JUnitConfiguration configuration, ExecutionEnvironment environment) { @@ -46,20 +42,6 @@ class TestClass extends TestObject { return javaParameters; } - @Nullable - @Override - protected String getPreferredRunner(GlobalSearchScope globalSearchScope) { - Project project = getConfiguration().getProject(); - final PsiClass psiClass = JavaExecutionUtil.findMainClass(project, getConfiguration().getPersistentData().getMainClassName(), globalSearchScope); - if (psiClass != null) { - if (JUnitUtil.isJUnit5TestClass(psiClass, false)) { - return JUnitStarter.JUNIT5_PARAMETER; - } - return JUnitStarter.JUNIT4_PARAMETER; - } - return null; - } - @NotNull @Override protected String getForkMode() { diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java index e6ced239d694..0eebfe995291 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java @@ -20,16 +20,12 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.execution.*; import com.intellij.execution.configurations.*; import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.UndoRefactoringElementListener; -import com.intellij.rt.execution.junit.JUnitStarter; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; class TestMethod extends TestObject { public TestMethod(JUnitConfiguration configuration, ExecutionEnvironment environment) { @@ -48,32 +44,6 @@ class TestMethod extends TestObject { return super.createJavaParameters(); } - @Nullable - @Override - protected String getPreferredRunner(GlobalSearchScope globalSearchScope) { - Project project = getConfiguration().getProject(); - JUnitConfiguration.Data data = getConfiguration().getPersistentData(); - final PsiClass psiClass = JavaExecutionUtil.findMainClass(project, data.getMainClassName(), globalSearchScope); - if (psiClass == null) return null; - - if (JUnitUtil.isJUnit5TestClass(psiClass, false)) { - return JUnitStarter.JUNIT5_PARAMETER; - } - - if (JUnitUtil.isJUnit4TestClass(psiClass)) { - return JUnitStarter.JUNIT4_PARAMETER; - } - - final String methodName = data.getMethodName(); - final PsiMethod[] methods = psiClass.findMethodsByName(methodName, true); - for (PsiMethod method : methods) { - if (JUnitUtil.isTestAnnotated(method)) { - return JUnitStarter.JUNIT4_PARAMETER; - } - } - return JUnitStarter.JUNIT3_PARAMETER; - } - @Override public String suggestActionName() { return ProgramRunnerUtil.shortenName(getConfiguration().getPersistentData().METHOD_NAME, 2) + "()"; diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java index 520908977ade..0f1bb8d5d86e 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java @@ -35,7 +35,6 @@ import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.rt.execution.junit.JUnitStarter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,12 +53,6 @@ public class TestMethods extends TestMethod { myFailedTests = failedTests; } - @Nullable - @Override - protected String getPreferredRunner(GlobalSearchScope globalSearchScope) { - return JUnitUtil.isJUnit5(globalSearchScope, getConfiguration().getProject()) ? JUnitStarter.JUNIT5_PARAMETER : null; - } - @Override protected JavaParameters createJavaParameters() throws ExecutionException { final JavaParameters javaParameters = super.createDefaultJavaParameters(); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 7ccd869f33e6..fdace57fba90 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -169,7 +169,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState myRoots = new HashSet<>(); + private Set myRoots = new HashSet<>(); private boolean mySuccessful; public JUnit5TestExecutionListener() { @@ -110,9 +111,9 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { testStarted(testIdentifier); myCurrentTestStart = System.currentTimeMillis(); } - else if (!myRoots.contains(testIdentifier)){ + else if (!myRoots.contains(testIdentifier.getUniqueId())){ myFinishCount = 0; - myPrintStream.println("##teamcity[testSuiteStarted" + idAndName(testIdentifier) + "]"); + myPrintStream.println("##teamcity[testSuiteStarted" + idAndName(testIdentifier) + getLocationHint(testIdentifier) + "]"); } } @@ -145,7 +146,7 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { testFinished(testIdentifier, duration); myFinishCount++; } - else if (!myRoots.contains(testIdentifier)){ + else if (!myRoots.contains(testIdentifier.getUniqueId())){ String messageName = null; if (status == TestExecutionResult.Status.FAILED) { messageName = MapSerializerUtil.TEST_FAILED; @@ -155,9 +156,11 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { } if (messageName != null) { if (status == TestExecutionResult.Status.FAILED) { - myPrintStream.println("\n##teamcity[testStarted name=\'" + JUnit4TestListener.CLASS_CONFIGURATION + "\' " + getLocationHint(testIdentifier) + "]"); - testFailure(JUnit4TestListener.CLASS_CONFIGURATION, JUnit4TestListener.CLASS_CONFIGURATION, messageName, throwableOptional, 0, reason, true); - myPrintStream.println("\n##teamcity[testFinished name=\'" + JUnit4TestListener.CLASS_CONFIGURATION + "\']"); + String nameAndId = + JUnit4TestListener.CLASS_CONFIGURATION + "\' nodeId=\'" + escapeName(JUnit4TestListener.CLASS_CONFIGURATION) + "\' parentNodeId=\'0\' "; + myPrintStream.println("\n##teamcity[testStarted name=\'" + nameAndId + getLocationHint(testIdentifier) + "]"); + testFailure(JUnit4TestListener.CLASS_CONFIGURATION, JUnit4TestListener.CLASS_CONFIGURATION, getParentId(testIdentifier), messageName, throwableOptional, 0, reason, true); + myPrintStream.println("\n##teamcity[testFinished name=\'" + nameAndId + "]"); } final Set descendants = myTestPlan != null ? myTestPlan.getDescendants(testIdentifier) : Collections.emptySet(); @@ -192,11 +195,12 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { long duration, String reason, boolean includeThrowable) { - testFailure(testIdentifier.getDisplayName(), testIdentifier.getUniqueId(), messageName, ex, duration, reason, includeThrowable); + testFailure(testIdentifier.getDisplayName(), testIdentifier.getUniqueId(), getParentId(testIdentifier), messageName, ex, duration, reason, includeThrowable); } private void testFailure(String methodName, String id, + String parentId, String messageName, Throwable ex, long duration, @@ -205,6 +209,8 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { final Map attrs = new LinkedHashMap<>(); attrs.put("name", methodName); attrs.put("id", id); + attrs.put("nodeId", id); + attrs.put("parentNodeId", parentId); if (duration > 0) { attrs.put("duration", Long.toString(duration)); } @@ -216,7 +222,7 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { ComparisonFailureData failureData = null; if (ex instanceof MultipleFailuresError && ((MultipleFailuresError)ex).hasFailures()) { for (Throwable assertionError : ((MultipleFailuresError)ex).getFailures()) { - testFailure(methodName, id, messageName, assertionError, duration, reason, false); + testFailure(methodName, id, parentId, messageName, assertionError, duration, reason, false); } } else if (ex instanceof AssertionFailedError && ((AssertionFailedError)ex).isActualDefined() && ((AssertionFailedError)ex).isExpectedDefined()) { @@ -256,8 +262,9 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { public void sendTree(TestPlan testPlan, String rootName) { myTestPlan = testPlan; myRootName = rootName; - myRoots = testPlan.getRoots(); - for (TestIdentifier root : myRoots) { + Set roots = testPlan.getRoots(); + myRoots = roots.stream().map(identifier -> identifier.getUniqueId()).collect(Collectors.toSet()); + for (TestIdentifier root : roots) { assert root.isContainer(); for (TestIdentifier testIdentifier : testPlan.getChildren(root)) { sendTreeUnderRoot(testPlan, testIdentifier, new HashSet<>()); @@ -287,28 +294,39 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { } } - private static String idAndName(TestIdentifier testIdentifier) { + private String idAndName(TestIdentifier testIdentifier) { return idAndName(testIdentifier, testIdentifier.getDisplayName()); } - private static String idAndName(TestIdentifier testIdentifier, String displayName) { - return " id=\'" + escapeName(testIdentifier.getUniqueId()) + "\' name=\'" + escapeName(displayName) + "\'"; + private String idAndName(TestIdentifier testIdentifier, String displayName) { + return " id=\'" + escapeName(testIdentifier.getUniqueId()) + + "\' name=\'" + escapeName(displayName) + + "\' nodeId=\'" + escapeName(testIdentifier.getUniqueId()) + + "\' parentNodeId=\'" + escapeName(getParentId(testIdentifier)) + "\'"; + } + + private String getParentId(TestIdentifier testIdentifier) { + String parentId = testIdentifier.getParentId().orElse("0"); + if (myRoots.contains(parentId)) { + parentId = "0"; + } + return parentId; } static String getLocationHint(TestIdentifier root) { return root.getSource() - .map(testSource -> getLocationHintValue(testSource, root.isTest())) + .map(testSource -> getLocationHintValue(testSource)) .filter(maybeLocationHintValue -> !NO_LOCATION_HINT_VALUE.equals(maybeLocationHintValue)) .map(locationHintValue -> "locationHint=\'" + locationHintValue + "\'") .orElse(NO_LOCATION_HINT); } - static String getLocationHintValue(TestSource testSource, boolean isTest) { + static String getLocationHintValue(TestSource testSource) { if (testSource instanceof CompositeTestSource) { CompositeTestSource compositeTestSource = ((CompositeTestSource)testSource); for (TestSource sourceFromComposite : compositeTestSource.getSources()) { - String locationHintValue = getLocationHintValue(sourceFromComposite, isTest); + String locationHintValue = getLocationHintValue(sourceFromComposite); if (!NO_LOCATION_HINT_VALUE.equals(locationHintValue)) { return locationHintValue; } @@ -327,12 +345,12 @@ public class JUnit5TestExecutionListener implements TestExecutionListener { if (testSource instanceof MethodSource) { MethodSource methodSource = (MethodSource)testSource; - return javaLocation(methodSource.getClassName(), methodSource.getMethodName(), isTest); + return javaLocation(methodSource.getClassName(), methodSource.getMethodName(), true); } if (testSource instanceof ClassSource) { String className = ((ClassSource)testSource).getClassName(); - return javaLocation(className, null, isTest); + return javaLocation(className, null, false); } return NO_LOCATION_HINT_VALUE; diff --git a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java index f932e5c95427..63de75cef5f0 100644 --- a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java +++ b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5EventsTest.java @@ -83,15 +83,15 @@ class JUnit5EventsTest { String lineSeparator = MapSerializerUtil.escapeStr(System.getProperty("line.separator"), MapSerializerUtil.STD_ESCAPER); Assertions.assertEquals("##teamcity[enteredTheMatrix]\n" + "\n" + - "##teamcity[testStarted id='|[engine:engine|]' name='test1()' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.test1']\n" + + "##teamcity[testStarted id='|[engine:engine|]' name='test1()' nodeId='|[engine:engine|]' parentNodeId='0' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.test1']\n" + "\n" + - "##teamcity[testFailed name='test1()' id='|[engine:engine|]' details='' message='' expected='expected1' actual='actual1']\n" + + "##teamcity[testFailed name='test1()' id='|[engine:engine|]' nodeId='|[engine:engine|]' parentNodeId='0' details='' message='' expected='expected1' actual='actual1']\n" + "\n" + - "##teamcity[testFailed name='test1()' id='|[engine:engine|]' details='' message='' expected='expected2' actual='actual2']\n" + + "##teamcity[testFailed name='test1()' id='|[engine:engine|]' nodeId='|[engine:engine|]' parentNodeId='0' details='' message='' expected='expected2' actual='actual2']\n" + "\n" + - "##teamcity[testFailed name='test1()' id='|[engine:engine|]' details='TRACE' message='2 errors (2 failures)" + lineSeparator + "\tmessage1" + lineSeparator + "\tmessage2']\n" + + "##teamcity[testFailed name='test1()' id='|[engine:engine|]' nodeId='|[engine:engine|]' parentNodeId='0' details='TRACE' message='2 errors (2 failures)|r|n\tmessage1|r|n\tmessage2']\n" + "\n" + - "##teamcity[testFinished id='|[engine:engine|]' name='test1()']\n", StringUtil.convertLineSeparators(myBuf.toString())); + "##teamcity[testFinished id='|[engine:engine|]' name='test1()' nodeId='|[engine:engine|]' parentNodeId='0']\n", StringUtil.convertLineSeparators(myBuf.toString())); } @Test @@ -107,14 +107,14 @@ class JUnit5EventsTest { Assertions.assertEquals("##teamcity[enteredTheMatrix]\n" + "##teamcity[treeEnded]\n" + - "##teamcity[testSuiteStarted id='|[engine:engine1|]' name='brokenStream()']\n" + + "##teamcity[testSuiteStarted id='|[engine:engine1|]' name='brokenStream()' nodeId='|[engine:engine1|]' parentNodeId='0'locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream']\n" + "\n" + - "##teamcity[testStarted name='Class Configuration' locationHint='java:suite://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream']\n" + + "##teamcity[testStarted name='Class Configuration' nodeId='Class Configuration' parentNodeId='0' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream']\n" + "\n" + - "##teamcity[testFailed name='Class Configuration' id='Class Configuration' details='TRACE' error='true' message='']\n" + + "##teamcity[testFailed name='Class Configuration' id='Class Configuration' nodeId='Class Configuration' parentNodeId='0' details='TRACE' error='true' message='']\n" + "\n" + - "##teamcity[testFinished name='Class Configuration']\n" + - "##teamcity[testSuiteFinished id='|[engine:engine1|]' name='brokenStream()']\n", StringUtil.convertLineSeparators(myBuf.toString())); + "##teamcity[testFinished name='Class Configuration' nodeId='Class Configuration' parentNodeId='0' ]\n" + + "##teamcity[testSuiteFinished id='|[engine:engine1|]' name='brokenStream()' nodeId='|[engine:engine1|]' parentNodeId='0']\n", StringUtil.convertLineSeparators(myBuf.toString())); } private static class TestClass { diff --git a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java index b9ab4ec32236..8f87127cc571 100644 --- a/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java +++ b/plugins/junit5_rt_tests/test/com/intellij/junit5/JUnit5NavigationTest.java @@ -91,11 +91,6 @@ class JUnit5NavigationTest { void deriveSuiteOrTestFromDescription() { myTestSource = methodOrClassSource(); Assertions.assertTrue(locationHintValue().startsWith("java:suite:")); - - ConfigurableTestDescriptor descriptor = new ConfigurableTestDescriptor(myTestSource); - descriptor.isTest(true); - Assertions.assertTrue(locationHintValue(descriptor).startsWith("java:test:")); - } @Test @@ -140,7 +135,7 @@ class JUnit5NavigationTest { private static String locationHintValue(final ConfigurableTestDescriptor descriptor) { TestIdentifier testIdentifier = TestIdentifier.from(descriptor); - return JUnit5TestExecutionListener.getLocationHintValue(testIdentifier.getSource().orElseThrow(IllegalStateException::new), testIdentifier.isTest()); + return JUnit5TestExecutionListener.getLocationHintValue(testIdentifier.getSource().orElseThrow(IllegalStateException::new)); } private static ClassSource anySupportedSource() {