From 367a4225e2196a39a335d43095cef5e6d165d6f1 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 25 Dec 2018 12:46:23 +0800 Subject: [PATCH] Add parameter information for JUnit 5 test methods (#539) --- .../java/test/plugin/model/TestItem.java | 15 ++++- .../searcher/BaseFrameworkSearcher.java | 8 +++ .../plugin/searcher/JUnit5TestSearcher.java | 47 +++++++++++++++ .../searcher/TestFrameworkSearcher.java | 4 ++ .../test/plugin/util/TestFrameworkUtils.java | 6 +- .../java/test/plugin/util/TestItemUtils.java | 60 +++++++------------ .../test/plugin/util/TestSearchUtils.java | 44 +++++++------- src/protocols.ts | 1 + src/runners/junit5Runner/JUnit5Runner.ts | 2 +- 9 files changed, 120 insertions(+), 67 deletions(-) diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestItem.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestItem.java index 363e3813..bdcba386 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestItem.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestItem.java @@ -33,8 +33,10 @@ public class TestItem { private String project; - public TestItem(String displayName, String fullName, String uri, Range range, TestLevel level, TestKind kind, - String project) { + private List paramTypes; + + public TestItem(String displayName, String fullName, String uri, String project, List paramTypes, + Range range, TestLevel level, TestKind kind) { this.displayName = displayName; this.fullName = fullName; this.uri = uri; @@ -42,6 +44,7 @@ public TestItem(String displayName, String fullName, String uri, Range range, Te this.level = level; this.kind = kind; this.project = project; + this.paramTypes = paramTypes; } public String getDisplayName() { @@ -114,4 +117,12 @@ public void addChild(TestItem child) { } this.children.add(child); } + + public List getParamTypes() { + return paramTypes; + } + + public void setParamTypes(List paramTypes) { + this.paramTypes = paramTypes; + } } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/BaseFrameworkSearcher.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/BaseFrameworkSearcher.java index a5fe58e5..824b3014 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/BaseFrameworkSearcher.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/BaseFrameworkSearcher.java @@ -11,8 +11,11 @@ package com.microsoft.java.test.plugin.searcher; +import com.microsoft.java.test.plugin.model.TestItem; import com.microsoft.java.test.plugin.model.TestKind; +import com.microsoft.java.test.plugin.model.TestLevel; import com.microsoft.java.test.plugin.util.TestFrameworkUtils; +import com.microsoft.java.test.plugin.util.TestItemUtils; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IMethod; @@ -76,4 +79,9 @@ public SearchPattern getSearchPattern() { } return searchPattern; } + + @Override + public TestItem parseTestItem(IMethod method) throws JavaModelException { + return TestItemUtils.constructTestItem(method, TestLevel.METHOD, this.getTestKind()); + } } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit5TestSearcher.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit5TestSearcher.java index 831428d2..4f07cf6e 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit5TestSearcher.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit5TestSearcher.java @@ -11,10 +11,29 @@ package com.microsoft.java.test.plugin.searcher; +import com.microsoft.java.test.plugin.model.TestItem; import com.microsoft.java.test.plugin.model.TestKind; +import com.microsoft.java.test.plugin.util.TestFrameworkUtils; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.manipulation.CoreASTProvider; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; public class JUnit5TestSearcher extends BaseFrameworkSearcher { + protected static final String DISPLAY_NAME_ANNOTATION_JUNIT5 = "org.junit.jupiter.api.DisplayName"; + protected static final String[] TEST_METHOD_ANNOTATIONS = { "org.junit.jupiter.api.Test", "org.junit.jupiter.params.ParameterizedTest" @@ -28,4 +47,32 @@ public JUnit5TestSearcher() { public TestKind getTestKind() { return TestKind.JUnit5; } + + @SuppressWarnings("rawtypes") + @Override + public TestItem parseTestItem(IMethod method) throws JavaModelException { + final TestItem item = super.parseTestItem(method); + // Check if the method has annotated with @DisplayName + final Optional annotation = TestFrameworkUtils.getAnnotation(method, + DISPLAY_NAME_ANNOTATION_JUNIT5); + if (annotation.isPresent()) { + item.setDisplayName((String) annotation.get().getMemberValuePairs()[0].getValue()); + } + + // Get the parameter type information + final List result = new LinkedList<>(); + final CompilationUnit astRoot = CoreASTProvider.getInstance().getAST( + method.getDeclaringType().getCompilationUnit(), CoreASTProvider.WAIT_YES, new NullProgressMonitor()); + final ASTNode name = NodeFinder.perform(astRoot, method.getSourceRange()); + if (name instanceof MethodDeclaration) { + final List parameterList = ((MethodDeclaration) name).parameters(); + for (final Object obj : parameterList) { + if (obj instanceof SingleVariableDeclaration) { + result.add(((SingleVariableDeclaration) obj).getType().resolveBinding().getQualifiedName()); + } + } + } + item.setParamTypes(result); + return item; + } } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/TestFrameworkSearcher.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/TestFrameworkSearcher.java index 02cfaa1e..5b104c0d 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/TestFrameworkSearcher.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/TestFrameworkSearcher.java @@ -11,9 +11,11 @@ package com.microsoft.java.test.plugin.searcher; +import com.microsoft.java.test.plugin.model.TestItem; import com.microsoft.java.test.plugin.model.TestKind; import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.SearchPattern; public interface TestFrameworkSearcher { @@ -25,4 +27,6 @@ public interface TestFrameworkSearcher { String[] getTestMethodAnnotations(); SearchPattern getSearchPattern(); + + TestItem parseTestItem(IMethod method) throws JavaModelException; } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestFrameworkUtils.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestFrameworkUtils.java index 719bd01e..ba4be9b8 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestFrameworkUtils.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestFrameworkUtils.java @@ -11,7 +11,7 @@ package com.microsoft.java.test.plugin.util; -import com.microsoft.java.test.plugin.model.TestKind; +import com.microsoft.java.test.plugin.model.TestItem; import com.microsoft.java.test.plugin.searcher.JUnit4TestSearcher; import com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher; import com.microsoft.java.test.plugin.searcher.TestFrameworkSearcher; @@ -31,10 +31,10 @@ public class TestFrameworkUtils { public static final TestFrameworkSearcher[] FRAMEWORK_SEARCHERS = new TestFrameworkSearcher[] { new JUnit4TestSearcher(), new JUnit5TestSearcher(), new TestNGTestSearcher() }; - public static TestKind resolveTestKindForMethod(IMethod method) { + public static TestItem resoveTestItemForMethod(IMethod method) throws JavaModelException { for (final TestFrameworkSearcher searcher : FRAMEWORK_SEARCHERS) { if (searcher.isTestMethod(method)) { - return searcher.getTestKind(); + return searcher.parseTestItem(method); } } return null; diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java index b2512a71..79b655aa 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java @@ -15,7 +15,6 @@ import com.microsoft.java.test.plugin.model.TestKind; import com.microsoft.java.test.plugin.model.TestLevel; -import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; @@ -26,11 +25,10 @@ import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.lsp4j.Range; -import java.util.Optional; +import java.util.Collections; @SuppressWarnings("restriction") public class TestItemUtils { - protected static final String DISPLAY_NAME_ANNOTATION_JUNIT5 = "org.junit.jupiter.api.DisplayName"; public static TestItem constructTestItem(IJavaElement element, TestLevel level) throws JavaModelException { return constructTestItem(element, level, null); @@ -38,58 +36,42 @@ public static TestItem constructTestItem(IJavaElement element, TestLevel level) public static TestItem constructTestItem(IJavaElement element, TestLevel level, TestKind kind) throws JavaModelException { - String displayName = element.getElementName(); - if (kind == TestKind.JUnit5 && element instanceof IMethod) { - final Optional annotation = TestFrameworkUtils.getAnnotation((IMethod) element, - DISPLAY_NAME_ANNOTATION_JUNIT5); - if (annotation.isPresent()) { - displayName = (String) annotation.get().getMemberValuePairs()[0].getValue(); - } - } + final String displayName = element.getElementName(); + final String fullName = parseTestItemFullName(element, level); + final String uri = JDTUtils.getFileURI(element.getResource()); + final Range range = parseTestItemRange(element); + final String projectName = element.getJavaProject().getProject().getName(); - return new TestItem(displayName, parseTestItemFullName(element, level), - JDTUtils.getFileURI(element.getResource()), parseTestItemRange(element, level), level, kind, - element.getJavaProject().getProject().getName()); + return new TestItem(displayName, fullName, uri, projectName, Collections.emptyList(), range, level, kind); } - public static String parseTestItemFullName(IJavaElement element, TestLevel level) { - switch (level) { - case CLASS: - case NESTED_CLASS: - final IType type = (IType) element; - return type.getFullyQualifiedName(); - case METHOD: - final IMethod method = (IMethod) element; - return method.getDeclaringType().getFullyQualifiedName() + "#" + method.getElementName(); - default: - return element.getElementName(); + public static TestLevel getTestLevelForIType(IType type) { + if (type.getParent() instanceof ICompilationUnit) { + return TestLevel.CLASS; + } else { + return TestLevel.NESTED_CLASS; } } - public static Range parseTestItemRange(IJavaElement element, TestLevel level) throws JavaModelException { + private static String parseTestItemFullName(IJavaElement element, TestLevel level) { switch (level) { case CLASS: case NESTED_CLASS: final IType type = (IType) element; - return getRange(type.getCompilationUnit(), type); + return type.getFullyQualifiedName(); case METHOD: final IMethod method = (IMethod) element; - return getRange(method.getCompilationUnit(), method); + return method.getDeclaringType().getFullyQualifiedName() + "#" + method.getElementName(); default: - return null; + return element.getElementName(); } } - public static TestLevel getTestLevelForIType(IType type) { - if (type.getParent() instanceof ICompilationUnit) { - return TestLevel.CLASS; - } else { - return TestLevel.NESTED_CLASS; + private static Range parseTestItemRange(IJavaElement element) throws JavaModelException { + if (element instanceof ISourceReference) { + final ISourceRange range = ((ISourceReference) element).getNameRange(); + return JDTUtils.toRange(element.getOpenable(), range.getOffset(), range.getLength()); } - } - - private static Range getRange(ICompilationUnit typeRoot, IJavaElement element) throws JavaModelException { - final ISourceRange range = ((ISourceReference) element).getNameRange(); - return JDTUtils.toRange(typeRoot, range.getOffset(), range.getLength()); + return null; } } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java index 8c4b5d18..dcadee2a 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java @@ -14,7 +14,6 @@ import com.google.gson.Gson; import com.microsoft.java.test.plugin.model.SearchTestItemParams; import com.microsoft.java.test.plugin.model.TestItem; -import com.microsoft.java.test.plugin.model.TestKind; import com.microsoft.java.test.plugin.model.TestLevel; import org.eclipse.core.resources.ResourcesPlugin; @@ -44,9 +43,9 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -67,7 +66,7 @@ public class TestSearchUtils { */ public static List searchCodeLens(List arguments, IProgressMonitor monitor) throws OperationCanceledException, InterruptedException, JavaModelException { - final List resultList = new ArrayList<>(); + final List resultList = new LinkedList<>(); if (arguments == null || arguments.size() == 0) { return resultList; } @@ -87,13 +86,9 @@ public static List searchCodeLens(List arguments, IProgressMon if (!isTestableClass(type)) { continue; } - final List testMethodList = Arrays.stream(type.getMethods()).map(m -> { + final List testMethodList = Arrays.stream(type.getMethods()).map(method -> { try { - final TestKind kind = TestFrameworkUtils.resolveTestKindForMethod(m); - if (kind != null) { - return TestItemUtils.constructTestItem(m, TestLevel.METHOD, kind); - } - return null; + return TestFrameworkUtils.resoveTestItemForMethod(method); } catch (final JavaModelException e) { return null; } @@ -122,7 +117,7 @@ public static List searchCodeLens(List arguments, IProgressMon */ public static List searchTestItems(List arguments, IProgressMonitor monitor) throws OperationCanceledException, InterruptedException, URISyntaxException, JavaModelException { - final List resultList = new ArrayList<>(); + final List resultList = new LinkedList<>(); if (arguments == null || arguments.size() == 0) { return resultList; @@ -161,7 +156,7 @@ public static List searchTestItems(List arguments, IProgressMo */ public static List searchAllTestItems(List arguments, IProgressMonitor monitor) throws CoreException, OperationCanceledException, InterruptedException { - final List searchResult = new ArrayList<>(); + final List searchResult = new LinkedList<>(); if (arguments == null || arguments.size() == 0) { return searchResult; @@ -190,8 +185,7 @@ public void acceptSearchMatch(SearchMatch match) throws CoreException { if (params.getLevel() == TestLevel.METHOD && !scope.encloses(method)) { return; } - final TestItem methodItem = TestItemUtils.constructTestItem(method, TestLevel.METHOD, - TestFrameworkUtils.resolveTestKindForMethod(method)); + final TestItem methodItem = TestFrameworkUtils.resoveTestItemForMethod(method); final IType type = (IType) method.getParent(); final TestItem classItem = classMap.get(type.getFullyQualifiedName()); if (classItem != null) { @@ -312,9 +306,9 @@ private static void searchInClass(List resultList, SearchTestItemParam resultList.add(TestItemUtils.constructTestItem(innerType, TestLevel.NESTED_CLASS)); } for (final IMethod method : type.getMethods()) { - final TestKind kind = TestFrameworkUtils.resolveTestKindForMethod(method); - if (kind != null) { - resultList.add(TestItemUtils.constructTestItem(method, TestLevel.METHOD, kind)); + final TestItem item = TestFrameworkUtils.resoveTestItemForMethod(method); + if (item != null) { + resultList.add(item); } } } @@ -326,14 +320,20 @@ private static void searchInNestedClass(List resultList, SearchTestIte final ICompilationUnit compilationUnit = JDTUtils.resolveCompilationUnit(params.getUri()); for (final IType type : compilationUnit.getAllTypes()) { if (type.getFullyQualifiedName().equals(params.getFullName())) { - for (final IMethod method : type.getMethods()) { - final TestKind kind = TestFrameworkUtils.resolveTestKindForMethod(method); - if (kind != null) { - resultList.add(TestItemUtils.constructTestItem(method, TestLevel.METHOD, kind)); - } - } + resultList.addAll(searchTestMethodsOfType(type)); + } + } + } + + private static List searchTestMethodsOfType(IType type) throws JavaModelException { + final List results = new LinkedList<>(); + for (final IMethod method : type.getMethods()) { + final TestItem item = TestFrameworkUtils.resoveTestItemForMethod(method); + if (item != null) { + results.add(item); } } + return results; } private static boolean isTestableClass(IType type) throws JavaModelException { diff --git a/src/protocols.ts b/src/protocols.ts index 4ebac864..5645126b 100644 --- a/src/protocols.ts +++ b/src/protocols.ts @@ -15,6 +15,7 @@ export interface ITestItem extends ITestItemBase { kind: TestKind; project: string; level: TestLevel; + paramTypes: string[]; } export interface ISearchTestItemParams { diff --git a/src/runners/junit5Runner/JUnit5Runner.ts b/src/runners/junit5Runner/JUnit5Runner.ts index c754ba9d..76865072 100644 --- a/src/runners/junit5Runner/JUnit5Runner.ts +++ b/src/runners/junit5Runner/JUnit5Runner.ts @@ -21,7 +21,7 @@ export class JUnit5Runner extends BaseRunner { if (test.level === TestLevel.Class || test.level === TestLevel.NestedClass) { params.push('-c', test.fullName); } else if (test.level === TestLevel.Method) { - params.push('-m', test.fullName); + params.push('-m', `${test.fullName}(${test.paramTypes.join(',')})`); } } return params;