diff --git a/src/runners/baseRunner/RunnerResultAnalyzer.ts b/src/runners/baseRunner/RunnerResultAnalyzer.ts index 7c7cb4e..0497275 100644 --- a/src/runners/baseRunner/RunnerResultAnalyzer.ts +++ b/src/runners/baseRunner/RunnerResultAnalyzer.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import * as path from 'path'; -import { Location, MarkdownString, Range, TestItem } from 'vscode'; +import { Location, MarkdownString, TestItem } from 'vscode'; import { IRunTestContext } from '../../types'; +import { processStackTraceLine } from '../utils'; export abstract class RunnerResultAnalyzer { constructor(protected testContext: IRunTestContext) { } @@ -21,46 +21,14 @@ export abstract class RunnerResultAnalyzer { } protected processStackTrace(data: string, traces: MarkdownString, currentItem: TestItem | undefined, projectName: string): void { - const traceRegExp: RegExp = /(\s?at\s+)([\w$\\.]+\/)?((?:[\w$]+\.)+[<\w$>]+)\((.*)\)/; - const traceResults: RegExpExecArray | null = traceRegExp.exec(data); - if (traceResults) { - const fullyQualifiedName: string = traceResults[3]; - if (this.isExcluded(fullyQualifiedName)) { - return; - } - - const location: string = traceResults[4]; - let sourceName: string | undefined; - let lineNumLiteral: string | undefined; - const locationResult: RegExpExecArray | null = /([\w-$]+\.java):(\d+)/.exec(location); - if (locationResult) { - sourceName = locationResult[1]; - lineNumLiteral = locationResult[2]; - } - - if (!sourceName || !lineNumLiteral) { - traces.appendText(data); - } else { - const atLiteral: string = traceResults[1]; - const optionalModuleName: string = traceResults[2] || ''; - traces.appendText(atLiteral); - traces.appendMarkdown(`${optionalModuleName + fullyQualifiedName}([${sourceName}:${lineNumLiteral}](command:_java.test.openStackTrace?${encodeURIComponent(JSON.stringify([data, projectName]))}))`); - if (currentItem && path.basename(currentItem.uri?.fsPath || '') === sourceName) { - const lineNum: number = parseInt(lineNumLiteral, 10); - if (currentItem.uri) { - if (!currentItem.range || (currentItem.range.start.line + 1 < lineNum && currentItem.range.end.line + 1 > lineNum)) { - this.testMessageLocation = new Location(currentItem.uri, new Range(lineNum - 1, 0, lineNum, 0)); - } else { - this.testMessageLocation = new Location(currentItem.uri, new Range(currentItem.range.start.line, 0, currentItem.range.start.line, 0)); - } - } - } - } - } else { - // '<' & '>' will be escaped when displaying the test message, so replacing them to '[' & ']'. - traces.appendText(data.replace(//g, ']')); + if (this.isExcluded(data)) { + return; + } + + const location: Location | undefined = processStackTraceLine(data, traces, currentItem, projectName); + if (location) { + this.testMessageLocation = location; } - traces.appendMarkdown('
'); } private isExcluded(stacktrace: string): boolean { diff --git a/src/runners/utils.ts b/src/runners/utils.ts index 80c1d36..dc0882e 100644 --- a/src/runners/utils.ts +++ b/src/runners/utils.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import { Location, TestItem, TestMessage, TestRun, Uri } from 'vscode'; +import { Location, MarkdownString, Range, TestItem, TestMessage, TestRun, Uri } from 'vscode'; import { JavaTestRunnerCommands } from '../constants'; import { asRange } from '../controller/utils'; import { executeJavaLanguageServerCommand } from '../utils/commandUtils'; +import * as path from 'path'; export async function findTestLocation(fullName: string): Promise { const location: any | undefined = await executeJavaLanguageServerCommand( @@ -52,3 +53,51 @@ export enum TestResultState { // Test run failed for some other reason (compilation error, timeout, etc) Errored = 6, } + +/** + * Append the line of stack trace to the traces. + * @param lineOfMessage line of stack trace. + * @param traces stack trace in markdown string. + * @param currentItem current test item. + * @param projectName project name. + */ +export function processStackTraceLine(lineOfMessage: string, traces: MarkdownString, currentItem: TestItem | undefined, projectName: string): Location | undefined { + let testMessageLocation: Location | undefined; + const traceResults: RegExpExecArray | null = /(\s?at\s+)([\w$\\.]+\/)?((?:[\w$]+\.)+[<\w$>]+)\((.*)\)/.exec(lineOfMessage); + if (traceResults) { + const fullyQualifiedName: string = traceResults[3]; + const location: string = traceResults[4]; + let sourceName: string | undefined; + let lineNumLiteral: string | undefined; + const locationResult: RegExpExecArray | null = /([\w-$]+\.java):(\d+)/.exec(location); + if (locationResult) { + sourceName = locationResult[1]; + lineNumLiteral = locationResult[2]; + } + + if (!sourceName || !lineNumLiteral) { + traces.appendText(lineOfMessage); + } else { + const atLiteral: string = traceResults[1]; + const optionalModuleName: string = traceResults[2] || ''; + traces.appendText(atLiteral); + traces.appendMarkdown(`${optionalModuleName + fullyQualifiedName}([${sourceName}:${lineNumLiteral}](command:_java.test.openStackTrace?${encodeURIComponent(JSON.stringify([lineOfMessage, projectName]))}))`); + if (currentItem && path.basename(currentItem.uri?.fsPath || '') === sourceName) { + const lineNum: number = parseInt(lineNumLiteral, 10); + if (currentItem.uri) { + if (!currentItem.range || (currentItem.range.start.line + 1 < lineNum && currentItem.range.end.line + 1 > lineNum)) { + testMessageLocation = new Location(currentItem.uri, new Range(lineNum - 1, 0, lineNum, 0)); + } else { + testMessageLocation = new Location(currentItem.uri, new Range(currentItem.range.start.line, 0, currentItem.range.start.line, 0)); + } + } + } + } + } else { + // '<' & '>' will be escaped when displaying the test message, so replacing them to '[' & ']'. + traces.appendText(lineOfMessage.replace(//g, ']')); + } + traces.appendMarkdown('
'); + + return testMessageLocation +}