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