Fix dart/flutter stack trace parsing

This commit is contained in:
Michal Dorner 2021-02-01 16:09:01 +01:00
parent 2834fd0c5f
commit effa386fea
No known key found for this signature in database
GPG key ID: 9EEE04B48DA36786
6 changed files with 38 additions and 25 deletions

View file

@ -40,9 +40,9 @@ test\\\\main_test.dart 13:9 main.<fn>.<fn>.<fn>
"details": "package:darttest/main.dart 2:3 throwError
test\\\\main_test.dart 17:9 main.<fn>.<fn>.<fn>
",
"line": 2,
"line": 17,
"message": "Exception: Some error",
"path": "lib/main.dart",
"path": "test/main_test.dart",
},
"name": "Test 1 Test 1.1 Exception in target unit",
"result": "failed",
@ -159,7 +159,7 @@ When the exception was thrown, this was the stack:
The test description was:
pass updateShouldNotify
════════════════════════════════════════════════════════════════════════════════════════════════════",
"line": 94,
"line": 112,
"message": "Test failed. See exception logs above.
The test description was: pass updateShouldNotify",
"path": "test/value_listenable_provider_test.dart",

View file

@ -19,7 +19,7 @@ describe('dart-json tests', () => {
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
const parser = new DartJsonParser(opts)
const parser = new DartJsonParser(opts, 'dart')
const result = await parser.parse(filePath, fileContent)
expect(result).toMatchSnapshot()
@ -42,7 +42,7 @@ describe('dart-json tests', () => {
workDir: '/__w/provider/provider/'
}
const parser = new DartJsonParser(opts)
const parser = new DartJsonParser(opts, 'flutter')
const result = await parser.parse(filePath, fileContent)
expect(result).toMatchSnapshot()

28
dist/index.js generated vendored
View file

@ -140,11 +140,11 @@ async function main() {
function getParser(reporter, options) {
switch (reporter) {
case 'dart-json':
return new dart_json_parser_1.DartJsonParser(options);
return new dart_json_parser_1.DartJsonParser(options, 'dart');
case 'dotnet-trx':
return new dotnet_trx_parser_1.DotnetTrxParser(options);
case 'flutter-json':
return new dart_json_parser_1.DartJsonParser(options);
return new dart_json_parser_1.DartJsonParser(options, 'flutter');
case 'jest-junit':
return new jest_junit_parser_1.JestJunitParser(options);
default:
@ -216,8 +216,9 @@ class TestCase {
}
}
class DartJsonParser {
constructor(options) {
constructor(options, sdk) {
this.options = options;
this.sdk = sdk;
}
async parse(path, content) {
const tr = this.getTestRun(path, content);
@ -300,9 +301,12 @@ class DartJsonParser {
const { trackedFiles } = this.options;
const message = (_b = (_a = test.error) === null || _a === void 0 ? void 0 : _a.error) !== null && _b !== void 0 ? _b : '';
const stackTrace = (_d = (_c = test.error) === null || _c === void 0 ? void 0 : _c.stackTrace) !== null && _d !== void 0 ? _d : '';
const print = test.print.filter(p => p.messageType === 'print').map(p => p.message).join('\n');
const print = test.print
.filter(p => p.messageType === 'print')
.map(p => p.message)
.join('\n');
const details = [print, stackTrace].filter(str => str !== '').join('\n');
const src = this.exceptionThrowSource(stackTrace, trackedFiles);
const src = this.exceptionThrowSource(details, trackedFiles);
let path;
let line;
if (src !== undefined) {
@ -324,16 +328,16 @@ class DartJsonParser {
};
}
exceptionThrowSource(ex, trackedFiles) {
// imports from package which is tested are listed in stack traces as 'package:xyz/' which maps to relative path 'lib/'
const packageRe = /^package:[a-zA-z0-9_$]+\//;
const lines = ex.split(/\r?\n/).map(str => str.replace(packageRe, 'lib/'));
const lines = ex.split(/\r?\n/g);
// regexp to extract file path and line number from stack trace
const re = /^(.*)\s+(\d+):\d+\s+/;
const dartRe = /^(?!package:)(.*)\s+(\d+):\d+\s+/;
const flutterRe = /^#\d+\s+.*\((?!package:)(.*):(\d+):\d+\)$/;
const re = this.sdk === 'dart' ? dartRe : flutterRe;
for (const str of lines) {
const match = str.match(re);
if (match !== null) {
const [_, pathStr, lineStr] = match;
const path = file_utils_1.normalizeFilePath(pathStr);
const path = file_utils_1.normalizeFilePath(this.getRelativePath(pathStr));
if (trackedFiles.includes(path)) {
const line = parseInt(lineStr);
return { path, line };
@ -343,6 +347,10 @@ class DartJsonParser {
}
getRelativePath(path) {
const { workDir } = this.options;
const prefix = 'file://';
if (path.startsWith(prefix)) {
path = path.substr(prefix.length);
}
if (path.startsWith(workDir)) {
path = path.substr(workDir.length);
}

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View file

@ -131,11 +131,11 @@ async function main(): Promise<void> {
function getParser(reporter: string, options: ParseOptions): TestParser {
switch (reporter) {
case 'dart-json':
return new DartJsonParser(options)
return new DartJsonParser(options, 'dart')
case 'dotnet-trx':
return new DotnetTrxParser(options)
case 'flutter-json':
return new DartJsonParser(options)
return new DartJsonParser(options, 'flutter')
case 'jest-junit':
return new JestJunitParser(options)
default:

View file

@ -72,7 +72,7 @@ class TestCase {
}
export class DartJsonParser implements TestParser {
constructor(readonly options: ParseOptions) {}
constructor(readonly options: ParseOptions, readonly sdk: 'dart' | 'flutter') {}
async parse(path: string, content: string): Promise<TestRunResult> {
const tr = this.getTestRun(path, content)
@ -162,7 +162,7 @@ export class DartJsonParser implements TestParser {
.map(p => p.message)
.join('\n')
const details = [print, stackTrace].filter(str => str !== '').join('\n')
const src = this.exceptionThrowSource(stackTrace, trackedFiles)
const src = this.exceptionThrowSource(details, trackedFiles)
let path
let line
@ -186,17 +186,18 @@ export class DartJsonParser implements TestParser {
}
private exceptionThrowSource(ex: string, trackedFiles: string[]): {path: string; line: number} | undefined {
// imports from package which is tested are listed in stack traces as 'package:xyz/' which maps to relative path 'lib/'
const packageRe = /^package:[a-zA-z0-9_$]+\//
const lines = ex.split(/\r?\n/).map(str => str.replace(packageRe, 'lib/'))
const lines = ex.split(/\r?\n/g)
// regexp to extract file path and line number from stack trace
const re = /^(.*)\s+(\d+):\d+\s+/
const dartRe = /^(?!package:)(.*)\s+(\d+):\d+\s+/
const flutterRe = /^#\d+\s+.*\((?!package:)(.*):(\d+):\d+\)$/
const re = this.sdk === 'dart' ? dartRe : flutterRe
for (const str of lines) {
const match = str.match(re)
if (match !== null) {
const [_, pathStr, lineStr] = match
const path = normalizeFilePath(pathStr)
const path = normalizeFilePath(this.getRelativePath(pathStr))
if (trackedFiles.includes(path)) {
const line = parseInt(lineStr)
return {path, line}
@ -207,6 +208,10 @@ export class DartJsonParser implements TestParser {
private getRelativePath(path: string): string {
const {workDir} = this.options
const prefix = 'file://'
if (path.startsWith(prefix)) {
path = path.substr(prefix.length)
}
if (path.startsWith(workDir)) {
path = path.substr(workDir.length)
}