Skip to content

Commit d2c9cf6

Browse files
committed
Running Kotlin and Spock tests
1 parent e5e4aff commit d2c9cf6

12 files changed

Lines changed: 455 additions & 106 deletions

File tree

java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegate.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -151,34 +151,39 @@ private void addTestItemArgs(List<String> arguments) throws CoreException {
151151
method.getParameters().length > 0) {
152152
final ICompilationUnit unit = method.getCompilationUnit();
153153
if (unit == null) {
154-
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
155-
"Cannot get compilation unit of method" + method.getElementName(), null)); //$NON-NLS-1$
156-
}
157-
final CompilationUnit root = (CompilationUnit) TestSearchUtils.parseToAst(unit,
158-
false /*fromCache*/, new NullProgressMonitor());
159-
final MethodDeclaration methodDeclaration = ASTNodeSearchUtil.getMethodDeclarationNode(method, root);
160-
if (methodDeclaration == null) {
161-
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
154+
// binary method
155+
if (method.getDeclaringType() == null) {
156+
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
157+
"Cannot get compilation unit of method" + method.getElementName(), null)); //$NON-NLS-1$
158+
}
159+
} else {
160+
final CompilationUnit root = (CompilationUnit) TestSearchUtils.parseToAst(unit,
161+
false /* fromCache */, new NullProgressMonitor());
162+
final MethodDeclaration methodDeclaration = ASTNodeSearchUtil.getMethodDeclarationNode(method,
163+
root);
164+
if (methodDeclaration == null) {
165+
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
162166
"Cannot get method declaration of method" + method.getElementName(), null)); //$NON-NLS-1$
163-
}
167+
}
164168

165-
final List<String> parameters = new LinkedList<>();
166-
for (final Object obj : methodDeclaration.parameters()) {
167-
if (obj instanceof SingleVariableDeclaration) {
168-
final ITypeBinding paramTypeBinding = ((SingleVariableDeclaration) obj)
169-
.getType().resolveBinding();
170-
if (paramTypeBinding == null) {
171-
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
172-
"Cannot set set argument for method" + methodDeclaration.toString(), null));
173-
} else if (paramTypeBinding.isPrimitive()) {
174-
parameters.add(paramTypeBinding.getQualifiedName());
175-
} else {
176-
parameters.add(paramTypeBinding.getBinaryName());
169+
final List<String> parameters = new LinkedList<>();
170+
for (final Object obj : methodDeclaration.parameters()) {
171+
if (obj instanceof SingleVariableDeclaration) {
172+
final ITypeBinding paramTypeBinding = ((SingleVariableDeclaration) obj).getType()
173+
.resolveBinding();
174+
if (paramTypeBinding == null) {
175+
throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID, IStatus.ERROR,
176+
"Cannot set set argument for method" + methodDeclaration.toString(), null));
177+
} else if (paramTypeBinding.isPrimitive()) {
178+
parameters.add(paramTypeBinding.getQualifiedName());
179+
} else {
180+
parameters.add(paramTypeBinding.getBinaryName());
181+
}
177182
}
178183
}
179-
}
180-
if (parameters.size() > 0) {
181-
testName += "(" + String.join(",", parameters) + ")";
184+
if (parameters.size() > 0) {
185+
testName += "(" + String.join(",", parameters) + ")";
186+
}
182187
}
183188
}
184189
arguments.add(method.getDeclaringType().getFullyQualifiedName() + ':' + testName);

java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/builder/JavaTestItemBuilder.java

Lines changed: 143 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,33 @@
1717
import com.microsoft.java.test.plugin.util.TestItemUtils;
1818

1919
import org.eclipse.core.resources.IProject;
20+
import org.eclipse.core.resources.IResource;
21+
import org.eclipse.core.resources.ResourcesPlugin;
2022
import org.eclipse.core.runtime.IPath;
23+
import org.eclipse.jdt.core.IClassFile;
24+
import org.eclipse.jdt.core.IClasspathEntry;
2125
import org.eclipse.jdt.core.IJavaElement;
2226
import org.eclipse.jdt.core.IJavaProject;
2327
import org.eclipse.jdt.core.IPackageFragment;
2428
import org.eclipse.jdt.core.JavaModelException;
29+
import org.eclipse.jdt.internal.core.BinaryMember;
30+
import org.eclipse.jdt.internal.core.BinaryMethod;
31+
import org.eclipse.jdt.internal.core.BinaryType;
32+
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
2533
import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore;
2634
import org.eclipse.jdt.ls.core.internal.JDTUtils;
35+
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
2736
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
37+
import org.eclipse.lsp4j.Position;
2838
import org.eclipse.lsp4j.Range;
39+
import org.objectweb.asm.ClassReader;
40+
import org.objectweb.asm.ClassVisitor;
41+
import org.objectweb.asm.Label;
42+
import org.objectweb.asm.MethodVisitor;
43+
import org.objectweb.asm.Opcodes;
44+
45+
import java.io.ByteArrayInputStream;
46+
import java.io.InputStream;
2947

3048
/**
3149
* Builder class to build {@link com.microsoft.java.test.plugin.model.JavaTestItem}
@@ -36,6 +54,7 @@ public class JavaTestItemBuilder {
3654
private IJavaElement element;
3755
private TestLevel level;
3856
private TestKind kind;
57+
private String displayName;
3958

4059
public JavaTestItemBuilder setJavaElement(IJavaElement element) {
4160
this.element = element;
@@ -52,34 +71,124 @@ public JavaTestItemBuilder setKind(TestKind kind) {
5271
return this;
5372
}
5473

74+
public JavaTestItemBuilder setDisplayName(String displayName) {
75+
this.displayName = displayName;
76+
return this;
77+
}
78+
5579
public JavaTestItem build() throws JavaModelException {
5680
if (this.element == null || this.level == null || this.kind == null) {
5781
throw new IllegalArgumentException("Failed to build Java test item due to missing arguments");
5882
}
5983

60-
final String displayName;
6184
String uri = null;
62-
if (this.element instanceof IJavaProject) {
63-
final IJavaProject javaProject = (IJavaProject) this.element;
64-
final IProject project = javaProject.getProject();
65-
if (ProjectUtils.isVisibleProject(project)) {
66-
displayName = project.getName();
85+
if (this.displayName == null) {
86+
if (this.element instanceof IJavaProject) {
87+
final IJavaProject javaProject = (IJavaProject) this.element;
88+
final IProject project = javaProject.getProject();
89+
if (ProjectUtils.isVisibleProject(project)) {
90+
displayName = project.getName();
91+
} else {
92+
final IPath realPath = ProjectUtils.getProjectRealFolder(project);
93+
displayName = realPath.lastSegment();
94+
uri = realPath.toFile().toURI().toString();
95+
}
96+
} else if (this.element instanceof IPackageFragment &&
97+
((IPackageFragment) this.element).isDefaultPackage()) {
98+
displayName = DEFAULT_PACKAGE_NAME;
99+
final IResource resource = getResource((IPackageFragment) this.element);
100+
if (resource == null || !resource.exists()) {
101+
return null;
102+
}
103+
uri = JDTUtils.getFileURI(resource);
67104
} else {
68-
final IPath realPath = ProjectUtils.getProjectRealFolder(project);
69-
displayName = realPath.lastSegment();
70-
uri = realPath.toFile().toURI().toString();
105+
displayName = JavaElementLabelsCore.getElementLabel(this.element, JavaElementLabelsCore.ALL_DEFAULT);
71106
}
72-
} else if (this.element instanceof IPackageFragment && ((IPackageFragment) this.element).isDefaultPackage()) {
73-
displayName = DEFAULT_PACKAGE_NAME;
74-
} else {
75-
displayName = JavaElementLabelsCore.getElementLabel(this.element, JavaElementLabelsCore.ALL_DEFAULT);
76107
}
108+
Range range = null;
77109
final String fullName = TestItemUtils.parseFullName(this.element, this.level, this.kind);
78110
if (uri == null) {
79-
uri = JDTUtils.getFileURI(this.element.getResource());
111+
IResource resource = this.element.getResource();
112+
if (resource == null && this.element instanceof IPackageFragment) {
113+
resource = getResource((IPackageFragment) this.element);
114+
}
115+
if (resource == null || !resource.exists()) {
116+
return null;
117+
}
118+
if (element instanceof BinaryMember) {
119+
final String[] sources = new String[1];
120+
final int[] lines = {-1};
121+
final IClassFile classFile = ((BinaryMember) element).getClassFile();
122+
try (InputStream is = new ByteArrayInputStream(classFile.getBytes())) {
123+
final ClassReader cr = new ClassReader(is);
124+
if (element instanceof BinaryType) {
125+
cr.accept(new ClassVisitor(Opcodes.ASM9) {
126+
@Override
127+
public void visitSource(String source, String debug) {
128+
sources[0] = source;
129+
}
130+
}, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
131+
} else if (element instanceof BinaryMethod) {
132+
final String methodDescriptor = ((BinaryMethod) element).getSignature();
133+
cr.accept(new ClassVisitor(Opcodes.ASM9) {
134+
@Override
135+
public void visitSource(String source, String debug) {
136+
sources[0] = source;
137+
}
138+
139+
public MethodVisitor visitMethod(int access, String name, String descriptor,
140+
String signature, String[] exceptions) {
141+
if (name.equals(element.getElementName()) && descriptor.equals(methodDescriptor)) {
142+
return new MethodVisitor(Opcodes.ASM9) {
143+
@Override
144+
public void visitLineNumber(int line, Label start) {
145+
if (lines[0] < 0) {
146+
lines[0] = line;
147+
if (line > 0) {
148+
lines[0]--;
149+
}
150+
}
151+
}
152+
};
153+
}
154+
return null;
155+
}
156+
}, ClassReader.SKIP_FRAMES);
157+
}
158+
} catch (Exception e) {
159+
JavaLanguageServerPlugin.logException(e);
160+
}
161+
if (sources[0] != null) {
162+
final IPackageFragment packageFragment = (IPackageFragment) element
163+
.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
164+
if (packageFragment != null) {
165+
final String packageName = packageFragment.getElementName();
166+
final IJavaProject project = element.getJavaProject();
167+
final String packagePath = packageName.replace('.', '/');
168+
for (final IClasspathEntry entry : project.getRawClasspath()) {
169+
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
170+
final IPath sourceFolderPath = entry.getPath();
171+
final IPath fullPath = sourceFolderPath.append(packagePath).append(sources[0]);
172+
final IResource candidate = ResourcesPlugin.getWorkspace().getRoot()
173+
.findMember(fullPath);
174+
if (candidate != null && candidate.exists()) {
175+
resource = candidate;
176+
break;
177+
}
178+
}
179+
}
180+
}
181+
}
182+
if (lines[0] > 0) {
183+
final Position line = new Position(lines[0] - 1, 0);
184+
range = new Range(line, line);
185+
}
186+
}
187+
if (uri == null) {
188+
uri = JDTUtils.getFileURI(resource);
189+
}
80190
}
81-
Range range = null;
82-
if (this.level == TestLevel.CLASS || this.level == TestLevel.METHOD) {
191+
if (range == null && (this.level == TestLevel.CLASS || this.level == TestLevel.METHOD)) {
83192
range = TestItemUtils.parseTestItemRange(this.element);
84193
}
85194

@@ -89,4 +198,22 @@ public JavaTestItem build() throws JavaModelException {
89198

90199
return result;
91200
}
201+
202+
private IResource getResource(IPackageFragment packageFragment) {
203+
if (packageFragment == null) {
204+
return null;
205+
}
206+
IResource resource = packageFragment.getResource();
207+
if (resource == null) {
208+
final IJavaElement e = packageFragment.getParent();
209+
if (e instanceof PackageFragmentRoot) {
210+
final PackageFragmentRoot root = (PackageFragmentRoot) e;
211+
resource = root.getResource();
212+
if (resource == null) {
213+
resource = root.resource(root);
214+
}
215+
}
216+
}
217+
return resource;
218+
}
92219
}

java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit4TestSearcher.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,9 @@ public Set<IType> findTestItemsInContainer(IJavaElement element, IProgressMonito
7777

7878
return types;
7979
}
80+
81+
@Override
82+
public String getDisplayName(IMethodBinding methodBinding) {
83+
return null;
84+
}
8085
}

java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit5TestSearcher.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.eclipse.jdt.core.IType;
2222
import org.eclipse.jdt.core.JavaModelException;
2323
import org.eclipse.jdt.core.dom.IAnnotationBinding;
24+
import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
2425
import org.eclipse.jdt.core.dom.IMethodBinding;
2526
import org.eclipse.jdt.core.dom.ITypeBinding;
2627
import org.eclipse.jdt.core.dom.Modifier;
@@ -40,9 +41,11 @@ public class JUnit5TestSearcher extends BaseFrameworkSearcher {
4041

4142
protected static final String DISPLAY_NAME_ANNOTATION_JUNIT5 = "org.junit.jupiter.api.DisplayName";
4243

44+
protected static final String SPOCK_FEATURE_METADATA = "org.spockframework.runtime.model.FeatureMetadata";
45+
4346
public JUnit5TestSearcher() {
4447
super();
45-
this.testMethodAnnotations = new String[] { JUNIT_PLATFORM_TESTABLE };
48+
this.testMethodAnnotations = new String[] { JUNIT_PLATFORM_TESTABLE, SPOCK_FEATURE_METADATA };
4649
}
4750

4851
@Override
@@ -133,4 +136,19 @@ public Set<IType> findTestItemsInContainer(IJavaElement element, IProgressMonito
133136
}
134137
return types;
135138
}
139+
140+
@Override
141+
public String getDisplayName(IMethodBinding methodBinding) {
142+
for (final IAnnotationBinding annotation : methodBinding.getAnnotations()) {
143+
if (matchesName(annotation.getAnnotationType(), SPOCK_FEATURE_METADATA)) {
144+
final IMemberValuePairBinding[] pairs = annotation.getDeclaredMemberValuePairs();
145+
for (final IMemberValuePairBinding pair : pairs) {
146+
if ("name".equals(pair.getName()) && (pair.getValue() instanceof String)) {
147+
return (String) pair.getValue();
148+
}
149+
}
150+
}
151+
}
152+
return null;
153+
}
136154
}

0 commit comments

Comments
 (0)