diff --git a/java-extension/com.microsoft.java.test.plugin.test/META-INF/MANIFEST.MF b/java-extension/com.microsoft.java.test.plugin.test/META-INF/MANIFEST.MF
index 4e03aee2..cc743c32 100644
--- a/java-extension/com.microsoft.java.test.plugin.test/META-INF/MANIFEST.MF
+++ b/java-extension/com.microsoft.java.test.plugin.test/META-INF/MANIFEST.MF
@@ -10,6 +10,7 @@ Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.jdt.ls.core,
com.microsoft.java.test.plugin,
+ com.google.gson,
org.junit,
org.apache.commons.commons-io;bundle-version="2.12.0",
org.eclipse.core.resources,
diff --git a/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.classpath b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.classpath
new file mode 100644
index 00000000..b6d99b1f
--- /dev/null
+++ b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.classpath
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.project b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.project
new file mode 100644
index 00000000..1615557d
--- /dev/null
+++ b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/.project
@@ -0,0 +1,17 @@
+
+
+ modular-junit
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/main/java/module-info.java b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/main/java/module-info.java
new file mode 100644
index 00000000..47c99b7e
--- /dev/null
+++ b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/main/java/module-info.java
@@ -0,0 +1,2 @@
+module com.example.modular {
+}
diff --git a/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p1/FirstTest.java b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p1/FirstTest.java
new file mode 100644
index 00000000..b94a787c
--- /dev/null
+++ b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p1/FirstTest.java
@@ -0,0 +1,9 @@
+package p1;
+
+import org.junit.jupiter.api.Test;
+
+class FirstTest {
+ @Test
+ void testFirstPackage() {
+ }
+}
diff --git a/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p2/SecondTest.java b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p2/SecondTest.java
new file mode 100644
index 00000000..93df5d89
--- /dev/null
+++ b/java-extension/com.microsoft.java.test.plugin.test/projects/modular-junit/src/test/java/p2/SecondTest.java
@@ -0,0 +1,9 @@
+package p2;
+
+import org.junit.jupiter.api.Test;
+
+class SecondTest {
+ @Test
+ void testSecondPackage() {
+ }
+}
diff --git a/java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegateTest.java b/java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegateTest.java
index d5c97416..6baaf304 100644
--- a/java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegateTest.java
+++ b/java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegateTest.java
@@ -12,17 +12,24 @@
package com.microsoft.java.test.plugin.launchers;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
import org.junit.Test;
import com.microsoft.java.test.plugin.AbstractProjectsManagerBasedTest;
import com.microsoft.java.test.plugin.model.Response;
+import com.google.gson.Gson;
public class JUnitLaunchConfigurationDelegateTest extends AbstractProjectsManagerBasedTest {
@@ -39,4 +46,40 @@ public void testWorkingDirectoryForTestNgUnmanagedFolder() throws Exception {
assertEquals(0, response.getStatus());
assertTrue(response.getBody().workingDirectory.endsWith("simple"));
}
+
+ @Test
+ public void testAddOpensForAllSelectedPackagesInModularProject() throws Exception {
+ final IProject project = importProjects("modular-junit").get(0);
+ final IJavaProject javaProject = JavaCore.create(project);
+ final IType firstTest = javaProject.findType("p1.FirstTest");
+ final IType secondTest = javaProject.findType("p2.SecondTest");
+ assertNotNull(firstTest);
+ assertNotNull(secondTest);
+
+ final Map request = new LinkedHashMap<>();
+ request.put("projectName", javaProject.getElementName());
+ request.put("testLevel", 5);
+ request.put("testKind", 0);
+ request.put("testNames", Arrays.asList(
+ firstTest.getFullyQualifiedName(), secondTest.getFullyQualifiedName()));
+ request.put("testHandles", Arrays.asList(
+ firstTest.getHandleIdentifier(), secondTest.getHandleIdentifier()));
+
+ final Response response = JUnitLaunchUtils.resolveLaunchArgument(
+ Arrays.asList(new Gson().toJson(request)), new NullProgressMonitor());
+
+ assertEquals(0, response.getStatus());
+ final List vmArguments = Arrays.asList(response.getBody().vmArguments);
+ final String firstPackagePrefix = "com.example.modular/p1=";
+ final String firstPackageOpen = vmArguments.stream()
+ .filter(argument -> argument.startsWith(firstPackagePrefix))
+ .findFirst()
+ .orElseThrow(() -> new AssertionError("Missing --add-opens for p1"));
+ final String targets = firstPackageOpen.substring(firstPackagePrefix.length());
+ final String secondPackageOpen = "com.example.modular/p2=" + targets;
+ assertEquals("--add-opens", vmArguments.get(vmArguments.indexOf(firstPackageOpen) - 1));
+ assertTrue(vmArguments.contains(secondPackageOpen));
+ assertEquals("--add-opens", vmArguments.get(vmArguments.indexOf(secondPackageOpen) - 1));
+ }
+
}
diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegate.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegate.java
index 65cfffbb..c0711c5c 100644
--- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegate.java
+++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegate.java
@@ -28,8 +28,11 @@
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.Launch;
import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
@@ -65,6 +68,30 @@ public JUnitLaunchConfigurationDelegate(Argument args) {
this.args = args;
}
+ @Override
+ protected IMember[] evaluateTests(ILaunchConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException {
+ if (this.args.testLevel != TestLevel.CLASS || this.args.testNames == null ||
+ this.args.testNames.length < 2 || this.args.testHandles == null) {
+ return super.evaluateTests(configuration, monitor);
+ }
+ if (this.args.testHandles.length != this.args.testNames.length) {
+ throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID,
+ "Cannot resolve all selected test classes. Refresh the Test Explorer and retry."));
+ }
+
+ final List testTypes = new ArrayList<>();
+ for (final String handle : this.args.testHandles) {
+ final IJavaElement element = JavaCore.create(handle);
+ if (!(element instanceof IType) || !element.exists()) {
+ throw new CoreException(new Status(IStatus.ERROR, JUnitPlugin.PLUGIN_ID,
+ "Cannot resolve a selected test class. Refresh the Test Explorer and retry."));
+ }
+ testTypes.add((IType) element);
+ }
+ return testTypes.toArray(new IMember[testTypes.size()]);
+ }
+
public Response getJUnitLaunchArguments(ILaunchConfiguration configuration, String mode,
IProgressMonitor monitor) {
final ILaunch launch = new Launch(configuration, mode, null);
diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchUtils.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchUtils.java
index f09703a3..738ba41a 100644
--- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchUtils.java
+++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchUtils.java
@@ -258,6 +258,7 @@ class Argument {
public TestLevel testLevel;
public TestKind testKind;
public String[] testNames;
+ public String[] testHandles;
public String uniqueId;
}
}
diff --git a/src/utils/launchUtils.ts b/src/utils/launchUtils.ts
index 0fb746e4..d22e4eb6 100644
--- a/src/utils/launchUtils.ts
+++ b/src/utils/launchUtils.ts
@@ -96,6 +96,7 @@ async function getLaunchArguments(testContext: IRunTestContext): Promise {
+function getTestHandles(testContext: IRunTestContext): string[] {
+ if (dataCache.get(testContext.testItems[0])?.testLevel !== TestLevel.Class ||
+ testContext.testItems.length < 2) {
+ return [];
+ }
+
+ const handles: (string | undefined)[] = testContext.testItems.map((item: TestItem) => {
+ return dataCache.get(item)?.jdtHandler;
+ });
+ if (handles.some((handle: string | undefined) => !handle)) {
+ const error: Error = new Error('Failed to resolve all selected test classes. Refresh the Test Explorer and retry.');
+ sendError(error);
+ throw error;
+ }
+ return handles as string[];
+}
+
+async function resolveJUnitLaunchArguments(projectName: string, testLevel: TestLevel, testKind: TestKind,
+ testNames: string[], testHandles: string[], uniqueId: string | undefined): Promise {
const argument: Response | undefined = await executeJavaLanguageServerCommand>(
JavaTestRunnerDelegateCommands.RESOLVE_JUNIT_ARGUMENT, JSON.stringify({
projectName,
testLevel,
testKind,
testNames,
+ testHandles,
uniqueId
}),
);