1 (function(){ 2 3 var APOS = "'"; QUOTE = '"'; 4 var ESCAPED_QUOTE = { }; 5 ESCAPED_QUOTE[QUOTE] = '"'; 6 ESCAPED_QUOTE[APOS] = '''; 7 8 function formatAttributes(attributes) { 9 var att_value; 10 var apos_pos, quot_pos; 11 var use_quote, escape, quote_to_escape; 12 var att_str; 13 var re; 14 var result = ''; 15 16 for (var att in attributes) { 17 att_value = attributes[att] || ""; 18 19 att_value = att_value.replace(/&/g, "&"); 20 att_value = att_value.replace(/</g, "<"); 21 att_value = att_value.replace(/>/g, ">"); 22 23 // Find first quote marks if any 24 apos_pos = att_value.indexOf(APOS); 25 quot_pos = att_value.indexOf(QUOTE); 26 27 // Determine which quote type to use around 28 // the attribute value 29 if (apos_pos == -1 && quot_pos == -1) { 30 att_str = ' ' + att + "='" + att_value + "'"; 31 result += att_str; 32 continue; 33 } 34 35 // Prefer the single quote unless forced to use double 36 if (quot_pos != -1 && quot_pos < apos_pos) { 37 use_quote = APOS; 38 } 39 else { 40 use_quote = QUOTE; 41 } 42 43 // Figure out which kind of quote to escape 44 // Use nice dictionary instead of yucky if-else nests 45 escape = ESCAPED_QUOTE[use_quote]; 46 47 // Escape only the right kind of quote 48 re = new RegExp(use_quote,'g'); 49 att_str = ' ' + att + '=' + use_quote + 50 att_value.replace(re, escape) + use_quote; 51 result += att_str; 52 } 53 return result; 54 }; 55 56 57 /** JavaScript API reporter. 58 * 59 * @constructor 60 */ 61 jasmine.XMLReporter = function() { 62 this.started = false; 63 this.finished = false; 64 this.suites_ = []; 65 this.results_ = {}; 66 }; 67 68 jasmine.XMLReporter.prototype.reportRunnerStarting = function(runner) { 69 this.started = true; 70 var suites = runner.suites(); 71 for (var i = 0; i < suites.length; i++) { 72 var suite = suites[i]; 73 this.suites_.push(this.summarize_(suite)); 74 } 75 this.startedAt = new Date(); 76 puts("<testsuites>") 77 }; 78 79 jasmine.XMLReporter.prototype.suites = function() { 80 return this.suites_; 81 }; 82 83 jasmine.XMLReporter.prototype.summarize_ = function(suiteOrSpec) { 84 var isSuite = suiteOrSpec instanceof jasmine.Suite 85 var summary = { 86 id: suiteOrSpec.id, 87 name: suiteOrSpec.description, 88 type: isSuite ? 'suite' : 'spec', 89 children: [] 90 }; 91 if (isSuite) { 92 var specs = suiteOrSpec.specs(); 93 for (var i = 0; i < specs.length; i++) { 94 summary.children.push(this.summarize_(specs[i])); 95 } 96 } 97 return summary; 98 }; 99 100 jasmine.XMLReporter.prototype.results = function() { 101 return this.results_; 102 }; 103 104 jasmine.XMLReporter.prototype.resultsForSpec = function(specId) { 105 return this.results_[specId]; 106 }; 107 108 //noinspection JSUnusedLocalSymbols 109 jasmine.XMLReporter.prototype.reportRunnerResults = function(runner) { 110 this.finished = true; 111 var results = runner.results(); 112 var specs = runner.specs(); 113 var specCount = specs.length; 114 if(jasmine.XMLReporter.current_suite){ 115 puts(" </testsuite>"); 116 } 117 // puts(" <tests>"+specCount+"</tests>"); 118 // puts(" <errors>"+results.failedCount+"</errors>"); 119 // puts(" <skipped>0</skipped>"); 120 // puts(" <failures>0</failures>"); 121 // puts(" <time>"+((new Date().getTime() - this.startedAt.getTime()) / 1000)+"</time>"); 122 puts("</testsuites>"); 123 }; 124 125 //noinspection JSUnusedLocalSymbols 126 jasmine.XMLReporter.prototype.reportSuiteResults = function(suite) { 127 }; 128 129 //noinspection JSUnusedLocalSymbols 130 jasmine.XMLReporter.prototype.reportSpecResults = function(spec) { 131 var suite = spec.suite; 132 if(jasmine.XMLReporter.current_suite != suite){ 133 if(jasmine.XMLReporter.current_suite){ 134 puts(" </testsuite>"); 135 } 136 var name = [ spec.description ]; 137 while(suite){ 138 name.unshift( suite.description ); 139 suite = suite.parentSuite; 140 } 141 puts(" <testsuite"+formatAttributes({name:name.join(" : ")}) +">"); 142 jasmine.XMLReporter.current_suite = spec.suite; 143 } 144 this.results_[spec.id] = { 145 spec: spec, 146 messages: spec.results().getItems(), 147 result: spec.results().failedCount > 0 ? "failed" : "passed" 148 }; 149 var results = spec.results().getItems(); 150 for(var i in results) { 151 var result = results[i]; 152 puts(" <testcase"+formatAttributes({name:(1+parseInt(i))+ ": " + result.matcherName})+">"); 153 if(!result.passed()){ 154 puts(" <failure"+formatAttributes({type:result.matcherName, 155 message:result.message})+">"); 156 puts("<![CDATA["); 157 puts(get_exception_trace(result.trace)); 158 puts("]]>"); 159 puts(" </failure>"); 160 } 161 puts(" </testcase>"); 162 } 163 }; 164 165 //noinspection JSUnusedLocalSymbols 166 jasmine.XMLReporter.prototype.log = function(str) { 167 // print(str); 168 }; 169 170 jasmine.XMLReporter.prototype.resultsForSpecs = function(specIds){ 171 var results = {}; 172 for (var i = 0; i < specIds.length; i++) { 173 var specId = specIds[i]; 174 results[specId] = this.summarizeResult_(this.results_[specId]); 175 } 176 return results; 177 }; 178 179 jasmine.XMLReporter.prototype.summarizeResult_ = function(result){ 180 var summaryMessages = []; 181 for (var messageIndex in result.messages) { 182 var resultMessage = result.messages[messageIndex]; 183 summaryMessages.push({ 184 text: resultMessage.text, 185 passed: resultMessage.passed ? resultMessage.passed() : true, 186 type: resultMessage.type, 187 message: resultMessage.message, 188 trace: { 189 stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : undefined 190 } 191 }); 192 }; 193 194 var summaryResult = { 195 result : result.result, 196 messages : summaryMessages 197 }; 198 199 return summaryResult; 200 }; 201 202 })(); 203