Skip to content

Commit

Permalink
Merge pull request #430 from mikepenz/feature/429
Browse files Browse the repository at this point in the history
Add support for line numbers provided via xml report (xunit)
  • Loading branch information
mikepenz authored Nov 29, 2021
2 parents 0be2b1f + 041dbc5 commit 7635c7c
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 18 deletions.
29 changes: 28 additions & 1 deletion __tests__/testParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ jest.setTimeout(10000)

describe('resolveFileAndLine', () => {
it('should default to 1 if no line found', async () => {
const { fileName, line } = await resolveFileAndLine(null, 'someClassName', 'not a stacktrace');
const { fileName, line } = await resolveFileAndLine(null, null, 'someClassName', 'not a stacktrace');
expect(fileName).toBe('someClassName');
expect(line).toBe(1);
});

it('should parse correctly fileName and line for a Java file', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'action.surefire.report.email.EmailAddressTest',
`
action.surefire.report.email.InvalidEmailAddressException: Invalid email address 'user@ñandú.com.ar'
Expand All @@ -34,6 +35,7 @@ action.surefire.report.email.InvalidEmailAddressException: Invalid email address
it('should parse correctly fileName and line for a Kotlin file', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'action.surefire.report.calc.CalcUtilsTest',
`
java.lang.AssertionError: unexpected exception type thrown; expected:<java.lang.IllegalStateException> but was:<java.lang.IllegalArgumentException>
Expand All @@ -51,6 +53,7 @@ Caused by: java.lang.IllegalArgumentException: Amount must have max 2 non-zero d
it('should parse correctly fileName and line for extended stacktrace', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'action.surefire.report.calc.StringUtilsTest',
`
java.lang.AssertionError:
Expand All @@ -74,6 +77,7 @@ Stacktrace was: java.lang.IllegalArgumentException: Input='' didn't match condit
it('should parse correctly fileName and line for pytest', async () => {
const { fileName, line } = await resolveFileAndLine(
'test.py',
null,
'anything',
`
def
Expand All @@ -92,6 +96,7 @@ test.py:14: AttributeError
it('should parse correctly line number for rust tests', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'project',
`thread &#x27;project::admission_webhook_tests::it_should_be_possible_to_update_projects&#x27; panicked at &#x27;boom&#x27;, tests/project/admission_webhook_tests.rs:48:38
note: run with &#x60;RUST_BACKTRACE&#x3D;1&#x60; environment variable to display a backtrace
Expand All @@ -105,6 +110,7 @@ note: run with &#x60;RUST_BACKTRACE&#x3D;1&#x60; environment variable to display
it('should parse correctly line number for rust tests 2', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'project::manifest_secrets',
`thread 'project::manifest_secrets::it_should_skip_annotated_manifests' panicked at 'assertion failed: \`(left == right)\`\\n" +
' left: \`0\`,\\n' +
Expand Down Expand Up @@ -283,6 +289,7 @@ describe('parseFile', () => {
it('should parse correctly fileName and line for a Java file with invalid chars', async () => {
const { fileName, line } = await resolveFileAndLine(
null,
null,
'action.surefire.report.email.EmailAddressTest++',
`
action.surefire.report.email.InvalidEmailAddressException: Invalid email address 'user@ñandú.com.ar'
Expand Down Expand Up @@ -435,4 +442,24 @@ action.surefire.report.email.InvalidEmailAddressException: Invalid email address
"raw_details": ""
}]);
});

it('should parse xunit results', async () => {
const { count, skipped, annotations } = await parseFile('test_results/xunit/report.xml');

expect(count).toBe(4);
expect(skipped).toBe(0);
expect(annotations).toStrictEqual([
{
path: "main.c",
start_line: 38,
end_line: 38,
start_column: 0,
end_column: 0,
annotation_level: "failure",
title: "main.c.test_my_sum_fail",
message: "Expected 2 Was 0",
raw_details: "",
}
]);
});
});
29 changes: 22 additions & 7 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "action-junit-report",
"version": "0.0.0",
"version": "2.0.0",
"private": true,
"description": "junit report action",
"main": "lib/main.js",
Expand Down
28 changes: 22 additions & 6 deletions src/testParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,29 @@ export interface Position {
*/
export async function resolveFileAndLine(
file: string | null,
line: string | null,
className: string,
output: String
): Promise<Position> {
let fileName = file ? file : className.split('.').slice(-1)[0]
const lineNumber = safeParseInt(line)
try {
if (fileName && lineNumber) {
return {fileName, line: lineNumber}
}

const escapedFileName = fileName
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace('::', '/') // Rust test output contains colons between package names - See: https://github.com/mikepenz/action-junit-report/pull/359

const matches = output.match(
new RegExp(` [^ ]*${escapedFileName}.*?:\\d+`, 'g')
)
if (!matches) return {fileName, line: 1}
if (!matches) return {fileName, line: lineNumber || 1}

const [lastItem] = matches.slice(-1)

const lineTokens = lastItem.split(':')
const line = lineTokens.pop() || '0'
line = lineTokens.pop() || '0'

// check, if the error message is from a rust file -- this way we have the chance to find
// out the involved test file
Expand All @@ -66,15 +71,25 @@ export async function resolveFileAndLine(

core.debug(`Resolved file ${fileName} and line ${line}`)

return {fileName, line: parseInt(line)}
return {fileName, line: safeParseInt(line) || -1}
} catch (error) {
core.warning(
`⚠️ Failed to resolve file and line for ${file} and ${className}`
`⚠️ Failed to resolve file (${file}) and/or line (${line}) for ${className}`
)
return {fileName, line: 1}
return {fileName, line: safeParseInt(line) || -1}
}
}

/**
* Parse the provided string line number, and return its value, or null if it is not available or NaN.
*/
function safeParseInt(line: string | null): number | null {
if (!line) return null
const parsed = parseInt(line)
if (isNaN(parsed)) return null
return parsed
}

/**
* Copyright 2020 ScaCap
* https://github.com/ScaCap/action-surefire-report/blob/master/utils.js#L18
Expand Down Expand Up @@ -214,6 +229,7 @@ async function parseSuite(

const pos = await resolveFileAndLine(
testcase._attributes.file || testsuite._attributes.file,
testcase._attributes.line || testsuite._attributes.line,
testcase._attributes.classname
? testcase._attributes.classname
: testcase._attributes.name,
Expand Down
11 changes: 11 additions & 0 deletions test_results/xunit/report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<testsuites disabled="0" errors="0" failures="1" tests="4" time="0.0">
<testsuite disabled="0" errors="0" failures="1" name="CI basic test" skipped="0" tests="4" time="0">
<testcase name="test_my_sum_pos" file="main.c" line="44"/>
<testcase name="test_my_sum_neg" file="main.c" line="45"/>
<testcase name="test_my_sum_fail" file="main.c" line="38">
<failure type="failure" message="Expected 2 Was 0"/>
</testcase>
<testcase name="test_my_sum_zero" file="main.c" line="47"/>
</testsuite>
</testsuites>

0 comments on commit 7635c7c

Please sign in to comment.