Skip to content

Commit 14033f6

Browse files
committed
Merge branch 'master' of github.com:stubbornella/csslint
2 parents e14628b + e6f90a9 commit 14033f6

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

src/formatters/junit-xml.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*global CSSLint*/
2+
CSSLint.addFormatter({
3+
//format information
4+
id: "junit-xml",
5+
name: "JUNIT XML format",
6+
7+
/**
8+
* Return opening root XML tag.
9+
* @return {String} to prepend before all results
10+
*/
11+
startFormat: function(){
12+
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
13+
},
14+
15+
/**
16+
* Return closing root XML tag.
17+
* @return {String} to append after all results
18+
*/
19+
endFormat: function() {
20+
return "</testsuites>";
21+
},
22+
23+
/**
24+
* Given CSS Lint results for a file, return output for this format.
25+
* @param results {Object} with error and warning messages
26+
* @param filename {String} relative file path
27+
* @param options {Object} (UNUSED for now) specifies special handling of output
28+
* @return {String} output for results
29+
*/
30+
formatResults: function(results, filename, options) {
31+
32+
var messages = results.messages,
33+
output = [],
34+
tests = {
35+
'error': 0,
36+
'failure': 0
37+
};
38+
39+
/**
40+
* Generate a source string for a rule.
41+
* JUNIT source strings usually resemble Java class names e.g
42+
* net.csslint.SomeRuleName
43+
* @param {Object} rule
44+
* @return rule source as {String}
45+
*/
46+
var generateSource = function(rule) {
47+
if (!rule || !('name' in rule)) {
48+
return "";
49+
}
50+
return 'net.csslint.' + rule.name.replace(/\s/g,'');
51+
};
52+
53+
/**
54+
* Replace special characters before write to output.
55+
*
56+
* Rules:
57+
* - single quotes is the escape sequence for double-quotes
58+
* - &lt; is the escape sequence for <
59+
* - &gt; is the escape sequence for >
60+
*
61+
* @param {String} message to escape
62+
* @return escaped message as {String}
63+
*/
64+
var escapeSpecialCharacters = function(str) {
65+
66+
if (!str || str.constructor !== String) {
67+
return "";
68+
}
69+
70+
return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");
71+
72+
};
73+
74+
if (messages.length > 0) {
75+
76+
messages.forEach(function (message, i) {
77+
78+
// since junit has no warning class
79+
// all issues as errors
80+
var type = message.type === 'warning' ? 'error' : message.type;
81+
82+
//ignore rollups for now
83+
if (!message.rollup) {
84+
85+
// build the test case seperately, once joined
86+
// we'll add it to a custom array filtered by type
87+
output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
88+
output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ':' + message.col + ':' + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">");
89+
output.push("</testcase>");
90+
91+
tests[type] += 1;
92+
93+
}
94+
95+
});
96+
97+
output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
98+
output.push("</testsuite>");
99+
100+
}
101+
102+
return output.join("");
103+
104+
}
105+
});

tests/formatters/junit-xml.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
(function(){
2+
3+
/*global YUITest, CSSLint*/
4+
var Assert = YUITest.Assert;
5+
6+
YUITest.TestRunner.add(new YUITest.TestCase({
7+
8+
name: "JUNIT XML formatter test",
9+
10+
"File with no problems should say so": function(){
11+
12+
var result = { messages: [], stats: [] },
13+
expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites></testsuites>";
14+
Assert.areEqual(expected, CSSLint.format(result, "FILE", "junit-xml"));
15+
16+
},
17+
18+
"File with problems should list them": function(){
19+
20+
var result = { messages: [
21+
{ type: "warning", line: 1, col: 1, message: "BOGUS", evidence: "ALSO BOGUS", rule: { name: "A Rule"} },
22+
{ type: "error", line: 2, col: 1, message: "BOGUS", evidence: "ALSO BOGUS", rule: { name: "Some Other Rule"} }
23+
], stats: [] },
24+
25+
file = "<testsuite time=\"0\" tests=\"2\" skipped=\"0\" errors=\"2\" failures=\"0\" package=\"net.csslint\" name=\"FILE\">",
26+
error1 = "<testcase time=\"0\" name=\"net.csslint.ARule\"><error message=\"BOGUS\"><![CDATA[1:1:ALSO BOGUS]]></error></testcase>",
27+
error2 = "<testcase time=\"0\" name=\"net.csslint.SomeOtherRule\"><error message=\"BOGUS\"><![CDATA[2:1:ALSO BOGUS]]></error></testcase>",
28+
expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>" + file + error1 + error2 + "</testsuite></testsuites>",
29+
actual = CSSLint.format(result, "FILE", "junit-xml");
30+
31+
Assert.areEqual(expected, actual);
32+
33+
},
34+
35+
"Formatter should escape special characters": function() {
36+
37+
var specialCharsSting = 'sneaky, "sneaky", <sneaky>',
38+
result = { messages: [
39+
{ type: "warning", line: 1, col: 1, message: specialCharsSting, evidence: "ALSO BOGUS", rule: [] },
40+
{ type: "error", line: 2, col: 1, message: specialCharsSting, evidence: "ALSO BOGUS", rule: [] }
41+
], stats: [] },
42+
43+
file = "<testsuite time=\"0\" tests=\"2\" skipped=\"0\" errors=\"2\" failures=\"0\" package=\"net.csslint\" name=\"FILE\">",
44+
error1 = "<testcase time=\"0\" name=\"\"><error message=\"sneaky, 'sneaky', &lt;sneaky&gt;\"><![CDATA[1:1:ALSO BOGUS]]></error></testcase>",
45+
error2 = "<testcase time=\"0\" name=\"\"><error message=\"sneaky, 'sneaky', &lt;sneaky&gt;\"><![CDATA[2:1:ALSO BOGUS]]></error></testcase>",
46+
expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>" + file + error1 + error2 + "</testsuite></testsuites>",
47+
actual = CSSLint.format(result, "FILE", "junit-xml");
48+
49+
Assert.areEqual(expected, actual);
50+
51+
}
52+
53+
}));
54+
})();

0 commit comments

Comments
 (0)