From 40b5f476c73cbe1015f9f429947a694ed8b9efe4 Mon Sep 17 00:00:00 2001 From: Michal Dorner Date: Sun, 24 Jan 2021 21:05:34 +0100 Subject: [PATCH] remove auto conversion of XML attributes based on value --- src/parsers/dotnet-trx/dotnet-trx-parser.ts | 11 ++++----- src/parsers/dotnet-trx/dotnet-trx-types.ts | 10 ++++---- src/parsers/jest-junit/jest-junit-parser.ts | 11 +++------ src/parsers/jest-junit/jest-junit-types.ts | 20 +++++++-------- src/utils/parse-utils.ts | 20 +++++++++++++++ src/utils/xml-utils.ts | 27 --------------------- 6 files changed, 44 insertions(+), 55 deletions(-) create mode 100644 src/utils/parse-utils.ts delete mode 100644 src/utils/xml-utils.ts diff --git a/src/parsers/dotnet-trx/dotnet-trx-parser.ts b/src/parsers/dotnet-trx/dotnet-trx-parser.ts index 842ef6c..c26eff1 100644 --- a/src/parsers/dotnet-trx/dotnet-trx-parser.ts +++ b/src/parsers/dotnet-trx/dotnet-trx-parser.ts @@ -5,8 +5,8 @@ import {Annotation, FileContent, ParseOptions, TestResult} from '../parser-types import {parseStringPromise} from 'xml2js' import {normalizeFilePath} from '../../utils/file-utils' -import {parseAttribute} from '../../utils/xml-utils' import {Icon, fixEol} from '../../utils/markdown-utils' +import {parseIsoDate, parseNetDuration} from '../../utils/parse-utils' import { TestExecutionResult, @@ -70,9 +70,7 @@ export async function parseDotnetTrx(files: FileContent[], options: ParseOptions async function getTrxReport(file: FileContent): Promise { core.info(`Parsing content of '${file.path}'`) try { - return (await parseStringPromise(file.content, { - attrValueProcessors: [parseAttribute] - })) as TrxReport + return (await parseStringPromise(file.content)) as TrxReport } catch (e) { throw new Error(`Invalid XML at ${file.path}\n\n${e}`) } @@ -80,7 +78,7 @@ async function getTrxReport(file: FileContent): Promise { function getTestRunResult(path: string, trx: TrxReport, testClasses: TestClass[]): TestRunResult { const times = trx.TestRun.Times[0].$ - const totalTime = times.finish.getTime() - times.start.getTime() + const totalTime = parseIsoDate(times.finish).getTime() - parseIsoDate(times.start).getTime() const suites = testClasses.map(tc => { const tests = tc.tests.map(t => new TestCaseResult(t.name, t.result, t.duration)) @@ -113,7 +111,8 @@ function getTestClasses(trx: TrxReport): TestClass[] { } const output = r.unitTestResult.Output const error = output?.length > 0 && output[0].ErrorInfo?.length > 0 ? output[0].ErrorInfo[0] : undefined - const test = new Test(r.testMethod.$.name, r.unitTestResult.$.outcome, r.unitTestResult.$.duration, error) + const duration = parseNetDuration(r.unitTestResult.$.duration) + const test = new Test(r.testMethod.$.name, r.unitTestResult.$.outcome, duration, error) tc.tests.push(test) } diff --git a/src/parsers/dotnet-trx/dotnet-trx-types.ts b/src/parsers/dotnet-trx/dotnet-trx-types.ts index c43f301..4602940 100644 --- a/src/parsers/dotnet-trx/dotnet-trx-types.ts +++ b/src/parsers/dotnet-trx/dotnet-trx-types.ts @@ -10,10 +10,10 @@ export interface TestRun { export interface Times { $: { - creation: Date - queuing: Date - start: Date - finish: Date + creation: string + queuing: string + start: string + finish: string } } @@ -43,7 +43,7 @@ export interface UnitTestResult { $: { testId: string testName: string - duration: number + duration: string outcome: Outcome } Output: Output[] diff --git a/src/parsers/jest-junit/jest-junit-parser.ts b/src/parsers/jest-junit/jest-junit-parser.ts index 5d66e75..e314563 100644 --- a/src/parsers/jest-junit/jest-junit-parser.ts +++ b/src/parsers/jest-junit/jest-junit-parser.ts @@ -5,7 +5,6 @@ import {parseStringPromise} from 'xml2js' import {JunitReport, TestCase, TestSuite} from './jest-junit-types' import {fixEol, Icon} from '../../utils/markdown-utils' import {normalizeFilePath} from '../../utils/file-utils' -import {parseAttribute} from '../../utils/xml-utils' import { TestExecutionResult, @@ -43,9 +42,7 @@ export async function parseJestJunit(files: FileContent[], options: ParseOptions async function getJunitReport(file: FileContent): Promise { core.info(`Parsing content of '${file.path}'`) try { - return (await parseStringPromise(file.content, { - attrValueProcessors: [parseAttribute] - })) as JunitReport + return (await parseStringPromise(file.content)) as JunitReport } catch (e) { throw new Error(`Invalid XML at ${file.path}\n\n${e}`) } @@ -54,12 +51,12 @@ async function getJunitReport(file: FileContent): Promise { function getTestRunResult(path: string, junit: JunitReport): TestRunResult { const suites = junit.testsuites.testsuite.map(ts => { const name = ts.$.name.trim() - const time = ts.$.time * 1000 + const time = parseFloat(ts.$.time) * 1000 const sr = new TestSuiteResult(name, getGroups(ts), time) return sr }) - const time = junit.testsuites.$.time * 1000 + const time = parseFloat(junit.testsuites.$.time) * 1000 return new TestRunResult(path, suites, time) } @@ -78,7 +75,7 @@ function getGroups(suite: TestSuite): TestGroupResult[] { const tests = grp.tests.map(tc => { const name = tc.$.name.trim() const result = getTestCaseResult(tc) - const time = tc.$.time * 1000 + const time = parseFloat(tc.$.time) * 1000 return new TestCaseResult(name, result, time) }) return new TestGroupResult(grp.describe, tests) diff --git a/src/parsers/jest-junit/jest-junit-types.ts b/src/parsers/jest-junit/jest-junit-types.ts index b5aa211..a727870 100644 --- a/src/parsers/jest-junit/jest-junit-types.ts +++ b/src/parsers/jest-junit/jest-junit-types.ts @@ -5,10 +5,10 @@ export interface JunitReport { export interface TestSuites { $: { name: string - tests: number - failures: number // assertion failed - errors: number // unhandled exception during test execution - time: number + tests: string + failures: string // assertion failed + errors: string // unhandled exception during test execution + time: string } testsuite: TestSuite[] } @@ -16,11 +16,11 @@ export interface TestSuites { export interface TestSuite { $: { name: string - tests: number - errors: number - failures: number - skipped: number - time: number + tests: string + errors: string + failures: string + skipped: string + time: string timestamp?: Date } testcase: TestCase[] @@ -31,7 +31,7 @@ export interface TestCase { classname: string file?: string name: string - time: number + time: string } failure?: string[] skipped?: string[] diff --git a/src/utils/parse-utils.ts b/src/utils/parse-utils.ts new file mode 100644 index 0000000..ff39a44 --- /dev/null +++ b/src/utils/parse-utils.ts @@ -0,0 +1,20 @@ +export function parseNetDuration(str: string): number { + // matches dotnet duration: 00:00:00.0010000 + const durationRe = /^(\d\d):(\d\d):(\d\d\.\d+)$/ + const durationMatch = str.match(durationRe) + if (durationMatch === null) { + throw new Error(`Invalid format: "${str}" is not NET duration`) + } + + const [_, hourStr, minStr, secStr] = durationMatch + return (parseInt(hourStr) * 3600 + parseInt(minStr) * 60 + parseFloat(secStr)) * 1000 +} + +export function parseIsoDate(str: string): Date { + const isoDateRe = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)$/ + if (str === undefined || !isoDateRe.test(str)) { + throw new Error(`Invalid format: "${str}" is not ISO date`) + } + + return new Date(str) +} diff --git a/src/utils/xml-utils.ts b/src/utils/xml-utils.ts deleted file mode 100644 index 319d26b..0000000 --- a/src/utils/xml-utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -const isoDateRe = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)$/ - -// matches dotnet duration: 00:00:00.0010000 -const durationRe = /^(\d\d):(\d\d):(\d\d\.\d+)$/ - -export function parseAttribute(str: string | undefined): string | Date | number | undefined { - if (str === '' || str === undefined) { - return str - } - - if (isoDateRe.test(str)) { - return new Date(str) - } - - const durationMatch = str.match(durationRe) - if (durationMatch !== null) { - const [_, hourStr, minStr, secStr] = durationMatch - return (parseInt(hourStr) * 3600 + parseInt(minStr) * 60 + parseFloat(secStr)) * 1000 - } - - const num = parseFloat(str) - if (isNaN(num)) { - return str - } - - return num -}