Skip to content

Commit 0e69c15

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

File tree

5 files changed

+272
-64
lines changed

5 files changed

+272
-64
lines changed

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

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
import com.microsoft.java.test.plugin.model.TestKind;
1616
import com.microsoft.java.test.plugin.model.TestLevel;
1717
import com.microsoft.java.test.plugin.util.TestItemUtils;
18-
1918
import org.eclipse.core.resources.IProject;
19+
import org.eclipse.core.resources.IResource;
2020
import org.eclipse.core.runtime.IPath;
2121
import org.eclipse.jdt.core.IJavaElement;
2222
import org.eclipse.jdt.core.IJavaProject;
2323
import org.eclipse.jdt.core.IPackageFragment;
2424
import org.eclipse.jdt.core.JavaModelException;
25+
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
2526
import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore;
2627
import org.eclipse.jdt.ls.core.internal.JDTUtils;
2728
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
@@ -71,12 +72,24 @@ public JavaTestItem build() throws JavaModelException {
7172
}
7273
} else if (this.element instanceof IPackageFragment && ((IPackageFragment) this.element).isDefaultPackage()) {
7374
displayName = DEFAULT_PACKAGE_NAME;
75+
final IResource resource = getResource((IPackageFragment) this.element);
76+
if (resource == null || !resource.exists()) {
77+
return null;
78+
}
79+
uri = JDTUtils.getFileURI(resource);
7480
} else {
7581
displayName = JavaElementLabelsCore.getElementLabel(this.element, JavaElementLabelsCore.ALL_DEFAULT);
7682
}
7783
final String fullName = TestItemUtils.parseFullName(this.element, this.level, this.kind);
7884
if (uri == null) {
79-
uri = JDTUtils.getFileURI(this.element.getResource());
85+
IResource resource = this.element.getResource();
86+
if (resource == null && this.element instanceof IPackageFragment) {
87+
resource = getResource((IPackageFragment) this.element);
88+
}
89+
if (resource == null || !resource.exists()) {
90+
return null;
91+
}
92+
uri = JDTUtils.getFileURI(resource);
8093
}
8194
Range range = null;
8295
if (this.level == TestLevel.CLASS || this.level == TestLevel.METHOD) {
@@ -89,4 +102,22 @@ public JavaTestItem build() throws JavaModelException {
89102

90103
return result;
91104
}
105+
106+
private IResource getResource(IPackageFragment packageFragment) {
107+
if (packageFragment == null) {
108+
return null;
109+
}
110+
IResource resource = packageFragment.getResource();
111+
if (resource == null) {
112+
final IJavaElement e = packageFragment.getParent();
113+
if (e instanceof PackageFragmentRoot) {
114+
final PackageFragmentRoot root = (PackageFragmentRoot) e;
115+
resource = root.getResource();
116+
if (resource == null) {
117+
resource = root.resource(root);
118+
}
119+
}
120+
}
121+
return resource;
122+
}
92123
}

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

Lines changed: 161 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.eclipse.jdt.core.dom.Modifier;
3535
import org.eclipse.jdt.core.dom.RecordDeclaration;
3636
import org.eclipse.jdt.core.dom.TypeDeclaration;
37+
import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
3738
import org.eclipse.jdt.internal.junit.launcher.ITestFinder;
3839
import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine;
3940

@@ -67,6 +68,157 @@ public class JUnit6TestFinder implements ITestFinder {
6768
*/
6869
private static final String JUNIT6_LOADER = "org.eclipse.jdt.junit.loader.junit6";
6970

71+
private static class Annotation {
72+
73+
private static final Annotation RUN_WITH = new Annotation("org.junit.runner.RunWith"); //$NON-NLS-1$
74+
75+
private static final Annotation TEST_4 = new Annotation("org.junit.Test"); //$NON-NLS-1$
76+
77+
private static final Annotation SUITE = new Annotation("org.junit.platform.suite.api.Suite"); //$NON-NLS-1$
78+
79+
private static final Annotation TESTABLE = new Annotation(JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME);
80+
81+
private static final Annotation NESTED = new Annotation(JUnitCorePlugin.JUNIT5_JUPITER_NESTED_ANNOTATION_NAME);
82+
83+
private final String fName;
84+
85+
private Annotation(String name) {
86+
fName = name;
87+
}
88+
89+
String getName() {
90+
return fName;
91+
}
92+
93+
boolean annotatesAtLeastOneInnerClass(ITypeBinding type) {
94+
if (type == null) {
95+
return false;
96+
}
97+
if (annotatesDeclaredTypes(type)) {
98+
return true;
99+
}
100+
final ITypeBinding superClass = type.getSuperclass();
101+
if (annotatesAtLeastOneInnerClass(superClass)) {
102+
return true;
103+
}
104+
final ITypeBinding[] interfaces = type.getInterfaces();
105+
for (final ITypeBinding intf : interfaces) {
106+
if (annotatesAtLeastOneInnerClass(intf)) {
107+
return true;
108+
}
109+
}
110+
return false;
111+
}
112+
113+
private boolean annotatesDeclaredTypes(ITypeBinding type) {
114+
final ITypeBinding[] declaredTypes = type.getDeclaredTypes();
115+
for (final ITypeBinding declaredType : declaredTypes) {
116+
if (isNestedClass(declaredType)) {
117+
return true;
118+
}
119+
}
120+
return false;
121+
}
122+
123+
private boolean isNestedClass(ITypeBinding type) {
124+
final int modifiers = type.getModifiers();
125+
if (type.isInterface() || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) {
126+
return false;
127+
}
128+
if (annotates(type.getAnnotations())) {
129+
return true;
130+
}
131+
return false;
132+
}
133+
134+
boolean annotatesTypeOrSuperTypes(ITypeBinding type) {
135+
while (type != null) {
136+
if (annotates(type.getAnnotations())) {
137+
return true;
138+
}
139+
type = type.getSuperclass();
140+
}
141+
return false;
142+
}
143+
144+
boolean annotatesAtLeastOneMethod(ITypeBinding type) {
145+
if (type == null) {
146+
return false;
147+
}
148+
if (annotatesDeclaredMethods(type)) {
149+
return true;
150+
}
151+
final ITypeBinding superClass = type.getSuperclass();
152+
if (annotatesAtLeastOneMethod(superClass)) {
153+
return true;
154+
}
155+
final ITypeBinding[] interfaces = type.getInterfaces();
156+
for (final ITypeBinding intf : interfaces) {
157+
if (annotatesAtLeastOneMethod(intf)) {
158+
return true;
159+
}
160+
}
161+
return false;
162+
}
163+
164+
private boolean annotatesDeclaredMethods(ITypeBinding type) {
165+
final IMethodBinding[] declaredMethods = type.getDeclaredMethods();
166+
for (final IMethodBinding curr : declaredMethods) {
167+
if (annotates(curr.getAnnotations())) {
168+
return true;
169+
}
170+
}
171+
return false;
172+
}
173+
174+
// See JUnitLaunchConfigurationTab#isAnnotatedWithTestable also.
175+
private boolean annotates(IAnnotationBinding[] annotations) {
176+
for (final IAnnotationBinding annotation : annotations) {
177+
if (annotation == null) {
178+
continue;
179+
}
180+
if (matchesName(annotation.getAnnotationType())) {
181+
return true;
182+
}
183+
if (TESTABLE.getName().equals(fName) || NESTED.getName().equals(fName)) {
184+
final Set<ITypeBinding> hierarchy = new HashSet<>();
185+
if (matchesNameInAnnotationHierarchy(annotation, hierarchy)) {
186+
return true;
187+
}
188+
}
189+
}
190+
return false;
191+
}
192+
193+
private boolean matchesName(ITypeBinding annotationType) {
194+
if (annotationType != null) {
195+
final String qualifiedName = annotationType.getQualifiedName();
196+
if (qualifiedName.equals(fName)) {
197+
return true;
198+
}
199+
}
200+
return false;
201+
}
202+
203+
private boolean matchesNameInAnnotationHierarchy(IAnnotationBinding annotation, Set<ITypeBinding> hierarchy) {
204+
final ITypeBinding type = annotation.getAnnotationType();
205+
if (type != null) {
206+
for (final IAnnotationBinding annotationBinding : type.getAnnotations()) {
207+
if (annotationBinding != null) {
208+
final ITypeBinding annotationType = annotationBinding.getAnnotationType();
209+
if (annotationType != null && hierarchy.add(annotationType)) {
210+
if (matchesName(annotationType) ||
211+
matchesNameInAnnotationHierarchy(annotationBinding, hierarchy)) {
212+
return true;
213+
}
214+
}
215+
}
216+
}
217+
}
218+
return false;
219+
}
220+
}
221+
70222
public JUnit6TestFinder() {
71223
}
72224

@@ -172,32 +324,20 @@ private static boolean isAvailable(ISourceRange range) {
172324
return range != null && range.getOffset() != -1;
173325
}
174326

175-
private boolean isTest(ITypeBinding typeBinding) {
176-
if (typeBinding == null || Modifier.isAbstract(typeBinding.getModifiers())) {
327+
private boolean isTest(ITypeBinding binding) {
328+
if (binding == null || Modifier.isAbstract(binding.getModifiers())) {
177329
return false;
178330
}
179331

180-
// Check if the type itself has test methods
181-
if (hasTestMethods(typeBinding)) {
332+
if (Annotation.RUN_WITH.annotatesTypeOrSuperTypes(binding) ||
333+
Annotation.SUITE.annotatesTypeOrSuperTypes(binding) ||
334+
Annotation.TEST_4.annotatesAtLeastOneMethod(binding) ||
335+
Annotation.TESTABLE.annotatesAtLeastOneMethod(binding) ||
336+
Annotation.TESTABLE.annotatesTypeOrSuperTypes(binding) ||
337+
Annotation.NESTED.annotatesAtLeastOneInnerClass(binding)) {
182338
return true;
183339
}
184-
185-
// Check nested classes with @Nested annotation
186-
for (final ITypeBinding nestedType : typeBinding.getDeclaredTypes()) {
187-
if (isNestedTestClass(nestedType)) {
188-
return true;
189-
}
190-
}
191-
192-
// Check superclass
193-
final ITypeBinding superclass = typeBinding.getSuperclass();
194-
if (superclass != null && !superclass.getQualifiedName().equals("java.lang.Object")) {
195-
if (isTest(superclass)) {
196-
return true;
197-
}
198-
}
199-
200-
return false;
340+
return CoreTestSearchEngine.isTestImplementor(binding);
201341
}
202342

203343
private boolean hasTestMethods(ITypeBinding typeBinding) {

java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static Range parseTestItemRange(IJavaElement element) throws JavaModelExc
3737
sourceRange.getLength() - nameRange.getOffset() + sourceRange.getOffset());
3838
}
3939
}
40-
return null;
40+
return JDTUtils.newRange();
4141
}
4242

4343
public static String parseFullName(IJavaElement element, TestLevel level, TestKind kind) {

0 commit comments

Comments
 (0)