Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

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

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
Expand All @@ -39,6 +37,8 @@
public final class ProjectTestUtils {

private static final String TEST_SCOPE = "test";
private static final String MAVEN_SCOPE_ATTRIBUTE = "maven.scope";
private static final String GRADLE_SCOPE_ATTRIBUTE = "gradle_scope";

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

final ArrayList<String> uriArray = ((ArrayList<String>) arguments.get(0));
for (final String uri : uriArray) {
final Set<IJavaProject> projectSet = parseProjects(uri);
for (final IJavaProject javaProject : projectSet) {
final IProject project = javaProject.getProject();
final String projectName = project.getName();
String projectType = "General";
if (ProjectUtils.isMavenProject(project)) {
projectType = "Maven";
}

if (ProjectUtils.isGradleProject(project)) {
projectType = "Gradle";
}

IContainer projectRoot = project;
if (!ProjectUtils.isVisibleProject(project)) {
projectType = "Workspace";
final IFolder workspaceLinkFolder = project.getFolder(ProjectUtils.WORKSPACE_LINK);
if (!workspaceLinkFolder.isLinked()) {
continue;
}

projectRoot = workspaceLinkFolder;
}
for (final IPath path : getTestPath(javaProject)) {
final IPath relativePath = path.makeRelativeTo(javaProject.getPath());
final IPath location = projectRoot.getRawLocation().append(relativePath);
testSourcePathList.add(new TestSourcePath(location.toOSString(), projectName, projectType));
for (final IJavaProject project : projectSet) {
for (final IPath path : getTestPath(project)) {
final IPath projectBasePath = project.getProject().getLocation();
final IPath relativePath = path.makeRelativeTo(project.getPath());
resultList.add(projectBasePath.append(relativePath).toOSString());
}
}
}
return testSourcePathList;
return resultList.toArray(new String[resultList.size()]);
}

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

for (final IClasspathAttribute attribute : entry.getExtraAttributes()) {
if (MAVEN_SCOPE_ATTRIBUTE.equals(attribute.getName()) ||
GRADLE_SCOPE_ATTRIBUTE.equals(attribute.getName())) {
return TEST_SCOPE.equals(attribute.getValue());
}
if (TEST_SCOPE.equals(attribute.getName())) {
return "true".equalsIgnoreCase(attribute.getValue());
}
Expand All @@ -167,17 +150,4 @@ public static boolean belongToProject(IPath testPath, IProject project) {

return false;
}

public static class TestSourcePath {
public String path;
public String projectName;
public String projectType;

TestSourcePath(String path, String projectName, String projectType) {
this.path = path;
this.projectName = projectName;
this.projectType = projectType;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
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;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.lsp4j.Location;

import java.net.URISyntaxException;
Expand Down Expand Up @@ -273,6 +274,15 @@ public void acceptSearchMatch(SearchMatch match) throws CoreException {

private static boolean isInTestScope(IJavaElement element) throws JavaModelException {
final IJavaProject project = element.getJavaProject();
// Ignore default project
if (ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getProject().getName())) {
return false;
}
// Always return true Eclipse & invisible project
if (ProjectUtils.isGeneralJavaProject(project.getProject())) {
return true;
}
// For Maven & Gradle project, only search in test source paths
for (final IPath sourcePath : ProjectUtils.listSourcePaths(project)) {
if (!ProjectTestUtils.isTest(project, sourcePath)) {
continue;
Expand Down
5 changes: 0 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,6 @@
"command": "java.test.config.migrate",
"title": "%contributes.commands.java.test.config.migrate.title%",
"category": "Java"
},
{
"command": "java.test.listTestSourcePaths",
"title": "%contributes.commands.java.test.listTestSourcePaths.title%",
"category": "Java"
}
],
"configuration": {
Expand Down
1 change: 0 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"contributes.commands.java.test.cancel.title": "Cancel Test Job",
"contributes.commands.java.test.explorer.refresh.title": "Refresh",
"contributes.commands.java.test.config.migrate.title": "Migrate Deprecated 'launch.test.json'",
"contributes.commands.java.test.listTestSourcePaths.title": "List all Java test source paths",
"configuration.java.test.report.position.description": "Specify where to show the test report",
"configuration.java.test.log.level.description": "Specify the level of the test logs",
"configuration.java.test.message.hintForDeprecatedConfig.description": "Specify whether the extension will show hint dialog when deprecated configuration file is used",
Expand Down
1 change: 0 additions & 1 deletion package.nls.zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"contributes.commands.java.test.cancel.title": "取消测试任务",
"contributes.commands.java.test.explorer.refresh.title": "刷新",
"contributes.commands.java.test.config.migrate.title": "迁移已弃用的 'launch.test.json' 文件",
"contributes.commands.java.test.listTestSourcePaths.title": "显示测试源文件所在路径",
"configuration.java.test.report.position.description": "设定测试报告的显示位置",
"configuration.java.test.log.level.description": "设定日志级别",
"configuration.java.test.message.hintForDeprecatedConfig.description": "设定插件是否会对使用弃用的配置文件进行提示",
Expand Down
29 changes: 0 additions & 29 deletions src/commands/testPathCommands.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/constants/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ export namespace JavaTestRunnerCommands {
export const OPEN_TEST_LOG: string = 'java.test.open.log';
export const JAVA_TEST_CANCEL: string = 'java.test.cancel';
export const JAVA_CONFIG_MIGRATE: string = 'java.test.config.migrate';
export const LIST_TEST_SOURCE_PATHS: string = 'java.test.listTestSourcePaths';
}
5 changes: 2 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentO
import { testCodeLensProvider } from './codeLensProvider';
import { debugTestsFromExplorer, openTextDocument, runTestsFromExplorer } from './commands/explorerCommands';
import { openLogFile, showOutputChannel } from './commands/logCommands';
import { listTestSourcePaths } from './commands/testPathCommands';
import { JavaTestRunnerCommands } from './constants/commands';
import { explorerNodeManager } from './explorer/explorerNodeManager';
import { testExplorer } from './explorer/testExplorer';
Expand Down Expand Up @@ -40,7 +39,7 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
throw new Error('Could not find Java home.');
}

testFileWatcher.initialize(context);
testFileWatcher.registerListeners();
testExplorer.initialize(context);
runnerExecutor.initialize(javaHome, context);
testReportProvider.initialize(context);
Expand All @@ -55,6 +54,7 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
testStatusBarProvider,
testResultManager,
testReportProvider,
testFileWatcher,
logger,
languages.registerCodeLensProvider({ scheme: 'file', language: 'java' }, testCodeLensProvider),
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.OPEN_DOCUMENT, async (uri: Uri, range?: Range) => await openTextDocument(uri, range)),
Expand All @@ -68,7 +68,6 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.OPEN_TEST_LOG, async () => await openLogFile(storagePath)),
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_TEST_CANCEL, async () => await runnerExecutor.cleanUp(true /* isCancel */)),
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.JAVA_CONFIG_MIGRATE, async () => await migrateTestConfig()),
instrumentOperationAsVsCodeCommand(JavaTestRunnerCommands.LIST_TEST_SOURCE_PATHS, async () => await listTestSourcePaths()),
);
}

Expand Down
51 changes: 32 additions & 19 deletions src/testFileWatcher.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { Disposable, ExtensionContext, FileSystemWatcher, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
import { ITestSourcePath } from './commands/testPathCommands';
import { Disposable, FileSystemWatcher, RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';
import { explorerNodeManager } from './explorer/explorerNodeManager';
import { testExplorer } from './explorer/testExplorer';
import { TestTreeNode } from './explorer/TestTreeNode';
import { logger } from './logger/logger';
import { getTestSourcePaths } from './utils/commandUtils';

class TestFileWatcher {
class TestFileWatcher implements Disposable {

public async initialize(context: ExtensionContext): Promise<void> {
private disposables: Disposable[] = [];

public async registerListeners(): Promise<void> {
this.dispose();
if (workspace.workspaceFolders) {
try {
const sourcePaths: ITestSourcePath[] = await getTestSourcePaths(workspace.workspaceFolders.map((workspaceFolder: WorkspaceFolder) => workspaceFolder.uri.toString()));
const sourcePaths: string[] = await getTestSourcePaths(workspace.workspaceFolders.map((workspaceFolder: WorkspaceFolder) => workspaceFolder.uri.toString()));
for (const sourcePath of sourcePaths) {
const pattern: RelativePattern = new RelativePattern(Uri.file(sourcePath.path).fsPath, '**/*.{[jJ][aA][vV][aA]}');
const pattern: RelativePattern = new RelativePattern(Uri.file(sourcePath).fsPath, '**/*.{[jJ][aA][vV][aA]}');
const watcher: FileSystemWatcher = workspace.createFileSystemWatcher(pattern, true /* ignoreCreateEvents */);
this.registerWatcherListeners(watcher, context.subscriptions);
context.subscriptions.push(watcher);
this.registerWatcherListeners(watcher);
this.disposables.push(watcher);
}
} catch (error) {
logger.error('Failed to get the test paths', error);
const watcher: FileSystemWatcher = workspace.createFileSystemWatcher('**/*.{[jJ][aA][vV][aA]}');
this.registerWatcherListeners(watcher, context.subscriptions);
context.subscriptions.push(watcher);
this.registerWatcherListeners(watcher);
this.disposables.push(watcher);
}
}

}

private registerWatcherListeners(watcher: FileSystemWatcher, disposables: Disposable[]): void {
watcher.onDidChange((uri: Uri) => {
const node: TestTreeNode | undefined = explorerNodeManager.getNode(uri.fsPath);
testExplorer.refresh(node);
}, null, disposables);
public dispose(): void {
for (const disposable of this.disposables) {
if (disposable) {
disposable.dispose();
}
}
this.disposables = [];
}

private registerWatcherListeners(watcher: FileSystemWatcher): void {
this.disposables.push(
watcher.onDidChange((uri: Uri) => {
const node: TestTreeNode | undefined = explorerNodeManager.getNode(uri.fsPath);
testExplorer.refresh(node);
}),

watcher.onDidDelete((uri: Uri) => {
explorerNodeManager.removeNode(uri.fsPath);
testExplorer.refresh();
}, null, disposables);
watcher.onDidDelete((uri: Uri) => {
explorerNodeManager.removeNode(uri.fsPath);
testExplorer.refresh();
}),
);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/testResultManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import * as fse from 'fs-extra';
import * as path from 'path';
import { Disposable, Uri, WorkspaceFolder } from 'vscode';
import { ITestSourcePath } from './commands/testPathCommands';
import { ITestResult, ITestResultDetails } from './runners/models';
import { getTestSourcePaths } from './utils/commandUtils';

Expand Down Expand Up @@ -49,9 +48,9 @@ class TestResultManager implements Disposable {
private async resolveFsPathFromFullName(workspaceFolder: WorkspaceFolder, fullName: string): Promise<string | undefined> {
const classFullyQualifiedName: string = fullName.slice(0, fullName.indexOf('$') > -1 ? fullName.indexOf('$') : fullName.indexOf('#'));
const relativePath: string = path.join(...classFullyQualifiedName.split('.'));
const classPathEntries: ITestSourcePath[] = await getTestSourcePaths([workspaceFolder.uri.toString()]);
const classPathEntries: string[] = await getTestSourcePaths([workspaceFolder.uri.toString()]);
for (const classPathEntry of classPathEntries) {
const possiblePath: string = `${path.join(Uri.file(classPathEntry.path).fsPath, relativePath)}.java`;
const possiblePath: string = `${path.join(Uri.file(classPathEntry).fsPath, relativePath)}.java`;
if (await fse.pathExists(possiblePath)) {
return Uri.file(possiblePath).toString();
}
Expand Down
5 changes: 2 additions & 3 deletions src/utils/commandUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

import * as _ from 'lodash';
import { commands } from 'vscode';
import { ITestSourcePath } from '../commands/testPathCommands';
import { JavaLanguageServerCommands, JavaTestRunnerDelegateCommands } from '../constants/commands';
import { logger } from '../logger/logger';
import { ILocation, ISearchTestItemParams, ITestItem } from '../protocols';

export async function getTestSourcePaths(uri: string[]): Promise<ITestSourcePath[]> {
return await executeJavaLanguageServerCommand<ITestSourcePath[]>(
export async function getTestSourcePaths(uri: string[]): Promise<string[]> {
return await executeJavaLanguageServerCommand<string[]>(
JavaTestRunnerDelegateCommands.GET_TEST_SOURCE_PATH, uri) || [];
}

Expand Down