Improve the perf when resolving code lens in large java file (#1042)

This commit is contained in:
Sheng Chen 2020-08-07 13:22:23 +08:00 коммит произвёл GitHub
Родитель e720568fad
Коммит 4fd98c2661
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 345 добавлений и 85 удалений

5
.vscode/launch.json поставляемый
Просмотреть файл

@ -11,7 +11,10 @@
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/dist/**/*.js" ],
"preLaunchTask": "npm: watch"
"preLaunchTask": "npm: watch",
"env": {
"DEBUG_VSCODE_JAVA":"true"
}
},
{
"type": "java",

Просмотреть файл

@ -4,7 +4,7 @@ Bundle-Name: com.microsoft.java.test.plugin
Bundle-SymbolicName: com.microsoft.java.test.plugin;singleton:=true
Bundle-Version: 0.24.0
Bundle-Activator: com.microsoft.java.test.plugin.util.JUnitPlugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: org.eclipse.jdt.core,
org.eclipse.jdt.launching,
org.osgi.framework;version="1.3.0"

Просмотреть файл

@ -20,6 +20,9 @@ import com.microsoft.java.test.plugin.util.TestItemUtils;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.SearchPattern;
@ -74,6 +77,19 @@ public abstract class BaseFrameworkSearcher implements TestFrameworkSearcher {
return searchPattern;
}
@Override
public boolean findAnnotation(IAnnotationBinding[] annotations, String[] annotationNames) {
for (final IAnnotationBinding annotation : annotations) {
final ITypeBinding annotationType = annotation.getAnnotationType();
for (final String annotationName : annotationNames) {
if (TestFrameworkUtils.isEquivalentAnnotationType(annotationType, annotationName)) {
return true;
}
}
}
return false;
}
@Override
public TestItem parseTestItem(IMethod method) throws JavaModelException {
return TestItemUtils.constructTestItem(method, TestLevel.METHOD, this.getTestKind());
@ -83,4 +99,10 @@ public abstract class BaseFrameworkSearcher implements TestFrameworkSearcher {
public TestItem parseTestItem(IType type) throws JavaModelException {
return TestItemUtils.constructTestItem(type, TestLevel.CLASS, this.getTestKind());
}
@Override
public TestItem parseTestItem(IMethodBinding methodBinding) throws JavaModelException {
return TestItemUtils.constructTestItem((IMethod) methodBinding.getJavaElement(),
TestLevel.METHOD, this.getTestKind());
}
}

Просмотреть файл

@ -17,6 +17,9 @@ import com.microsoft.java.test.plugin.util.TestFrameworkUtils;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
public class JUnit4TestSearcher extends BaseFrameworkSearcher {
@ -33,6 +36,11 @@ public class JUnit4TestSearcher extends BaseFrameworkSearcher {
return TestKind.JUnit;
}
@Override
public String getJdtTestKind() {
return TestKindRegistry.JUNIT4_TEST_KIND_ID;
}
@Override
public boolean isTestMethod(IMethod method) {
try {
@ -55,4 +63,18 @@ public class JUnit4TestSearcher extends BaseFrameworkSearcher {
return false;
}
}
@Override
public boolean isTestMethod(IMethodBinding methodBinding) {
final int modifiers = methodBinding.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
return false;
}
if (methodBinding.isConstructor() || !"void".equals(methodBinding.getReturnType().getName())) {
return false;
}
return this.findAnnotation(methodBinding.getAnnotations(), this.getTestMethodAnnotations());
}
}

Просмотреть файл

@ -23,14 +23,21 @@ import org.eclipse.jdt.core.ISourceRange;
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.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class JUnit5TestSearcher extends BaseFrameworkSearcher {
@ -59,6 +66,11 @@ public class JUnit5TestSearcher extends BaseFrameworkSearcher {
return TestKind.JUnit5;
}
@Override
public String getJdtTestKind() {
return TestKindRegistry.JUNIT5_TEST_KIND_ID;
}
@Override
public boolean isTestMethod(IMethod method) {
try {
@ -81,6 +93,20 @@ public class JUnit5TestSearcher extends BaseFrameworkSearcher {
}
}
@Override
public boolean isTestMethod(IMethodBinding methodBinding) {
final int modifiers = methodBinding.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isStatic(modifiers) || Modifier.isPrivate(modifiers)) {
return false;
}
if (methodBinding.isConstructor()) {
return false;
}
return this.findAnnotation(methodBinding.getAnnotations(), this.getTestMethodAnnotations());
}
@SuppressWarnings("rawtypes")
@Override
public TestItem parseTestItem(IMethod method) throws JavaModelException {
@ -110,4 +136,81 @@ public class JUnit5TestSearcher extends BaseFrameworkSearcher {
item.setParamTypes(result);
return item;
}
@Override
public TestItem parseTestItem(IMethodBinding methodBinding) throws JavaModelException {
final TestItem item = super.parseTestItem(methodBinding);
// deal with @DisplayName
for (final IAnnotationBinding annotation : methodBinding.getAnnotations()) {
if (annotation == null) {
continue;
}
if (matchesName(annotation.getAnnotationType(), DISPLAY_NAME_ANNOTATION_JUNIT5)) {
item.setDisplayName((String) annotation.getAllMemberValuePairs()[0].getValue());
break;
}
}
// parse the parameters
final ITypeBinding[] parameters = methodBinding.getParameterTypes();
if (parameters.length > 0) {
final List<String> result = new LinkedList<>();
for (final ITypeBinding parameter : parameters) {
result.add(parameter.getQualifiedName());
}
item.setParamTypes(result);
}
return item;
}
@Override
public boolean findAnnotation(IAnnotationBinding[] annotations, String[] annotationNames) {
for (final IAnnotationBinding annotation : annotations) {
if (annotation == null) {
continue;
}
for (final String annotationName : annotationNames) {
if (matchesName(annotation.getAnnotationType(), annotationName)) {
return true;
}
if (JUPITER_NESTED.equals(annotationName) || JUNIT_PLATFORM_TESTABLE.equals(annotationName)) {
final Set<ITypeBinding> hierarchy = new HashSet<>();
if (matchesNameInAnnotationHierarchy(annotation, annotationName, hierarchy)) {
return true;
}
}
}
}
return false;
}
private boolean matchesName(ITypeBinding annotationType, String annotationName) {
return TestFrameworkUtils.isEquivalentAnnotationType(annotationType, annotationName);
}
private boolean matchesNameInAnnotationHierarchy(IAnnotationBinding annotation, String annotationName,
Set<ITypeBinding> hierarchy) {
final ITypeBinding type = annotation.getAnnotationType();
if (type == null) {
return false;
}
for (final IAnnotationBinding annotationBinding : type.getAnnotations()) {
if (annotationBinding == null) {
continue;
}
final ITypeBinding annotationType = annotationBinding.getAnnotationType();
if (annotationType != null && hierarchy.add(annotationType)) {
if (matchesName(annotationType, annotationName) ||
matchesNameInAnnotationHierarchy(annotationBinding, annotationName, hierarchy)) {
return true;
}
}
}
return false;
}
}

Просмотреть файл

@ -17,14 +17,21 @@ import com.microsoft.java.test.plugin.model.TestKind;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.search.SearchPattern;
public interface TestFrameworkSearcher {
TestKind getTestKind();
String getJdtTestKind();
@Deprecated
boolean isTestMethod(IMethod method);
boolean isTestMethod(IMethodBinding methodBinding);
boolean isTestClass(IType type);
String[] getTestMethodAnnotations();
@ -33,7 +40,12 @@ public interface TestFrameworkSearcher {
SearchPattern getSearchPattern();
boolean findAnnotation(IAnnotationBinding[] annotations, String[] annotationNames);
@Deprecated
TestItem parseTestItem(IMethod method) throws JavaModelException;
TestItem parseTestItem(IMethodBinding methodBinding) throws JavaModelException;
TestItem parseTestItem(IType type) throws JavaModelException;
}

Просмотреть файл

@ -17,6 +17,8 @@ import com.microsoft.java.test.plugin.util.TestFrameworkUtils;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.Modifier;
public class TestNGTestSearcher extends BaseFrameworkSearcher {
@ -31,6 +33,11 @@ public class TestNGTestSearcher extends BaseFrameworkSearcher {
return TestKind.TestNG;
}
@Override
public String getJdtTestKind() {
return "";
}
@Override
public boolean isTestMethod(IMethod method) {
try {
@ -53,4 +60,17 @@ public class TestNGTestSearcher extends BaseFrameworkSearcher {
return false;
}
}
@Override
public boolean isTestMethod(IMethodBinding methodBinding) {
final int modifiers = methodBinding.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isStatic(modifiers)) {
return false;
}
if (methodBinding.isConstructor() || !"void".equals(methodBinding.getReturnType().getName())) {
return false;
}
return this.findAnnotation(methodBinding.getAnnotations(), this.getTestMethodAnnotations());
}
}

Просмотреть файл

@ -12,6 +12,8 @@
package com.microsoft.java.test.plugin.util;
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.searcher.JUnit4TestSearcher;
import com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher;
import com.microsoft.java.test.plugin.searcher.TestFrameworkSearcher;
@ -24,8 +26,17 @@ import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder;
import org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder;
import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@ -34,7 +45,70 @@ public class TestFrameworkUtils {
public static final TestFrameworkSearcher[] FRAMEWORK_SEARCHERS = new TestFrameworkSearcher[] {
new JUnit4TestSearcher(), new JUnit5TestSearcher(), new TestNGTestSearcher() };
public static TestItem resoveTestItemForMethod(IMethod method) throws JavaModelException {
private static final JUnit4TestFinder JUNIT4_TEST_FINDER = new JUnit4TestFinder();
private static final JUnit5TestFinder JUNIT5_TEST_FINDER = new JUnit5TestFinder();
public static void findTestItemsInTypeBinding(ITypeBinding typeBinding, List<TestItem> result,
TestItem parentClassTestItem) throws JavaModelException {
final List<TestFrameworkSearcher> searchers = new ArrayList<>();
final IType type = (IType) typeBinding.getJavaElement();
for (final TestFrameworkSearcher searcher : FRAMEWORK_SEARCHERS) {
if (CoreTestSearchEngine.isAccessibleClass(type, searcher.getJdtTestKind())) {
searchers.add(searcher);
}
}
if (searchers.size() == 0) {
return;
}
final List<TestItem> testMethods = new LinkedList<>();
final List<String> testMethodIds = new LinkedList<>();
for (final IMethodBinding methodBinding : typeBinding.getDeclaredMethods()) {
for (final TestFrameworkSearcher searcher : searchers) {
if (searcher.isTestMethod(methodBinding)) {
final TestItem methodItem = searcher.parseTestItem(methodBinding);
testMethods.add(methodItem);
testMethodIds.add(methodItem.getId());
break;
}
}
}
TestItem classItem = null;
if (testMethods.size() > 0) {
result.addAll(testMethods);
classItem = TestItemUtils.constructTestItem((IType) typeBinding.getJavaElement(),
TestLevel.CLASS);
classItem.setChildren(testMethodIds);
classItem.setKind(testMethods.get(0).getKind());
result.add(classItem);
} else {
if (JUNIT4_TEST_FINDER.isTest(type)) {
// Leverage JUnit4TestFinder to handle @RunWithclasses
classItem = TestItemUtils.constructTestItem(type, TestLevel.CLASS, TestKind.JUnit);
result.add(classItem);
} else if (JUNIT5_TEST_FINDER.isTest(type)) {
// Leverage JUnit5TestFinder to handle @Nested and @Testable classes
classItem = TestItemUtils.constructTestItem(type, TestLevel.CLASS, TestKind.JUnit5);
result.add(classItem);
}
}
// set the class item as the child of its declaring type
if (classItem != null && parentClassTestItem != null) {
parentClassTestItem.addChild(classItem.getId());
}
for (final ITypeBinding childTypeBinding : typeBinding.getDeclaredTypes()) {
findTestItemsInTypeBinding(childTypeBinding, result, classItem);
}
}
public static boolean isEquivalentAnnotationType(ITypeBinding annotationType, String annotationName) {
return annotationType != null && Objects.equals(annotationType.getQualifiedName(), annotationName);
}
public static TestItem resolveTestItemForMethod(IMethod method) throws JavaModelException {
for (final TestFrameworkSearcher searcher : FRAMEWORK_SEARCHERS) {
if (searcher.isTestMethod(method)) {
return searcher.parseTestItem(method);
@ -59,6 +133,7 @@ public class TestFrameworkUtils {
* @param annotationToSearch The annotation string.
* @param checkHierarchy Specify whether to search the whole annotation hierarchy.
*/
@Deprecated
public static Optional<IAnnotation> getAnnotation(IMember member, String annotationToSearch,
boolean checkHierarchy) {
if (!IAnnotatable.class.isInstance(member)) {
@ -110,6 +185,7 @@ public class TestFrameworkUtils {
* @param annotationToSearch The annotation string.
* @param checkHierarchy Specify whether to search the whole annotation hierarchy.
*/
@Deprecated
public static boolean hasAnnotation(IMember member, String annotationToSearch, boolean checkHierarchy) {
return getAnnotation(member, annotationToSearch, checkHierarchy).isPresent();
}

Просмотреть файл

@ -14,9 +14,7 @@ package com.microsoft.java.test.plugin.util;
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 com.microsoft.java.test.plugin.searcher.JUnit4TestSearcher;
import com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher;
import org.eclipse.core.resources.IFolder;
@ -37,6 +35,12 @@ import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
@ -52,15 +56,12 @@ import org.eclipse.lsp4j.Location;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@SuppressWarnings("restriction")
@ -88,61 +89,29 @@ public class TestSearchUtils {
Job.getJobManager().join(DocumentLifeCycleHandler.DOCUMENT_LIFE_CYCLE_JOBS, monitor);
final ICompilationUnit unit = JDTUtils.resolveCompilationUnit(uri);
// whether the file is on test path or not is guarded at client side cache
if (!isJavaElementExist(unit) || monitor.isCanceled()) {
final IType primaryType = unit.findPrimaryType();
if (!isJavaElementExist(unit) || primaryType == null || monitor.isCanceled()) {
return resultList;
}
final IType[] childrenTypes = unit.getAllTypes();
final Map<String, TestItem> classMapping = new HashMap<>();
for (final IType type : childrenTypes) {
if (!isTestableClass(type)) {
continue;
}
final List<TestItem> testMethodList = Arrays.stream(type.getMethods()).map(method -> {
try {
return TestFrameworkUtils.resoveTestItemForMethod(method);
} catch (final JavaModelException e) {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
TestItem classItem = null;
if (testMethodList.size() > 0) {
classItem = TestItemUtils.constructTestItem(type, TestLevel.CLASS);
for (final TestItem method : testMethodList) {
resultList.add(method);
classItem.addChild(method.getId());
}
// Assume the kinds of all methods are the same.
classItem.setKind(testMethodList.get(0).getKind());
resultList.add(classItem);
} else {
// JUnit 5 supports nested test classes
if (isJunit5TestableClass(type)) {
classItem = TestItemUtils.constructTestItem(type, TestLevel.CLASS, TestKind.JUnit5);
resultList.add(classItem);
}
// Class annotated by @RunWith should be considered as a Suite even it has no test method children
if (TestFrameworkUtils.hasAnnotation(type, JUnit4TestSearcher.RUN_WITH, false /*checkHierarchy*/)) {
classItem = TestItemUtils.constructTestItem(type, TestLevel.CLASS, TestKind.JUnit);
resultList.add(classItem);
}
}
if (classItem == null) {
continue;
}
classMapping.put(type.getFullyQualifiedName(), classItem);
final IType declarationType = type.getDeclaringType();
if (declarationType != null) {
final TestItem declarationTypeItem = classMapping.get(declarationType.getFullyQualifiedName());
if (declarationTypeItem != null) {
declarationTypeItem.addChild(classItem.getId());
}
}
final ASTParser parser = ASTParser.newParser(AST.JLS14);
parser.setSource(unit);
parser.setFocalPosition(0);
parser.setResolveBindings(true);
parser.setIgnoreMethodBodies(true);
final CompilationUnit root = (CompilationUnit) parser.createAST(monitor);
final ASTNode node = root.findDeclaringNode(primaryType.getKey());
if (!(node instanceof TypeDeclaration)) {
return resultList;
}
final ITypeBinding binding = ((TypeDeclaration) node).resolveBinding();
if (binding == null) {
return resultList;
}
TestFrameworkUtils.findTestItemsInTypeBinding(binding, resultList, null /*parentClassItem*/);
return resultList;
}
@ -222,7 +191,7 @@ public class TestSearchUtils {
if (!scope.encloses(method)) {
return;
}
final TestItem methodItem = TestFrameworkUtils.resoveTestItemForMethod(method);
final TestItem methodItem = TestFrameworkUtils.resolveTestItemForMethod(method);
if (methodItem == null) {
return;
}
@ -409,7 +378,7 @@ public class TestSearchUtils {
continue;
}
for (final IMethod method : type.getMethods()) {
final TestItem item = TestFrameworkUtils.resoveTestItemForMethod(method);
final TestItem item = TestFrameworkUtils.resolveTestItemForMethod(method);
if (item != null) {
resultList.add(item);
}

Просмотреть файл

@ -10,7 +10,7 @@
<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
<unit id="org.eclipse.jdt.source.feature.group" version="0.0.0"/>
<unit id="org.eclipse.sdk.feature.group" version="0.0.0"/>
<repository location="http://download.eclipse.org/releases/2019-06/"/>
<repository location="http://download.eclipse.org/releases/2020-06/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.jdt.ls.core" version="0.0.0"/>

Просмотреть файл

@ -53,9 +53,9 @@
</build>
<repositories>
<repository>
<id>202003</id>
<id>202006</id>
<layout>p2</layout>
<url>https://download.eclipse.org/releases/2020-03/</url>
<url>https://download.eclipse.org/releases/2020-06/</url>
</repository>
<repository>
<id>oss.sonatype.org</id>

44
package-lock.json сгенерированный
Просмотреть файл

@ -343,7 +343,7 @@
},
"acorn": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
"resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
},
"acorn-globals": {
@ -422,7 +422,7 @@
},
"ansi-colors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
"integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
"dev": true,
"requires": {
@ -631,7 +631,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -845,7 +845,7 @@
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"dev": true,
"requires": {
@ -1587,7 +1587,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -1758,7 +1758,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -1808,7 +1808,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -2460,7 +2460,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -3238,7 +3238,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -3296,7 +3296,7 @@
"dependencies": {
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": {
@ -4117,7 +4117,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -5121,7 +5121,7 @@
},
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
},
@ -5212,7 +5212,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -5572,7 +5572,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -5587,7 +5587,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@ -6558,7 +6558,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -6596,7 +6596,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
@ -7308,7 +7308,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -8478,7 +8478,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -8807,7 +8807,7 @@
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"requires": {
"camelcase": "^1.0.2",
@ -9104,7 +9104,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@ -9748,7 +9748,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {

Просмотреть файл

@ -84,6 +84,15 @@ suite('Code Lens Tests', function() {
assert.ok(failedDetail!.duration !== undefined, 'Should have execution time');
});
test("Can show Code Lens for methods annotated with meta-annotation", async function() {
const document: TextDocument = await workspace.openTextDocument(Uris.GRADLE_JUNIT5_META_ANNOTATION_TEST);
await window.showTextDocument(document);
const codeLensProvider: TestCodeLensProvider = new TestCodeLensProvider();
let codeLens: CodeLens[] = await codeLensProvider.provideCodeLenses(document, Token.cancellationToken);
assert.equal(codeLens.length, 4);
});
test("Can run test method annotated with @Nested", async function() {
const document: TextDocument = await workspace.openTextDocument(Uris.GRADLE_JUNIT5_NESTED_TEST);
await window.showTextDocument(document);

Просмотреть файл

@ -39,6 +39,7 @@ export namespace Uris {
const GRADLE_JUNIT5_TEST_PACKAGE: string = path.join('junit5', 'src', 'test', 'java', 'junit5');
export const GRADLE_JUNIT5_PARAMETERIZED_TEST: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'ParameterizedAnnotationTest.java'));
export const GRADLE_JUNIT5_NESTED_TEST: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'NestedTest.java'));
export const GRADLE_JUNIT5_META_ANNOTATION_TEST: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'MetaAnnotationTest.java'));
export const GRADLE_JUNIT5_PROPERTY_TEST: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'PropertyTest.java'));
export const GRADLE_CUCUMBER_TEST: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'cucumber', 'CucumberTest.java'));
export const GRADLE_CUCUMBER_STEP: Uri = Uri.file(path.join(TEST_PROJECT_BASE_PATH, GRADLE_JUNIT5_TEST_PACKAGE, 'cucumber', 'CucumberSteps.java'));

Просмотреть файл

@ -0,0 +1,16 @@
package junit5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
@Test
public @interface FastTest {
}

Просмотреть файл

@ -0,0 +1,7 @@
package junit5;
public class MetaAnnotationTest {
@FastTest
void myFastTest() {
}
}