java test locator: use metainfo to store parameters (IDEA-169549)

it makes possible to distinguish multiple overloads, possible with custom runners and with junit 5
This commit is contained in:
Anna Kozlova
2018-01-04 16:41:54 +01:00
parent 87326679b3
commit 3d20076e7c
11 changed files with 109 additions and 66 deletions
@@ -23,12 +23,14 @@ import com.intellij.execution.testframework.sm.runner.SMTestLocator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
@@ -69,10 +71,32 @@ public class JavaTestLocator implements SMTestLocator {
return results;
}
@NotNull
@Override
public List<Location> getLocation(@NotNull String protocol,
@NotNull String path,
@Nullable String metainfo,
@NotNull Project project,
@NotNull GlobalSearchScope scope) {
List<Location> locations = getLocation(protocol, path, project, scope);
if (locations.size() > 1 && metainfo != null) {
for (Location location : locations) {
PsiElement element = location.getPsiElement();
if (element instanceof PsiMethod) {
if (metainfo.equals(ClassUtil.getVMParametersMethodSignature((PsiMethod)element))) {
return Collections.singletonList(location);
}
}
}
}
return locations;
}
private static List<Location> collectMethodNavigatables(@NotNull String path,
@NotNull Project project,
@NotNull GlobalSearchScope scope,
String paramName) {
String paramName) {
List<Location> results = Collections.emptyList();
String className = StringUtil.getPackageName(path);
if (!StringUtil.isEmpty(className)) {
@@ -17,6 +17,7 @@ package com.intellij.psi.util;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import gnu.trove.TObjectIntHashMap;
@@ -270,4 +271,41 @@ public class ClassUtil {
PsiFile parentFile = aClass.getContainingFile();
return parentFile != null && parentFile.getLanguage() == JavaLanguage.INSTANCE; // do not select JspClass
}
public static String getVMParametersMethodSignature(PsiMethod method) {
return StringUtil.join(method.getParameterList().getParameters(),
param -> {
PsiType type = TypeConversionUtil.erasure(param.getType());
return type != null ? type.accept(createSignatureVisitor()) : "";
},
",");
}
private static PsiTypeVisitor<String> createSignatureVisitor() {
return new PsiTypeVisitor<String>() {
@Override
public String visitPrimitiveType(PsiPrimitiveType primitiveType) {
return primitiveType.getCanonicalText();
}
@Override
public String visitClassType(PsiClassType classType) {
PsiClass aClass = classType.resolve();
if (aClass == null) {
return "";
}
return getJVMClassName(aClass);
}
@Override
public String visitArrayType(PsiArrayType arrayType) {
PsiType componentType = arrayType.getComponentType();
String typePresentation = componentType.accept(this);
if (componentType instanceof PsiClassType) {
typePresentation = "L" + typePresentation + ";";
}
return "[" + typePresentation;
}
};
}
}
@@ -156,14 +156,14 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP
}
@Override
protected SMTestProxy createSuite(String suiteName, String locationHint, String id, String parentNodeId) {
Node node = createNode(new TestSuiteStartedEvent(suiteName, id, parentNodeId, locationHint, null, null, null, false), true);
protected SMTestProxy createSuite(String suiteName, String locationHint, String metaInfo, String id, String parentNodeId) {
Node node = createNode(new TestSuiteStartedEvent(suiteName, id, parentNodeId, locationHint, metaInfo, null, null, false), true);
return node.getProxy();
}
@Override
protected SMTestProxy createProxy(String testName, String locationHint, String id, String parentNodeId) {
Node node = createNode(new TestStartedEvent(testName, id, parentNodeId, locationHint, null, null, null, false), false);
protected SMTestProxy createProxy(String testName, String locationHint, String metaInfo, String id, String parentNodeId) {
Node node = createNode(new TestStartedEvent(testName, id, parentNodeId, locationHint, metaInfo, null, null, false), false);
return node.getProxy();
}
@@ -76,20 +76,20 @@ public abstract class GeneralTestEventsProcessor implements Disposable {
});
}
protected SMTestProxy createProxy(String testName, String locationHint, String id, String parentNodeId) {
return new SMTestProxy(testName, false, locationHint);
protected SMTestProxy createProxy(String testName, String locationHint, String metaInfo, String id, String parentNodeId) {
return new SMTestProxy(testName, false, locationHint, metaInfo, false);
}
protected SMTestProxy createSuite(String suiteName, String locationHint, String id, String parentNodeId) {
return new SMTestProxy(suiteName, true, locationHint);
protected SMTestProxy createSuite(String suiteName, String locationHint, String metaInfo, String id, String parentNodeId) {
return new SMTestProxy(suiteName, true, locationHint, metaInfo, false);
}
protected final List<Runnable> myBuildTreeRunnables = new ArrayList<>();
public void onSuiteTreeNodeAdded(final String testName, final String locationHint, String id, String parentNodeId) {
public void onSuiteTreeNodeAdded(final String testName, final String locationHint, final String metaInfo, String id, String parentNodeId) {
myTreeBuildBeforeStart = true;
myBuildTreeRunnables.add(() -> {
final SMTestProxy testProxy = createProxy(testName, locationHint, id, parentNodeId);
final SMTestProxy testProxy = createProxy(testName, locationHint, metaInfo, id, parentNodeId);
testProxy.setTreeBuildBeforeStart();
if (myLocator != null) {
testProxy.setLocator(myLocator);
@@ -103,10 +103,10 @@ public abstract class GeneralTestEventsProcessor implements Disposable {
});
}
public void onSuiteTreeStarted(final String suiteName, final String locationHint, String id, String parentNodeId) {
public void onSuiteTreeStarted(final String suiteName, final String locationHint, String metaInfo, String id, String parentNodeId) {
myTreeBuildBeforeStart = true;
myBuildTreeRunnables.add(() -> {
final SMTestProxy newSuite = createSuite(suiteName, locationHint, id, parentNodeId);
final SMTestProxy newSuite = createSuite(suiteName, locationHint, metaInfo, id, parentNodeId);
if (myLocator != null) {
newSuite.setLocator(myLocator);
}
@@ -15,7 +15,6 @@
*/
package com.intellij.execution.testframework.sm.runner;
import com.intellij.execution.process.ProcessOutputType;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil;
import com.intellij.execution.testframework.sm.runner.events.*;
@@ -53,16 +52,16 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
}
@Override
protected SMTestProxy createProxy(String testName, String locationHint, String id, String parentNodeId) {
SMTestProxy proxy = super.createProxy(testName, locationHint, id, parentNodeId);
protected SMTestProxy createProxy(String testName, String locationHint, String metaInfo, String id, String parentNodeId) {
SMTestProxy proxy = super.createProxy(testName, locationHint, metaInfo, id, parentNodeId);
SMTestProxy currentSuite = getCurrentSuite();
currentSuite.addChild(proxy);
return proxy;
}
@Override
protected SMTestProxy createSuite(String suiteName, String locationHint, String id, String parentNodeId) {
SMTestProxy newSuite = super.createSuite(suiteName, locationHint, id, parentNodeId);
protected SMTestProxy createSuite(String suiteName, String locationHint, String metaInfo, String id, String parentNodeId) {
SMTestProxy newSuite = super.createSuite(suiteName, locationHint, metaInfo, id, parentNodeId);
final SMTestProxy parentSuite = getCurrentSuite();
parentSuite.addChild(newSuite);
@@ -222,10 +222,10 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
}
}
private void fireOnSuiteTreeNodeAdded(String testName, String locationHint, String id, String parentNodeId) {
private void fireOnSuiteTreeNodeAdded(String testName, String locationHint, String metaInfo, String id, String parentNodeId) {
final GeneralTestEventsProcessor processor = myProcessor;
if (processor != null) {
processor.onSuiteTreeNodeAdded(testName, locationHint, id, parentNodeId);
processor.onSuiteTreeNodeAdded(testName, locationHint, metaInfo, id, parentNodeId);
}
}
@@ -237,11 +237,11 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
}
}
private void fireOnSuiteTreeStarted(String suiteName, String locationHint, String id, String parentNodeId) {
private void fireOnSuiteTreeStarted(String suiteName, String locationHint, String metainfo, String id, String parentNodeId) {
final GeneralTestEventsProcessor processor = myProcessor;
if (processor != null) {
processor.onSuiteTreeStarted(suiteName, locationHint, id, parentNodeId);
processor.onSuiteTreeStarted(suiteName, locationHint, metainfo, id, parentNodeId);
}
}
@@ -564,13 +564,21 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
fireOnTestFrameworkAttached();
}
else if (SUITE_TREE_STARTED.equals(name)) {
fireOnSuiteTreeStarted(msg.getAttributes().get("name"), msg.getAttributes().get(ATTR_KEY_LOCATION_URL), TreeNodeEvent.getNodeId(msg), msg.getAttributes().get("parentNodeId"));
fireOnSuiteTreeStarted(msg.getAttributes().get("name"),
msg.getAttributes().get(ATTR_KEY_LOCATION_URL),
BaseStartedNodeEvent.getMetainfo(msg),
TreeNodeEvent.getNodeId(msg),
msg.getAttributes().get("parentNodeId"));
}
else if (SUITE_TREE_ENDED.equals(name)) {
fireOnSuiteTreeEnded(msg.getAttributes().get("name"));
}
else if (SUITE_TREE_NODE.equals(name)) {
fireOnSuiteTreeNodeAdded(msg.getAttributes().get("name"), msg.getAttributes().get(ATTR_KEY_LOCATION_URL), TreeNodeEvent.getNodeId(msg), msg.getAttributes().get("parentNodeId"));
fireOnSuiteTreeNodeAdded(msg.getAttributes().get("name"),
msg.getAttributes().get(ATTR_KEY_LOCATION_URL),
BaseStartedNodeEvent.getMetainfo(msg),
TreeNodeEvent.getNodeId(msg),
msg.getAttributes().get("parentNodeId"));
}
else if (BUILD_TREE_ENDED_NODE.equals(name)) {
fireOnBuildTreeEnded();
@@ -17,6 +17,7 @@ package com.intellij.execution.testframework.sm.runner.events;
import com.intellij.openapi.util.text.StringUtil;
import jetbrains.buildServer.messages.serviceMessages.MessageWithAttributes;
import jetbrains.buildServer.messages.serviceMessages.ServiceMessage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -97,7 +98,7 @@ public abstract class BaseStartedNodeEvent extends TreeNodeEvent {
}
@Nullable
public static String getMetainfo(@NotNull MessageWithAttributes message) {
public static String getMetainfo(@NotNull ServiceMessage message) {
return message.getAttributes().get("metainfo");
}
@@ -289,8 +289,8 @@ public class SMTestRunnerResultsFormTest extends BaseSMTRunnerTestCase {
//with test tree build before start actual tests
public void testPrependTreeAndSameTestsStartFinish() {
//send tree
myEventsProcessor.onSuiteTreeStarted("suite1", null, "suite1", "0");
myEventsProcessor.onSuiteTreeNodeAdded("test1", null, "test1", "suite1");
myEventsProcessor.onSuiteTreeStarted("suite1", null, null, "suite1", "0");
myEventsProcessor.onSuiteTreeNodeAdded("test1", null, null,"test1", "suite1");
myEventsProcessor.onSuiteTreeEnded("suite1");
//start testing
@@ -31,7 +31,6 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
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;
@@ -651,46 +650,13 @@ public class JUnitConfiguration extends JavaTestConfigurationBase {
public static String getMethodPresentation(PsiMethod method) {
if (method.getParameterList().getParametersCount() > 0 && MetaAnnotationUtil.isMetaAnnotated(method, JUnitUtil.TEST5_ANNOTATIONS)) {
return method.getName() + "(" + StringUtil.join(method.getParameterList().getParameters(),
param -> {
PsiType type = TypeConversionUtil.erasure(param.getType());
return type != null ? type.accept(createSignatureVisitor()) : "";
},
",") + ")";
return method.getName() + "(" + ClassUtil.getVMParametersMethodSignature(method) + ")";
}
else {
return method.getName();
}
}
private static PsiTypeVisitor<String> createSignatureVisitor() {
return new PsiTypeVisitor<String>() {
@Override
public String visitPrimitiveType(PsiPrimitiveType primitiveType) {
return primitiveType.getCanonicalText();
}
@Override
public String visitClassType(PsiClassType classType) {
PsiClass aClass = classType.resolve();
if (aClass == null) {
return "";
}
return ClassUtil.getJVMClassName(aClass);
}
@Override
public String visitArrayType(PsiArrayType arrayType) {
PsiType componentType = arrayType.getComponentType();
String typePresentation = componentType.accept(this);
if (componentType instanceof PsiClassType) {
typePresentation = "L" + typePresentation + ";";
}
return "[" + typePresentation;
}
};
}
public String getGeneratedName(final JavaRunConfigurationModule configurationModule) {
if (TEST_PACKAGE.equals(TEST_OBJECT) || TEST_DIRECTORY.equals(TEST_OBJECT)) {
if (TEST_SEARCH_SCOPE.getScope() == TestSearchScope.WHOLE_PROJECT) {
@@ -346,10 +346,17 @@ public class JUnit5TestExecutionListener implements TestExecutionListener {
return root.getSource()
.map(testSource -> getLocationHintValue(testSource))
.filter(maybeLocationHintValue -> !NO_LOCATION_HINT_VALUE.equals(maybeLocationHintValue))
.map(locationHintValue -> "locationHint=\'" + locationHintValue + "\'")
.map(locationHintValue -> "locationHint=\'" + locationHintValue + "\'" + getMetainfo(root))
.orElse(NO_LOCATION_HINT);
}
private static String getMetainfo(TestIdentifier root) {
return root.getSource()
.filter(testSource -> testSource instanceof MethodSource)
.map(testSource -> " metainfo=\'" + ((MethodSource)testSource).getMethodParameterTypes() + "\'")
.orElse(NO_LOCATION_HINT);
}
static String getLocationHintValue(TestSource testSource) {
if (testSource instanceof CompositeTestSource) {
@@ -90,7 +90,7 @@ class JUnit5EventsTest {
String lineSeparator = MapSerializerUtil.escapeStr(System.getProperty("line.separator"), MapSerializerUtil.STD_ESCAPER);
Assertions.assertEquals("##teamcity[enteredTheMatrix]\n" +
"\n" +
"##teamcity[testStarted id='|[engine:testMethod|]' name='test1()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.test1']\n" +
"##teamcity[testStarted id='|[engine:testMethod|]' name='test1()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.test1' metainfo='']\n" +
"\n" +
"##teamcity[testFailed name='test1()' id='|[engine:testMethod|]' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' message='' expected='expected1' actual='actual1' details='']\n" +
"\n" +
@@ -117,11 +117,11 @@ class JUnit5EventsTest {
Assertions.assertEquals("##teamcity[enteredTheMatrix]\n" +
"##teamcity[suiteTreeStarted id='|[engine:testClass|]' name='JUnit5EventsTest$TestClass' nodeId='|[engine:testClass|]' parentNodeId='0' locationHint='java:suite://com.intellij.junit5.JUnit5EventsTest$TestClass']\n" +
"##teamcity[suiteTreeStarted id='|[engine:testMethod|]' name='brokenStream()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream']\n" +
"##teamcity[suiteTreeStarted id='|[engine:testMethod|]' name='brokenStream()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream' metainfo='']\n" +
"##teamcity[suiteTreeEnded id='|[engine:testMethod|]' name='brokenStream()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]']\n" +
"##teamcity[suiteTreeEnded id='|[engine:testClass|]' name='JUnit5EventsTest$TestClass' nodeId='|[engine:testClass|]' parentNodeId='0']\n" +
"##teamcity[treeEnded]\n" +
"##teamcity[testSuiteStarted id='|[engine:testMethod|]' name='brokenStream()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]'locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream']\n" +
"##teamcity[testSuiteStarted id='|[engine:testMethod|]' name='brokenStream()' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]'locationHint='java:test://com.intellij.junit5.JUnit5EventsTest$TestClass.brokenStream' metainfo='']\n" +
"\n" +
"##teamcity[testFailed name='Class Configuration' id='|[engine:testMethod|]' nodeId='|[engine:testMethod|]' parentNodeId='|[engine:testClass|]' error='true' message='' details='TRACE']\n" +
"\n" +