TestFormat.js revision 5aab19b8b78189ce79cf89283f2d505566d4e6a8
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein/**
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * An object object containing test result formatting methods.
75c0816e8295e180f4bc7f10db3d0d880383bc1cMark Andrews * @namespace Test
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @class TestFormat
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @static
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinTest.TestFormat = function(){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein /* (intentionally not documented)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Basic XML escaping method. Replaces quotes, less-than, greater-than,
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * apostrophe, and ampersand characters with their corresponding entities.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @param {String} text The text to encode.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @return {String} The XML-escaped text.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein function xmlEscape(text){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews return text.replace(/[<>"'&]/g, function(value){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein switch(value){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "<": return "&lt;";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case ">": return "&gt;";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "\"": return "&quot;";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "'": return "&apos;";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "&": return "&amp;";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein });
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein return {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein /**
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Returns test results formatted as a JSON string. Requires JSON utility.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @param {Object} result The results object created by TestRunner.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @return {String} A JSON-formatted string of results.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @method JSON
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @static
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein JSON: function(results) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein return Test.Util.JSON.stringify(results);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein },
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein /**
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Returns test results formatted as an XML string.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @param {Object} result The results object created by TestRunner.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @return {String} An XML-formatted string of results.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @method XML
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @static
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein XML: function(results) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein function serializeToXML(results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein var xml = "<" + results.type + " name=\"" + xmlEscape(results.name) + "\"";
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (typeof(results.duration)=="number"){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += " duration=\"" + results.duration + "\"";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.type == "test"){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += " result=\"" + results.result + "\" message=\"" + xmlEscape(results.message) + "\">";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein } else {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += " passed=\"" + results.passed + "\" failed=\"" + results.failed + "\" ignored=\"" + results.ignored + "\" total=\"" + results.total + "\">";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein for (var prop in results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.hasOwnProperty(prop)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += serializeToXML(results[prop]);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += "</" + results.type + ">";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein return xml;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToXML(results);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein },
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein /**
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Returns test results formatted in JUnit XML format.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @param {Object} result The results object created by TestRunner.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @return {String} An XML-formatted string of results.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @method JUnitXML
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * @static
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein JUnitXML: function(results) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein function serializeToJUnitXML(results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein var xml = "";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein switch (results.type){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //equivalent to testcase in JUnit
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "test":
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.result != "ignore"){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml = "<testcase name=\"" + xmlEscape(results.name) + "\" time=\"" + (results.duration/1000) + "\">";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.result == "fail"){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += "<failure message=\"" + xmlEscape(results.message) + "\"><![CDATA[" + results.message + "]]></failure>";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml+= "</testcase>";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein break;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //equivalent to testsuite in JUnit
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "testcase":
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml = "<testsuite name=\"" + xmlEscape(results.name) + "\" tests=\"" + results.total + "\" failures=\"" + results.failed + "\" time=\"" + (results.duration/1000) + "\">";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein for (var prop in results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.hasOwnProperty(prop)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += serializeToJUnitXML(results[prop]);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += "</testsuite>";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein break;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //no JUnit equivalent, don't output anything
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "testsuite":
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein for (var prop in results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.hasOwnProperty(prop)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += serializeToJUnitXML(results[prop]);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein break;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //top-level, equivalent to testsuites in JUnit
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein case "report":
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml = "<testsuites>";
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein for (var prop in results){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results.hasOwnProperty(prop)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein xml += serializeToJUnitXML(results[prop]);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein }
}
xml += "</testsuites>";
//no default
}
return xml;
}
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializeToJUnitXML(results);
},
/**
* Returns test results formatted in TAP format.
* For more information, see <a href="http://testanything.org/">Test Anything Protocol</a>.
* @param {Object} result The results object created by TestRunner.
* @return {String} A TAP-formatted string of results.
* @method TAP
* @static
*/
TAP: function(results) {
var currentTestNum = 1;
function serializeToTAP(results){
var text = "";
switch (results.type){
case "test":
if (results.result != "ignore"){
text = "ok " + (currentTestNum++) + " - " + results.name;
if (results.result == "fail"){
text = "not " + text + " - " + results.message;
}
text += "\n";
} else {
text = "#Ignored test " + results.name + "\n";
}
break;
case "testcase":
text = "#Begin testcase " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";
for (var prop in results){
if (results.hasOwnProperty(prop)){
if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
text += serializeToTAP(results[prop]);
}
}
}
text += "#End testcase " + results.name + "\n";
break;
case "testsuite":
text = "#Begin testsuite " + results.name + "(" + results.failed + " failed of " + results.total + ")\n";
for (var prop in results){
if (results.hasOwnProperty(prop)){
if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
text += serializeToTAP(results[prop]);
}
}
}
text += "#End testsuite " + results.name + "\n";
break;
case "report":
for (var prop in results){
if (results.hasOwnProperty(prop)){
if (results[prop] && typeof results[prop] == "object" && !(results[prop] instanceof Array)){
text += serializeToTAP(results[prop]);
}
}
}
//no default
}
return text;
}
return "1.." + results.total + "\n" + serializeToTAP(results);
}
};
}();