Skip to content

Commit

Permalink
fix(cli): correctly handle special characters in JUnit failure details
Browse files Browse the repository at this point in the history
Those details are contained in XML CDATA section and should therefore not be XML-escaped.
  • Loading branch information
fgreinacher committed Jan 19, 2022
1 parent f1b2c2c commit ffc1c1e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 3 deletions.
@@ -0,0 +1,46 @@
[
{
"code": "special-xml-strings",
"message": "start ' \" < > end",
"path": [
"root",
"'",
"\"",
"leaf"
],
"severity": 0,
"source": "",
"range": {
"start": {
"line": 0,
"character": 0
},
"end": {
"line": 0,
"character": 0
}
}
},
{
"code": "special-cdata-strings",
"message": "start <![CDATA[ ]]> <![CDATA[ end",
"path": [
"root",
"]]>",
"<![CDATA[",
"leaf"
],
"severity": 0,
"source": "",
"range": {
"start": {
"line": 0,
"character": 0
},
"end": {
"line": 0,
"character": 0
}
}
}
]
55 changes: 54 additions & 1 deletion packages/cli/src/formatters/__tests__/junit.test.ts
Expand Up @@ -4,6 +4,7 @@ import { DiagnosticSeverity } from '@stoplight/types';

const oas3SchemaErrors = require('./__fixtures__/oas3-schema-errors.json');
const mixedErrors = require('./__fixtures__/mixed-errors.json');
const specialXmlStrings = require('./__fixtures__/errors-with-special-xml-strings.json');

describe('JUnit formatter', () => {
let parse: Parser['parseStringPromise'];
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('JUnit formatter', () => {
$: {
message: "should have required property '$ref'",
},
_: 'line 36, col 22, should have required property &apos;$ref&apos; (oas3-schema) at path #/paths/~1pets/get/responses/200/headers/header-1',
_: "line 36, col 22, should have required property '$ref' (oas3-schema) at path #/paths/~1pets/get/responses/200/headers/header-1",
},
],
},
Expand Down Expand Up @@ -168,4 +169,56 @@ describe('JUnit formatter', () => {
},
});
});

test('handles special XML strings properly', async () => {
const result = await parse(junit(specialXmlStrings, { failSeverity: DiagnosticSeverity.Error }));
expect(result).toEqual({
testsuites: {
testsuite: [
{
$: {
errors: '0',
failures: '2',
name: '',
package: 'org.spectral',
tests: '2',
time: '0',
},
testcase: [
{
$: {
classname: '',
name: 'org.spectral.special-xml-strings',
time: '0',
},
failure: [
{
$: {
message: 'start \' " < > end',
},
_: 'line 1, col 1, start \' " < > end (special-xml-strings) at path #/root/\'/"/leaf',
},
],
},
{
$: {
classname: '',
name: 'org.spectral.special-cdata-strings',
time: '0',
},
failure: [
{
$: {
message: 'start <![CDATA[ ]]> <![CDATA[ end',
},
_: 'line 1, col 1, start <![CDATA[ ]]> <![CDATA[ end (special-cdata-strings) at path #/root/]]>/<![CDATA[/leaf',
},
],
},
],
},
],
},
});
});
});
11 changes: 9 additions & 2 deletions packages/cli/src/formatters/junit.ts
Expand Up @@ -29,6 +29,13 @@ import { printPath, PrintStyle } from '@stoplight/spectral-runtime';
import { Formatter } from './types';
import { groupBySource, xmlEscape } from './utils';

/**
* Prepares the given text for inclusion in an XML CDATA section.
*/
function prepareForCdata(text: string): string {
return text.replace(']]>', ']]]]><![CDATA[>');
}

export const junit: Formatter = (results, { failSeverity }) => {
let output = '';

Expand All @@ -50,8 +57,8 @@ export const junit: Formatter = (results, { failSeverity }) => {
output += `<failure message="${xmlEscape(result.message)}">`;
output += '<![CDATA[';
output += `line ${result.range.start.line + 1}, col ${result.range.start.character + 1}, `;
output += `${xmlEscape(result.message)} (${result.code}) `;
output += `at path ${xmlEscape(printPath(result.path, PrintStyle.EscapedPointer))}`;
output += `${prepareForCdata(result.message)} (${result.code}) `;
output += `at path ${prepareForCdata(printPath(result.path, PrintStyle.EscapedPointer))}`;
output += ']]>';
output += `</failure>`;
output += '</testcase>\n';
Expand Down

0 comments on commit ffc1c1e

Please sign in to comment.