This repository has been archived by the owner on Mar 25, 2021. It is now read-only.
/
junitFormatter.ts
104 lines (93 loc) · 4.2 KB
/
junitFormatter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* @license
* Copyright 2018 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AbstractFormatter } from "../language/formatter/abstractFormatter";
import { IFormatterMetadata } from "../language/formatter/formatter";
import { RuleFailure } from "../language/rule/rule";
import * as Utils from "../utils";
export class Formatter extends AbstractFormatter {
/* tslint:disable:object-literal-sort-keys */
public static metadata: IFormatterMetadata = {
formatterName: "junit",
description: "Formats errors as though they were JUnit output.",
descriptionDetails: Utils.dedent`
Imitates the JUnit XML Output`,
sample: Utils.dedent`
<?xml version="1.0" encoding="utf-8"?>
<testsuites package="tslint">
<testsuite name="myFile.ts">
<testcase name="semicolon" classname="myFile.ts">
<failure type="warning">Missing semicolon Line 1, Column 14</failure>
</testcase>
</testsuite>
</testsuites>
`,
consumer: "machine",
};
/* tslint:enable:object-literal-sort-keys */
public format(failures: RuleFailure[], _fixes?: RuleFailure[], fileNames?: string[]): string {
let output = '<?xml version="1.0" encoding="utf-8"?><testsuites package="tslint">';
const failureFileNames: Set<string> = new Set([...failures.map(f => f.getFileName())]);
if (failures.length !== 0) {
const failuresSorted = failures.sort((a, b) =>
a.getFileName().localeCompare(b.getFileName()),
);
let previousFilename: string | null = null;
for (const failure of failuresSorted) {
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const message = this.escapeXml(failure.getFailure());
const rule = this.escapeXml(failure.getRuleName());
const severity = failure.getRuleSeverity();
if (failure.getFileName() !== previousFilename) {
if (previousFilename !== null) {
output += "</testsuite>";
}
previousFilename = failure.getFileName();
output += `<testsuite name="${this.escapeXml(failure.getFileName())}">`;
}
output += `<testcase name="${rule}" `;
output += `classname="${this.escapeXml(failure.getFileName())}">`;
output += `<failure type="${severity}">${message} `;
output += `Line ${lineAndCharacter.line + 1}, `;
output += `Column ${lineAndCharacter.character + 1}`;
output += `</failure>`;
output += "</testcase>";
}
if (previousFilename !== null) {
output += "</testsuite>";
}
}
if (fileNames !== undefined && fileNames.length !== 0) {
// Filter out files which have had a failure associated with them.
const filteredFileNames = fileNames.filter(fileName => !failureFileNames.has(fileName));
for (const fileName of filteredFileNames) {
output += `<testsuite name="${this.escapeXml(fileName)}" errors="0">`;
output += `<testcase name="${this.escapeXml(fileName)}" />`;
output += `</testsuite>`;
}
}
output += "</testsuites>";
return output;
}
private escapeXml(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/'/g, "'")
.replace(/"/g, """);
}
}