dom/imptests/testharnessreport.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:637aeb877ece
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 var W3CTest = {
6 /**
7 * Dictionary mapping a test URL to either the string "all", which means that
8 * all tests in this file are expected to fail, or a dictionary mapping test
9 * names to either the boolean |true|, or the string "debug". The former
10 * means that this test is expected to fail in all builds, and the latter
11 * that it is only expected to fail in debug builds.
12 */
13 "expectedFailures": {},
14
15 /**
16 * If set to true, we will dump the test failures to the console.
17 */
18 "dumpFailures": false,
19
20 /**
21 * If dumpFailures is true, this holds a structure like necessary for
22 * expectedFailures, for ease of updating the expectations.
23 */
24 "failures": {},
25
26 /**
27 * List of test results, needed by TestRunner to update the UI.
28 */
29 "tests": [],
30
31 /**
32 * Number of unlogged passes, to stop buildbot from truncating the log.
33 * We will print a message every MAX_COLLAPSED_MESSAGES passes.
34 */
35 "collapsedMessages": 0,
36 "MAX_COLLAPSED_MESSAGES": 100,
37
38 /**
39 * Reference to the TestRunner object in the parent frame.
40 */
41 "runner": parent === this ? null : parent.TestRunner || parent.wrappedJSObject.TestRunner,
42
43 /**
44 * Prefixes for the error logging. Indexed first by int(todo) and second by
45 * int(result).
46 */
47 "prefixes": [
48 ["TEST-UNEXPECTED-FAIL", "TEST-PASS"],
49 ["TEST-KNOWN-FAIL", "TEST-UNEXPECTED-PASS"]
50 ],
51
52 /**
53 * Prefix of the path to parent of the the failures directory.
54 */
55 "pathprefix": "/tests/dom/imptests/",
56
57 /**
58 * Returns the URL of the current test, relative to the root W3C tests
59 * directory. Used as a key into the expectedFailures dictionary.
60 */
61 "getPath": function() {
62 var url = this.getURL();
63 if (!url.startsWith(this.pathprefix)) {
64 return "";
65 }
66 return url.substring(this.pathprefix.length);
67 },
68
69 /**
70 * Returns the root-relative URL of the current test.
71 */
72 "getURL": function() {
73 return this.runner ? this.runner.currentTestURL : location.pathname;
74 },
75
76 /**
77 * Report the results in the tests array.
78 */
79 "reportResults": function() {
80 var element = function element(aLocalName) {
81 var xhtmlNS = "http://www.w3.org/1999/xhtml";
82 return document.createElementNS(xhtmlNS, aLocalName);
83 };
84
85 var stylesheet = element("link");
86 stylesheet.setAttribute("rel", "stylesheet");
87 stylesheet.setAttribute("href", "/resources/testharness.css");
88 var heads = document.getElementsByTagName("head");
89 if (heads.length) {
90 heads[0].appendChild(stylesheet);
91 }
92
93 var log = document.getElementById("log");
94 if (!log) {
95 return;
96 }
97 var section = log.appendChild(element("section"));
98 section.id = "summary";
99 section.appendChild(element("h2")).textContent = "Details";
100
101 var table = section.appendChild(element("table"));
102 table.id = "results";
103
104 var tr = table.appendChild(element("thead")).appendChild(element("tr"));
105 for (var header of ["Result", "Test Name", "Message"]) {
106 tr.appendChild(element("th")).textContent = header;
107 }
108 var statuses = [
109 ["Unexpected Fail", "Pass"],
110 ["Known Fail", "Unexpected Pass"]
111 ];
112 var tbody = table.appendChild(element("tbody"));
113 for (var test of this.tests) {
114 tr = tbody.appendChild(element("tr"));
115 tr.className = (test.result === !test.todo ? "pass" : "fail");
116 tr.appendChild(element("td")).textContent =
117 statuses[+test.todo][+test.result];
118 tr.appendChild(element("td")).textContent = test.name;
119 tr.appendChild(element("td")).textContent = test.message;
120 }
121 },
122
123 /**
124 * Returns a printable message based on aTest's 'name' and 'message'
125 * properties.
126 */
127 "formatTestMessage": function(aTest) {
128 return aTest.name + (aTest.message ? ": " + aTest.message : "");
129 },
130
131 /**
132 * Lets the test runner know about a test result.
133 */
134 "_log": function(test) {
135 var url = this.getURL();
136 var msg = this.prefixes[+test.todo][+test.result] + " | ";
137 if (url) {
138 msg += url;
139 }
140 msg += " | " + this.formatTestMessage(test);
141 if (this.runner) {
142 this.runner[(test.result === !test.todo) ? "log" : "error"](msg);
143 } else {
144 dump(msg + "\n");
145 }
146 },
147
148 /**
149 * Logs a message about collapsed messages (if any), and resets the counter.
150 */
151 "_logCollapsedMessages": function() {
152 if (this.collapsedMessages) {
153 this._log({
154 "name": document.title,
155 "result": true,
156 "todo": false,
157 "message": "Elided " + this.collapsedMessages + " passes or known failures."
158 });
159 }
160 this.collapsedMessages = 0;
161 },
162
163 /**
164 * Maybe logs a result, eliding up to MAX_COLLAPSED_MESSAGES consecutive
165 * passes.
166 */
167 "_maybeLog": function(test) {
168 var success = (test.result === !test.todo);
169 if (success && ++this.collapsedMessages < this.MAX_COLLAPSED_MESSAGES) {
170 return;
171 }
172 this._logCollapsedMessages();
173 this._log(test);
174 },
175
176 /**
177 * Reports a test result. The argument is an object with the following
178 * properties:
179 *
180 * o message (string): message to be reported
181 * o result (boolean): whether this test failed
182 * o todo (boolean): whether this test is expected to fail
183 */
184 "report": function(test) {
185 this.tests.push(test);
186 this._maybeLog(test);
187 },
188
189 /**
190 * Returns true if this test is expected to fail, and false otherwise.
191 */
192 "_todo": function(test) {
193 if (this.expectedFailures === "all") {
194 return true;
195 }
196 var value = this.expectedFailures[test.name];
197 return value === true || (value === "debug" && !!SpecialPowers.isDebugBuild);
198 },
199
200 /**
201 * Callback function for testharness.js. Called when one test in a file
202 * finishes.
203 */
204 "result": function(test) {
205 var url = this.getPath();
206 this.report({
207 "name": test.name,
208 "message": test.message || "",
209 "result": test.status === test.PASS,
210 "todo": this._todo(test)
211 });
212 if (this.dumpFailures && test.status !== test.PASS) {
213 this.failures[test.name] = true;
214 }
215 },
216
217 /**
218 * Callback function for testharness.js. Called when the entire test file
219 * finishes.
220 */
221 "finish": function(tests, status) {
222 var url = this.getPath();
223 this.report({
224 "name": "Finished test",
225 "message": "Status: " + status.status,
226 "result": status.status === status.OK,
227 "todo":
228 url in this.expectedFailures &&
229 this.expectedFailures[url] === "error"
230 });
231
232 this._logCollapsedMessages();
233
234 if (this.dumpFailures) {
235 dump("@@@ @@@ Failures\n");
236 dump(url + "@@@" + JSON.stringify(this.failures) + "\n");
237 }
238 if (this.runner) {
239 this.runner.testFinished(this.tests.map(function(aTest) {
240 return {
241 "message": this.formatTestMessage(aTest),
242 "result": aTest.result,
243 "todo": aTest.todo
244 };
245 }, this));
246 } else {
247 this.reportResults();
248 }
249 },
250
251 /**
252 * Log an unexpected failure. Intended to be used from harness code, not
253 * from tests.
254 */
255 "logFailure": function(aTestName, aMessage) {
256 this.report({
257 "name": aTestName,
258 "message": aMessage,
259 "result": false,
260 "todo": false
261 });
262 },
263
264 /**
265 * Timeout the current test. Intended to be used from harness code, not
266 * from tests.
267 */
268 "timeout": function() {
269 this.logFailure("Timeout", "Test runner timed us out.");
270 timeout();
271 }
272 };
273 (function() {
274 try {
275 var path = W3CTest.getPath();
276 if (path) {
277 // Get expected fails. If there aren't any, there will be a 404, which is
278 // fine. Anything else is unexpected.
279 var url = W3CTest.pathprefix + "failures/" + path + ".json";
280 var request = new XMLHttpRequest();
281 request.open("GET", url, false);
282 request.send();
283 if (request.status === 200) {
284 W3CTest.expectedFailures = JSON.parse(request.responseText);
285 } else if (request.status !== 404) {
286 W3CTest.logFailure("Fetching failures file", "Request status was " + request.status);
287 }
288 }
289
290 add_result_callback(W3CTest.result.bind(W3CTest));
291 add_completion_callback(W3CTest.finish.bind(W3CTest));
292 setup({
293 "output": false,
294 "explicit_timeout": true
295 });
296 } catch (e) {
297 W3CTest.logFailure("Harness setup", "Unexpected exception: " + e);
298 }
299 })();

mercurial