junit 5: move to id-based processing (IDEA-172141)

This commit is contained in:
Anna.Kozlova
2017-07-20 18:56:14 +02:00
parent 9b2bb11067
commit 87f6b96f83
9 changed files with 88 additions and 96 deletions
@@ -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;
@@ -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() {
@@ -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) + "()";
@@ -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();
@@ -169,7 +169,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
final Project project = getConfiguration().getProject();
final SourceScope sourceScope = getSourceScope();
GlobalSearchScope globalSearchScope = getScopeForJUnit(getConfiguration().getConfigurationModule().getModule(), sourceScope, project);
String preferredRunner = getPreferredRunner(globalSearchScope);
String preferredRunner = getConfiguration().getPreferredRunner(globalSearchScope);
if (JUnitStarter.JUNIT5_PARAMETER.equals(preferredRunner)) {
final PathsList classPath = javaParameters.getClassPath();
File lib = new File(PathUtil.getJarPathForClass(MultipleFailuresError.class)).getParentFile();
@@ -203,11 +203,6 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
return javaParameters;
}
@Nullable
protected String getPreferredRunner(GlobalSearchScope globalSearchScope) {
return JUnitUtil.isJUnit5(globalSearchScope, getConfiguration().getProject()) ? JUnitStarter.JUNIT5_PARAMETER : null;
}
private static boolean hasPackageWithDirectories(JavaPsiFacade psiFacade,
String packageQName,
GlobalSearchScope globalSearchScope) {
@@ -224,6 +219,12 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState<JUnitCon
: sourceScope != null ? sourceScope.getLibrariesScope() : GlobalSearchScope.allScope(project);
}
public static GlobalSearchScope getScopeForJUnit(JUnitConfiguration configuration) {
return getScopeForJUnit(configuration.getConfigurationModule().getModule(),
configuration.getTestSearchScope().getSourceScope(configuration),
configuration.getProject() );
}
@NotNull
protected OSProcessHandler createHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
@@ -17,6 +17,7 @@ package com.intellij.execution.junit2.ui.properties;
import com.intellij.execution.Executor;
import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.TestObject;
import com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction;
import com.intellij.execution.testframework.JavaAwareTestConsoleProperties;
import com.intellij.execution.testframework.JavaTestLocator;
@@ -27,6 +28,7 @@ import com.intellij.execution.testframework.sm.runner.SMTestLocator;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.rt.execution.junit.JUnitStarter;
import com.intellij.rt.execution.junit.RepeatCount;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,6 +40,7 @@ public class JUnitConsoleProperties extends JavaAwareTestConsoleProperties<JUnit
public JUnitConsoleProperties(@NotNull JUnitConfiguration configuration, Executor executor) {
super("JUnit", configuration, executor);
setIdBasedTestTree(JUnitStarter.JUNIT5_PARAMETER.equals(configuration.getPreferredRunner(TestObject.getScopeForJUnit(configuration))));
}
@NotNull
@@ -38,6 +38,7 @@ import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import java.util.stream.Collectors;
public class JUnit5TestExecutionListener implements TestExecutionListener {
private static final String NO_LOCATION_HINT = "";
@@ -47,7 +48,7 @@ public class JUnit5TestExecutionListener implements TestExecutionListener {
private long myCurrentTestStart;
private int myFinishCount;
private String myRootName;
private Set<TestIdentifier> myRoots = new HashSet<>();
private Set<String> 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<TestIdentifier> 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<String, String> 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<TestIdentifier> 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;
@@ -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 {
@@ -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() {