Skip to content

Commit

Permalink
Add parameter information for JUnit 5 test methods (#539)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdneo authored Dec 25, 2018
1 parent cf0d958 commit 367a422
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,18 @@ public class TestItem {

private String project;

public TestItem(String displayName, String fullName, String uri, Range range, TestLevel level, TestKind kind,
String project) {
private List<String> paramTypes;

public TestItem(String displayName, String fullName, String uri, String project, List<String> paramTypes,
Range range, TestLevel level, TestKind kind) {
this.displayName = displayName;
this.fullName = fullName;
this.uri = uri;
this.range = range;
this.level = level;
this.kind = kind;
this.project = project;
this.paramTypes = paramTypes;
}

public String getDisplayName() {
Expand Down Expand Up @@ -114,4 +117,12 @@ public void addChild(TestItem child) {
}
this.children.add(child);
}

public List<String> getParamTypes() {
return paramTypes;
}

public void setParamTypes(List<String> paramTypes) {
this.paramTypes = paramTypes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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<IAnnotation> 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<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -25,4 +27,6 @@ public interface TestFrameworkSearcher {
String[] getTestMethodAnnotations();

SearchPattern getSearchPattern();

TestItem parseTestItem(IMethod method) throws JavaModelException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,70 +25,53 @@
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);
}

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<IAnnotation> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -67,7 +66,7 @@ public class TestSearchUtils {
*/
public static List<TestItem> searchCodeLens(List<Object> arguments, IProgressMonitor monitor)
throws OperationCanceledException, InterruptedException, JavaModelException {
final List<TestItem> resultList = new ArrayList<>();
final List<TestItem> resultList = new LinkedList<>();
if (arguments == null || arguments.size() == 0) {
return resultList;
}
Expand All @@ -87,13 +86,9 @@ public static List<TestItem> searchCodeLens(List<Object> arguments, IProgressMon
if (!isTestableClass(type)) {
continue;
}
final List<TestItem> testMethodList = Arrays.stream(type.getMethods()).map(m -> {
final List<TestItem> 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;
}
Expand Down Expand Up @@ -122,7 +117,7 @@ public static List<TestItem> searchCodeLens(List<Object> arguments, IProgressMon
*/
public static List<TestItem> searchTestItems(List<Object> arguments, IProgressMonitor monitor)
throws OperationCanceledException, InterruptedException, URISyntaxException, JavaModelException {
final List<TestItem> resultList = new ArrayList<>();
final List<TestItem> resultList = new LinkedList<>();

if (arguments == null || arguments.size() == 0) {
return resultList;
Expand Down Expand Up @@ -161,7 +156,7 @@ public static List<TestItem> searchTestItems(List<Object> arguments, IProgressMo
*/
public static List<TestItem> searchAllTestItems(List<Object> arguments, IProgressMonitor monitor)
throws CoreException, OperationCanceledException, InterruptedException {
final List<TestItem> searchResult = new ArrayList<>();
final List<TestItem> searchResult = new LinkedList<>();

if (arguments == null || arguments.size() == 0) {
return searchResult;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -312,9 +306,9 @@ private static void searchInClass(List<TestItem> 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);
}
}
}
Expand All @@ -326,14 +320,20 @@ private static void searchInNestedClass(List<TestItem> 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<TestItem> searchTestMethodsOfType(IType type) throws JavaModelException {
final List<TestItem> 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 {
Expand Down
1 change: 1 addition & 0 deletions src/protocols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface ITestItem extends ITestItemBase {
kind: TestKind;
project: string;
level: TestLevel;
paramTypes: string[];
}

export interface ISearchTestItemParams {
Expand Down
2 changes: 1 addition & 1 deletion src/runners/junit5Runner/JUnit5Runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 367a422

Please sign in to comment.