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 }), );