Skip to content

Commit ec740b4

Browse files
authored
fix: better resolve test scope for invisible project (#697)
1 parent 0749848 commit ec740b4

File tree

11 files changed

+62
-110
lines changed

11 files changed

+62
-110
lines changed

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

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
package com.microsoft.java.test.plugin.util;
1313

14-
import org.eclipse.core.resources.IContainer;
15-
import org.eclipse.core.resources.IFolder;
1614
import org.eclipse.core.resources.IProject;
1715
import org.eclipse.core.runtime.IPath;
1816
import org.eclipse.core.runtime.IProgressMonitor;
@@ -39,6 +37,8 @@
3937
public final class ProjectTestUtils {
4038

4139
private static final String TEST_SCOPE = "test";
40+
private static final String MAVEN_SCOPE_ATTRIBUTE = "maven.scope";
41+
private static final String GRADLE_SCOPE_ATTRIBUTE = "gradle_scope";
4242

4343
/**
4444
* Method to get the valid paths which contains test code
@@ -49,46 +49,25 @@ public final class ProjectTestUtils {
4949
* @throws JavaModelException
5050
*/
5151
@SuppressWarnings("unchecked")
52-
public static List<TestSourcePath> listTestSourcePaths(List<Object> arguments, IProgressMonitor monitor)
52+
public static String[] listTestSourcePaths(List<Object> arguments, IProgressMonitor monitor)
5353
throws JavaModelException {
54-
final List<TestSourcePath> testSourcePathList = new ArrayList<>();
54+
final List<String> resultList = new ArrayList<>();
5555
if (arguments == null || arguments.size() == 0) {
56-
return testSourcePathList;
56+
return new String[0];
5757
}
5858

5959
final ArrayList<String> uriArray = ((ArrayList<String>) arguments.get(0));
6060
for (final String uri : uriArray) {
6161
final Set<IJavaProject> projectSet = parseProjects(uri);
62-
for (final IJavaProject javaProject : projectSet) {
63-
final IProject project = javaProject.getProject();
64-
final String projectName = project.getName();
65-
String projectType = "General";
66-
if (ProjectUtils.isMavenProject(project)) {
67-
projectType = "Maven";
68-
}
69-
70-
if (ProjectUtils.isGradleProject(project)) {
71-
projectType = "Gradle";
72-
}
73-
74-
IContainer projectRoot = project;
75-
if (!ProjectUtils.isVisibleProject(project)) {
76-
projectType = "Workspace";
77-
final IFolder workspaceLinkFolder = project.getFolder(ProjectUtils.WORKSPACE_LINK);
78-
if (!workspaceLinkFolder.isLinked()) {
79-
continue;
80-
}
81-
82-
projectRoot = workspaceLinkFolder;
83-
}
84-
for (final IPath path : getTestPath(javaProject)) {
85-
final IPath relativePath = path.makeRelativeTo(javaProject.getPath());
86-
final IPath location = projectRoot.getRawLocation().append(relativePath);
87-
testSourcePathList.add(new TestSourcePath(location.toOSString(), projectName, projectType));
62+
for (final IJavaProject project : projectSet) {
63+
for (final IPath path : getTestPath(project)) {
64+
final IPath projectBasePath = project.getProject().getLocation();
65+
final IPath relativePath = path.makeRelativeTo(project.getPath());
66+
resultList.add(projectBasePath.append(relativePath).toOSString());
8867
}
8968
}
9069
}
91-
return testSourcePathList;
70+
return resultList.toArray(new String[resultList.size()]);
9271
}
9372

9473
public static Set<IJavaProject> parseProjects(String uriStr) {
@@ -144,6 +123,10 @@ public static boolean isTest(IClasspathEntry entry) {
144123
}
145124

146125
for (final IClasspathAttribute attribute : entry.getExtraAttributes()) {
126+
if (MAVEN_SCOPE_ATTRIBUTE.equals(attribute.getName()) ||
127+
GRADLE_SCOPE_ATTRIBUTE.equals(attribute.getName())) {
128+
return TEST_SCOPE.equals(attribute.getValue());
129+
}
147130
if (TEST_SCOPE.equals(attribute.getName())) {
148131
return "true".equalsIgnoreCase(attribute.getValue());
149132
}
@@ -167,17 +150,4 @@ public static boolean belongToProject(IPath testPath, IProject project) {
167150

168151
return false;
169152
}
170-
171-
public static class TestSourcePath {
172-
public String path;
173-
public String projectName;
174-
public String projectType;
175-
176-
TestSourcePath(String path, String projectName, String projectType) {
177-
this.path = path;
178-
this.projectName = projectName;
179-
this.projectType = projectType;
180-
}
181-
}
182-
183153
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,15 @@ public void acceptSearchMatch(SearchMatch match) throws CoreException {
275275

276276
private static boolean isInTestScope(IJavaElement element) throws JavaModelException {
277277
final IJavaProject project = element.getJavaProject();
278+
// Ignore default project
279+
if (ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getProject().getName())) {
280+
return false;
281+
}
282+
// Always return true Eclipse & invisible project
283+
if (ProjectUtils.isGeneralJavaProject(project.getProject())) {
284+
return true;
285+
}
286+
// For Maven & Gradle project, only search in test source paths
278287
for (final IPath sourcePath : ProjectUtils.listSourcePaths(project)) {
279288
if (!ProjectTestUtils.isTest(project, sourcePath)) {
280289
continue;

package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@
153153
"command": "java.test.config.migrate",
154154
"title": "%contributes.commands.java.test.config.migrate.title%",
155155
"category": "Java"
156-
},
157-
{
158-
"command": "java.test.listTestSourcePaths",
159-
"title": "%contributes.commands.java.test.listTestSourcePaths.title%",
160-
"category": "Java"
161156
}
162157
],
163158
"configuration": {

package.nls.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"contributes.commands.java.test.cancel.title": "Cancel Test Job",
1111
"contributes.commands.java.test.explorer.refresh.title": "Refresh",
1212
"contributes.commands.java.test.config.migrate.title": "Migrate Deprecated 'launch.test.json'",
13-
"contributes.commands.java.test.listTestSourcePaths.title": "List all Java test source paths",
1413
"configuration.java.test.report.position.description": "Specify where to show the test report",
1514
"configuration.java.test.log.level.description": "Specify the level of the test logs",
1615
"configuration.java.test.message.hintForDeprecatedConfig.description": "Specify whether the extension will show hint dialog when deprecated configuration file is used",

package.nls.zh.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"contributes.commands.java.test.cancel.title": "取消测试任务",
1111
"contributes.commands.java.test.explorer.refresh.title": "刷新",
1212
"contributes.commands.java.test.config.migrate.title": "迁移已弃用的 'launch.test.json' 文件",
13-
"contributes.commands.java.test.listTestSourcePaths.title": "显示测试源文件所在路径",
1413
"configuration.java.test.report.position.description": "设定测试报告的显示位置",
1514
"configuration.java.test.log.level.description": "设定日志级别",
1615
"configuration.java.test.message.hintForDeprecatedConfig.description": "设定插件是否会对使用弃用的配置文件进行提示",

src/commands/testPathCommands.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/constants/commands.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,4 @@ export namespace JavaTestRunnerCommands {
3131
export const OPEN_TEST_LOG: string = 'java.test.open.log';
3232
export const JAVA_TEST_CANCEL: string = 'java.test.cancel';
3333
export const JAVA_CONFIG_MIGRATE: string = 'java.test.config.migrate';
34-
export const LIST_TEST_SOURCE_PATHS: string = 'java.test.listTestSourcePaths';
3534
}

src/extension.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentO
99
import { testCodeLensProvider } from './codeLensProvider';
1010
import { debugTestsFromExplorer, openTextDocument, runTestsFromExplorer } from './commands/explorerCommands';
1111
import { openLogFile, showOutputChannel } from './commands/logCommands';
12-
import { listTestSourcePaths } from './commands/testPathCommands';
1312
import { JavaTestRunnerCommands } from './constants/commands';
1413
import { explorerNodeManager } from './explorer/explorerNodeManager';
1514
import { testExplorer } from './explorer/testExplorer';
@@ -40,7 +39,7 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
4039
throw new Error('Could not find Java home.');
4140
}
4241

43-
testFileWatcher.initialize(context);
42+
testFileWatcher.registerListeners();
4443
testExplorer.initialize(context);
4544
runnerExecutor.initialize(javaHome, context);
4645
testReportProvider.initialize(context);
@@ -55,6 +54,7 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
5554
testStatusBarProvider,
5655
testResultManager,
5756
testReportProvider,
57+
testFileWatcher,
5858
logger,
5959
languages.registerCodeLensProvider({ scheme: 'file', language: 'java' }, testCodeLensProvider),
6060
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.OPEN_DOCUMENT, async (uri: Uri, range?: Range) => await openTextDocument(uri, range)),
@@ -68,7 +68,6 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
6868
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.OPEN_TEST_LOG, async () => await openLogFile(storagePath)),
6969
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_TEST_CANCEL, async () => await runnerExecutor.cleanUp(true /* isCancel */)),
7070
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_CONFIG_MIGRATE, async () => await migrateTestConfig()),
71-
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.LIST_TEST_SOURCE_PATHS, async () => await listTestSourcePaths()),
7271
);
7372
}
7473

src/testFileWatcher.ts

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,59 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4-
import { Disposable, ExtensionContext, FileSystemWatcher, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
5-
import { ITestSourcePath } from './commands/testPathCommands';
4+
import { Disposable, FileSystemWatcher, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
65
import { explorerNodeManager } from './explorer/explorerNodeManager';
76
import { testExplorer } from './explorer/testExplorer';
87
import { TestTreeNode } from './explorer/TestTreeNode';
98
import { logger } from './logger/logger';
109
import { getTestSourcePaths } from './utils/commandUtils';
1110

12-
class TestFileWatcher {
11+
class TestFileWatcher implements Disposable {
1312

14-
public async initialize(context: ExtensionContext): Promise<void> {
13+
private disposables: Disposable[] = [];
14+
15+
public async registerListeners(): Promise<void> {
16+
this.dispose();
1517
if (workspace.workspaceFolders) {
1618
try {
17-
const sourcePaths: ITestSourcePath[] = await getTestSourcePaths(workspace.workspaceFolders.map((workspaceFolder: WorkspaceFolder) => workspaceFolder.uri.toString()));
19+
const sourcePaths: string[] = await getTestSourcePaths(workspace.workspaceFolders.map((workspaceFolder: WorkspaceFolder) => workspaceFolder.uri.toString()));
1820
for (const sourcePath of sourcePaths) {
19-
const pattern: RelativePattern = new RelativePattern(Uri.file(sourcePath.path).fsPath, '**/*.{[jJ][aA][vV][aA]}');
21+
const pattern: RelativePattern = new RelativePattern(Uri.file(sourcePath).fsPath, '**/*.{[jJ][aA][vV][aA]}');
2022
const watcher: FileSystemWatcher = workspace.createFileSystemWatcher(pattern, true /* ignoreCreateEvents */);
21-
this.registerWatcherListeners(watcher, context.subscriptions);
22-
context.subscriptions.push(watcher);
23+
this.registerWatcherListeners(watcher);
24+
this.disposables.push(watcher);
2325
}
2426
} catch (error) {
2527
logger.error('Failed to get the test paths', error);
2628
const watcher: FileSystemWatcher = workspace.createFileSystemWatcher('**/*.{[jJ][aA][vV][aA]}');
27-
this.registerWatcherListeners(watcher, context.subscriptions);
28-
context.subscriptions.push(watcher);
29+
this.registerWatcherListeners(watcher);
30+
this.disposables.push(watcher);
2931
}
3032
}
3133

3234
}
3335

34-
private registerWatcherListeners(watcher: FileSystemWatcher, disposables: Disposable[]): void {
35-
watcher.onDidChange((uri: Uri) => {
36-
const node: TestTreeNode | undefined = explorerNodeManager.getNode(uri.fsPath);
37-
testExplorer.refresh(node);
38-
}, null, disposables);
36+
public dispose(): void {
37+
for (const disposable of this.disposables) {
38+
if (disposable) {
39+
disposable.dispose();
40+
}
41+
}
42+
this.disposables = [];
43+
}
44+
45+
private registerWatcherListeners(watcher: FileSystemWatcher): void {
46+
this.disposables.push(
47+
watcher.onDidChange((uri: Uri) => {
48+
const node: TestTreeNode | undefined = explorerNodeManager.getNode(uri.fsPath);
49+
testExplorer.refresh(node);
50+
}),
3951

40-
watcher.onDidDelete((uri: Uri) => {
41-
explorerNodeManager.removeNode(uri.fsPath);
42-
testExplorer.refresh();
43-
}, null, disposables);
52+
watcher.onDidDelete((uri: Uri) => {
53+
explorerNodeManager.removeNode(uri.fsPath);
54+
testExplorer.refresh();
55+
}),
56+
);
4457
}
4558
}
4659

src/testResultManager.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import * as fse from 'fs-extra';
55
import * as path from 'path';
66
import { Disposable, Uri, WorkspaceFolder } from 'vscode';
7-
import { ITestSourcePath } from './commands/testPathCommands';
87
import { ITestResult, ITestResultDetails } from './runners/models';
98
import { getTestSourcePaths } from './utils/commandUtils';
109

@@ -49,9 +48,9 @@ class TestResultManager implements Disposable {
4948
private async resolveFsPathFromFullName(workspaceFolder: WorkspaceFolder, fullName: string): Promise<string | undefined> {
5049
const classFullyQualifiedName: string = fullName.slice(0, fullName.indexOf('$') > -1 ? fullName.indexOf('$') : fullName.indexOf('#'));
5150
const relativePath: string = path.join(...classFullyQualifiedName.split('.'));
52-
const classPathEntries: ITestSourcePath[] = await getTestSourcePaths([workspaceFolder.uri.toString()]);
51+
const classPathEntries: string[] = await getTestSourcePaths([workspaceFolder.uri.toString()]);
5352
for (const classPathEntry of classPathEntries) {
54-
const possiblePath: string = `${path.join(Uri.file(classPathEntry.path).fsPath, relativePath)}.java`;
53+
const possiblePath: string = `${path.join(Uri.file(classPathEntry).fsPath, relativePath)}.java`;
5554
if (await fse.pathExists(possiblePath)) {
5655
return Uri.file(possiblePath).toString();
5756
}

0 commit comments

Comments
 (0)