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 0f3fe07d..30912c74 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 @@ -17,18 +17,41 @@ import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.Launch; +import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; +import org.eclipse.jdt.internal.junit.JUnitMessages; +import org.eclipse.jdt.internal.junit.Messages; +import org.eclipse.jdt.internal.junit.launcher.ITestKind; +import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; +import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.VMRunnerConfiguration; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; public class JUnitLaunchConfigurationDelegate extends org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate { + + private boolean fIsHierarchicalPackage; + public JUnitLaunchArguments getJUnitLaunchArguments(ILaunchConfiguration configuration, String mode, - IProgressMonitor monitor) throws CoreException { + boolean isHierarchicalPackage, IProgressMonitor monitor) throws CoreException { + fIsHierarchicalPackage = isHierarchicalPackage; final ILaunch launch = new Launch(configuration, mode, null); // TODO: Make the getVMRunnerConfiguration() in super class protected. @@ -48,11 +71,85 @@ public JUnitLaunchArguments getJUnitLaunchArguments(ILaunchConfiguration configu launchArguments.modulepath = config.getModulepath(); launchArguments.vmArguments = getVmArguments(config); launchArguments.programArguments = config.getProgramArguments(); + + // The JUnit 5 launcher only supports run a single package, here we add all the sub-package names + // to the package name file as a workaround + if (isHierarchicalPackage && + TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(getTestRunnerKind(configuration).getId())) { + appendPackageNames(launchArguments.programArguments, configuration); + } return launchArguments; } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { return null; + } finally { + fIsHierarchicalPackage = false; + } + } + + /* + * Override the super implementation when it is launched in hierarchical mode and starts from + * the package level + * + * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#evaluateTests( + * org.eclipse.debug.core.ILaunchConfiguration, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IMember[] evaluateTests(ILaunchConfiguration configuration, IProgressMonitor monitor) + throws CoreException { + if (!fIsHierarchicalPackage) { + return super.evaluateTests(configuration, monitor); + } + + final IPackageFragment testPackage = getTestPackage(configuration); + if (testPackage == null) { + return super.evaluateTests(configuration, monitor); + } + + final IPackageFragment[] packages = JavaElementUtil.getPackageAndSubpackages(testPackage); + + final HashSet result = new HashSet<>(); + final ITestKind testKind = getTestRunnerKind(configuration); + for (final IPackageFragment packageFragment : packages) { + testKind.getFinder().findTestsInContainer(packageFragment, result, monitor); + } + + if (result.isEmpty()) { + final String msg = Messages.format(JUnitMessages.JUnitLaunchConfigurationDelegate_error_notests_kind, + testKind.getDisplayName()); + abort(msg, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE); + } + return result.toArray(new IMember[result.size()]); + } + + private IPackageFragment getTestPackage(ILaunchConfiguration configuration) throws CoreException { + final String containerHandle = configuration.getAttribute( + JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); + if (containerHandle.length() != 0) { + final IJavaElement element = JavaCore.create(containerHandle); + if (element == null || !element.exists()) { + abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_input_element_deosn_not_exist, null, + IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE); + } + if (element instanceof IPackageFragment) { + return (IPackageFragment) element; + } } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#getTestRunnerKind( + * org.eclipse.debug.core.ILaunchConfiguration) + */ + private ITestKind getTestRunnerKind(ILaunchConfiguration configuration) { + ITestKind testKind = JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration); + if (testKind.isNull()) { + testKind = TestKindRegistry.getDefault().getKind(TestKindRegistry.JUNIT4_TEST_KIND_ID); + } + return testKind; } private String[] getVmArguments(VMRunnerConfiguration config) { @@ -69,6 +166,34 @@ private String[] getVmArguments(VMRunnerConfiguration config) { return vmArgs.toArray(new String[vmArgs.size()]); } + /** + * JUnit5's runner will run packages defined in a file, we can add more packages into that file when it's + * run from hierarchical mode to let the runner run test in all the sub-packages. + */ + private void appendPackageNames(String[] programArguments, ILaunchConfiguration configuration) { + for (int i = 0; i < programArguments.length; i++) { + if ("-packageNameFile".equals(programArguments[i]) && i + 1 < programArguments.length) { + final String packageNameFilePath = programArguments[i + 1]; + final File file = new File(packageNameFilePath); + try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), + StandardCharsets.UTF_8))) { + final IPackageFragment testPackage = getTestPackage(configuration); + if (testPackage == null) { + return; + } + final IPackageFragment[] packages = JavaElementUtil.getPackageAndSubpackages(testPackage); + for (final IPackageFragment pkg : packages) { + bw.write(pkg.getElementName()); + bw.newLine(); + } + } catch (IOException | CoreException e) { + // do nothing + } + return; + } + } + } + public static class JUnitLaunchArguments { String workingDirectory; String mainClass; 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 da3bb573..95ab5d43 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 @@ -108,7 +108,7 @@ public static JUnitLaunchArguments resolveLaunchArgument(List arguments, return resolveTestNGLaunchArguments(configuration, javaProject, delegate); } - return delegate.getJUnitLaunchArguments(configuration, "run", monitor); + return delegate.getJUnitLaunchArguments(configuration, "run", args.isHierarchicalPackage, monitor); } public static void addOverrideDependencies(List vmArgs, String dependencies) { @@ -305,5 +305,6 @@ class Argument { public TestKind testKind; public Position start; public Position end; + public boolean isHierarchicalPackage; } } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/SearchTestItemParams.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/SearchTestItemParams.java index 890b797d..d894de1a 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/SearchTestItemParams.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/SearchTestItemParams.java @@ -18,10 +18,20 @@ public class SearchTestItemParams { private String fullName; + private boolean isHierarchicalPackage; + public TestLevel getLevel() { return level; } + public boolean isHierarchicalPackage() { + return isHierarchicalPackage; + } + + public void setHierarchicalPackage(boolean isHierarchicalPackage) { + this.isHierarchicalPackage = isHierarchicalPackage; + } + public void setLevel(TestLevel level) { this.level = level; } diff --git a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java index 865703f8..5c02dfcd 100644 --- a/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java +++ b/java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestSearchUtils.java @@ -49,6 +49,7 @@ import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; +import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.handlers.DocumentLifeCycleHandler; @@ -293,7 +294,7 @@ private static boolean isInTestScope(IJavaElement element) throws JavaModelExcep } private static IJavaSearchScope createSearchScope(SearchTestItemParams params) - throws JavaModelException, URISyntaxException { + throws URISyntaxException, CoreException { switch (params.getLevel()) { case ROOT: final IJavaProject[] projects = Stream.of(ProjectUtils.getJavaProjects()) @@ -306,9 +307,14 @@ private static IJavaSearchScope createSearchScope(SearchTestItemParams params) return SearchEngine.createJavaSearchScope(projectSet.toArray(new IJavaElement[projectSet.size()]), IJavaSearchScope.SOURCES); case PACKAGE: + final IJavaElement[] elements; final IJavaElement packageElement = resolvePackage(params.getUri(), params.getFullName()); - return SearchEngine.createJavaSearchScope(new IJavaElement[] { packageElement }, - IJavaSearchScope.SOURCES); + if (params.isHierarchicalPackage()) { + elements = JavaElementUtil.getPackageAndSubpackages((IPackageFragment) packageElement); + } else { + elements = new IJavaElement[] { packageElement }; + } + return SearchEngine.createJavaSearchScope(elements, IJavaSearchScope.SOURCES); case CLASS: final ICompilationUnit compilationUnit = JDTUtils.resolveCompilationUnit(params.getUri()); final IType[] types = compilationUnit.getAllTypes(); @@ -354,24 +360,27 @@ private static void searchInFolder(List resultList, SearchTestItemPara private static void searchInPackage(List resultList, SearchTestItemParams params) throws JavaModelException { - final IPackageFragment packageFragment = resolvePackage(params.getUri(), params.getFullName()); - if (packageFragment == null) { + final IJavaElement packageFragment = resolvePackage(params.getUri(), params.getFullName()); + if (packageFragment == null || !(packageFragment instanceof IPackageFragment)) { return; } - for (final ICompilationUnit unit : packageFragment.getCompilationUnits()) { + for (final ICompilationUnit unit : ((IPackageFragment) packageFragment).getCompilationUnits()) { for (final IType type : unit.getTypes()) { resultList.add(TestItemUtils.constructTestItem(type, TestLevel.CLASS)); } } } - private static IPackageFragment resolvePackage(String uriString, String fullName) throws JavaModelException { - if (TestItemUtils.DEFAULT_PACKAGE_NAME.equals(fullName)) { - final IFolder resource = (IFolder) JDTUtils.findResource(JDTUtils.toURI(uriString), + private static IJavaElement resolvePackage(String uriString, String fullName) throws JavaModelException { + final IFolder resource = (IFolder) JDTUtils.findResource(JDTUtils.toURI(uriString), ResourcesPlugin.getWorkspace().getRoot()::findContainersForLocationURI); - final IJavaElement element = JavaCore.create(resource); - if (element instanceof IPackageFragmentRoot) { + final IJavaElement element = JavaCore.create(resource); + if (element == null) { + return null; + } + if (element instanceof IPackageFragmentRoot) { + if (TestItemUtils.DEFAULT_PACKAGE_NAME.equals(fullName)) { final IPackageFragmentRoot packageRoot = (IPackageFragmentRoot) element; for (final IJavaElement child : packageRoot.getChildren()) { if (child instanceof IPackageFragment && ((IPackageFragment) child).isDefaultPackage()) { @@ -379,11 +388,9 @@ private static IPackageFragment resolvePackage(String uriString, String fullName } } } - } else { - return JDTUtils.resolvePackage(uriString); } - return null; + return element; } private static void searchInClass(List resultList, SearchTestItemParams params) diff --git a/package.json b/package.json index 3f70494d..af6dc246 100644 --- a/package.json +++ b/package.json @@ -123,6 +123,21 @@ "command": "java.test.explorer.debug", "when": "view == testExplorer && viewItem != UNTESTABLE_NODE", "group": "inline@1" + }, + { + "command": "java.test.runFromJavaProjectExplorer", + "when": "view == javaProjectExplorer && viewItem =~ /java:(type|package|packageRoot)(?=.*?\\b\\+uri\\b)(?=.*?\\b\\+test\\b)/", + "group": "8_execution@10" + }, + { + "command": "java.test.debugFromJavaProjectExplorer", + "when": "view == javaProjectExplorer && viewItem =~ /java:(type|package|packageRoot)(?=.*?\\b\\+uri\\b)(?=.*?\\b\\+test\\b)/", + "group": "8_execution@20" + }, + { + "command": "java.test.runFromJavaProjectExplorer", + "when": "view == javaProjectExplorer && viewItem =~ /java:(type|package|packageRoot)(?=.*?\\b\\+uri\\b)(?=.*?\\b\\+test\\b)/", + "group": "inline@run_0" } ], "commandPalette": [ @@ -138,6 +153,14 @@ "command": "java.test.explorer.refresh", "when": "false" }, + { + "command": "java.test.runFromJavaProjectExplorer", + "when": "false" + }, + { + "command": "java.test.debugFromJavaProjectExplorer", + "when": "false" + }, { "command": "java.test.config.migrate", "when": "java:hasDeprecatedTestConfig" @@ -201,6 +224,17 @@ "icon": "$(run-all)", "category": "Java" }, + { + "command": "java.test.runFromJavaProjectExplorer", + "title": "%contributes.commands.java.test.runFromJavaProjectExplorer%", + "icon": "$(play)", + "category": "Java" + }, + { + "command": "java.test.debugFromJavaProjectExplorer", + "title": "%contributes.commands.java.test.debugFromJavaProjectExplorer%", + "category": "Java" + }, { "command": "java.test.explorer.debugAll", "title": "%contributes.commands.java.test.explorer.debugAll.title%", diff --git a/package.nls.json b/package.nls.json index 4b015cec..399ded03 100644 --- a/package.nls.json +++ b/package.nls.json @@ -11,6 +11,8 @@ "contributes.commands.java.test.show.report.title": "Show Test Report", "contributes.commands.java.test.editor.run.title": "Run Tests", "contributes.commands.java.test.editor.debug.title": "Debug Tests", + "contributes.commands.java.test.runFromJavaProjectExplorer": "Run Tests", + "contributes.commands.java.test.debugFromJavaProjectExplorer": "Debug Tests", "contributes.commands.java.test.relaunch.title": "Relaunch the Tests", "contributes.commands.java.test.cancel.title": "Cancel Test Job", "contributes.commands.java.test.explorer.refresh.title": "Refresh", diff --git a/package.nls.zh.json b/package.nls.zh.json index c871c329..73d77ca1 100644 --- a/package.nls.zh.json +++ b/package.nls.zh.json @@ -13,6 +13,8 @@ "contributes.commands.java.test.editor.debug.title": "调试测试用例", "contributes.commands.java.test.relaunch.title": "重新执行测试任务", "contributes.commands.java.test.cancel.title": "取消测试任务", + "contributes.commands.java.test.runFromJavaProjectExplorer": "运行测试", + "contributes.commands.java.test.debugFromJavaProjectExplorer": "调试测试", "contributes.commands.java.test.explorer.refresh.title": "刷新", "contributes.commands.java.test.config.migrate.title": "迁移已弃用的 'launch.test.json' 文件", "configuration.java.test.report.showAfterExecution.description": "设定测试报告是否会在测试完成后自动显示", diff --git a/src/commands/explorerCommands.ts b/src/commands/explorerCommands.ts index 7f19a88a..e8bedb7a 100644 --- a/src/commands/explorerCommands.ts +++ b/src/commands/explorerCommands.ts @@ -9,6 +9,7 @@ import { ITestItem, TestKind, TestLevel } from '../protocols'; import { IRunnerContext } from '../runners/models'; import { runnerScheduler } from '../runners/runnerScheduler'; import { testItemModel } from '../testItemModel'; +import { executeTestsFromUri } from './runFromUri'; export async function openTextDocument(uri: Uri, range?: Range): Promise { const document: TextDocument = await workspace.openTextDocument(uri); @@ -44,8 +45,31 @@ async function executeTestsFromExplorer(isDebug: boolean, node?: ITestItem, laun runnerContext.tests = [node]; } } + return executeTests(runnerContext, launchConfiguration); +} + +export async function runTestsFromJavaProjectExplorer(node: any, isDebug: boolean): Promise { + if (node._nodeData.kind === 6 /*PrimaryType*/) { + return executeTestsFromUri(Uri.parse(node._nodeData.uri), undefined, isDebug); + } + + const runnerContext: IRunnerContext = { + scope: TestLevel.Package, + testUri: node._nodeData.uri, + fullName: node._nodeData.name, + projectName: node._project.name, + kind: TestKind.None, + isDebug, + tests: [], + // isPackage is only available when the explorer is in hierarchical mode + isHierarchicalPackage: node._nodeData.isPackage, + }; + + return executeTests(runnerContext); +} - const progressReporter: IProgressReporter | undefined = progressProvider?.createProgressReporter(isDebug ? 'Debug Test' : 'Run Test', ProgressLocation.Notification, true); +async function executeTests(runnerContext: IRunnerContext, launchConfiguration?: DebugConfiguration): Promise { + const progressReporter: IProgressReporter | undefined = progressProvider?.createProgressReporter(runnerContext.isDebug ? 'Debug Test' : 'Run Test', ProgressLocation.Notification, true); if (runnerContext.tests.length === 0) { try { await searchTestItems(runnerContext, progressReporter); @@ -58,7 +82,7 @@ async function executeTestsFromExplorer(isDebug: boolean, node?: ITestItem, laun } if (runnerContext.tests.length === 0) { - logger.info('No test items found.\n'); + window.showInformationMessage(`No tests found under: '${Uri.parse(runnerContext.testUri).fsPath}'.`); progressReporter?.done(); return; } @@ -70,7 +94,7 @@ async function searchTestItems(runnerContext: IRunnerContext, progressReporter?: return new Promise(async (resolve: () => void, reject: () => void): Promise => { const searchImpl: (token: CancellationToken) => Promise = async (token: CancellationToken) => { token.onCancellationRequested(reject); - runnerContext.tests = await testItemModel.getAllNodes(runnerContext.scope, runnerContext.fullName, runnerContext.testUri, token); + runnerContext.tests = await testItemModel.getAllNodes(runnerContext.scope, runnerContext.fullName, runnerContext.testUri, runnerContext.isHierarchicalPackage, token); return resolve(); }; diff --git a/src/constants/commands.ts b/src/constants/commands.ts index 7a3122a5..bb9d18f9 100644 --- a/src/constants/commands.ts +++ b/src/constants/commands.ts @@ -26,6 +26,8 @@ export namespace JavaTestRunnerCommands { export const DEBUG_ALL_TEST_FROM_EXPLORER: string = 'java.test.explorer.debugAll'; export const RUN_ALL_TEST_FROM_EXPLORER: string = 'java.test.explorer.runAll'; export const DEBUG_TEST_FROM_EXPLORER: string = 'java.test.explorer.debug'; + export const RUN_TEST_FROM_JAVA_PROJECT_EXPLORER: string = 'java.test.runFromJavaProjectExplorer'; + export const DEBUG_TEST_FROM_JAVA_PROJECT_EXPLORER: string = 'java.test.debugFromJavaProjectExplorer'; export const SHOW_TEST_REPORT: string = 'java.test.show.report'; export const SHOW_TEST_OUTPUT: string = 'java.test.show.output'; export const OPEN_TEST_LOG: string = 'java.test.open.log'; diff --git a/src/extension.ts b/src/extension.ts index 1164226f..f3d704c4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,7 +8,7 @@ import { commands, DebugConfiguration, Event, Extension, ExtensionContext, exten import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, instrumentOperationAsVsCodeCommand } from 'vscode-extension-telemetry-wrapper'; import { sendInfo } from 'vscode-extension-telemetry-wrapper'; import { testCodeLensController } from './codelens/TestCodeLensController'; -import { debugTestsFromExplorer, openTextDocument, runTestsFromExplorer } from './commands/explorerCommands'; +import { debugTestsFromExplorer, openTextDocument, runTestsFromExplorer, runTestsFromJavaProjectExplorer } from './commands/explorerCommands'; import { openLogFile, showOutputChannel } from './commands/logCommands'; import { runFromCodeLens } from './commands/runFromCodeLens'; import { executeTestsFromUri } from './commands/runFromUri'; @@ -118,6 +118,8 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.DEBUG_TEST_FROM_EDITOR, async (uri?: Uri, progressReporter?: IProgressReporter) => await executeTestsFromUri(uri, progressReporter, true /* isDebug */)), instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_TEST_REPORT_OPEN_STACKTRACE, async (trace: string, fullName: string) => await openStackTrace(trace, fullName)), instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_TEST_REPORT_OPEN_TEST_SOURCE_LOCATION, async (uri: string, range: string, fullName: string) => await openTestSourceLocation(uri, range, fullName)), + instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.RUN_TEST_FROM_JAVA_PROJECT_EXPLORER, async (node: any) => await runTestsFromJavaProjectExplorer(node, false /* isDebug */)), + instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.DEBUG_TEST_FROM_JAVA_PROJECT_EXPLORER, async (node: any) => await runTestsFromJavaProjectExplorer(node, true /* isDebug */)), ); setContextKeyForDeprecatedConfig(); diff --git a/src/protocols.ts b/src/protocols.ts index 2d4f7f1c..ecff8f85 100644 --- a/src/protocols.ts +++ b/src/protocols.ts @@ -23,6 +23,7 @@ export interface ISearchTestItemParams { level: TestLevel; fullName: string; uri: string; + isHierarchicalPackage?: boolean; } export enum TestLevel { diff --git a/src/runners/models.ts b/src/runners/models.ts index 7e09a2e5..b687a1d8 100644 --- a/src/runners/models.ts +++ b/src/runners/models.ts @@ -38,4 +38,5 @@ export interface IRunnerContext { isDebug: boolean; kind: TestKind; tests: ITestItem[]; + isHierarchicalPackage?: boolean; } diff --git a/src/testItemModel.ts b/src/testItemModel.ts index 6ac55deb..87199d50 100644 --- a/src/testItemModel.ts +++ b/src/testItemModel.ts @@ -23,9 +23,12 @@ class TestItemModel implements Disposable { return this.save(childrenNodes); } - public async getAllNodes(level: TestLevel, fullName: string, uri: string, token: CancellationToken): Promise { + public async getAllNodes(level: TestLevel, fullName: string, uri: string, isHierarchicalPackage: boolean | undefined, token: CancellationToken): Promise { const searchParam: ISearchTestItemParams = constructSearchTestItemParams(level, fullName, uri); - const tests: ITestItem[] = await searchTestItemsAll(searchParam, token); + const tests: ITestItem[] = await searchTestItemsAll({ + ...searchParam, + isHierarchicalPackage, + }, token); if (token.isCancellationRequested) { return []; } diff --git a/src/utils/commandUtils.ts b/src/utils/commandUtils.ts index ed7e800e..02ccc0c5 100644 --- a/src/utils/commandUtils.ts +++ b/src/utils/commandUtils.ts @@ -42,7 +42,8 @@ export async function resolveStackTraceLocation(trace: string, projectNames: str } export async function resolveJUnitLaunchArguments(uri: string, classFullName: string, testName: string, project: string, - scope: TestLevel, testKind: TestKind, start?: Position, end?: Position): Promise { + scope: TestLevel, testKind: TestKind, start?: Position, end?: Position, + isHierarchicalPackage?: boolean): Promise { const argument: IJUnitLaunchArguments | undefined = await executeJavaLanguageServerCommand( JavaTestRunnerDelegateCommands.RESOLVE_JUNIT_ARGUMENT, JSON.stringify({ uri, @@ -53,6 +54,7 @@ export async function resolveJUnitLaunchArguments(uri: string, classFullName: st testKind, start, end, + isHierarchicalPackage, })); if (!argument) { diff --git a/src/utils/launchUtils.ts b/src/utils/launchUtils.ts index e8029b33..a1c7ea8b 100644 --- a/src/utils/launchUtils.ts +++ b/src/utils/launchUtils.ts @@ -102,7 +102,7 @@ async function getJUnitLaunchArguments(runnerContext: IRunnerContext): Promise {