js/src/tests/browser.js

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:60380cf3595c
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 var gPageCompleted;
7 var GLOBAL = this + '';
8
9 // Variables local to jstests harness.
10 var jstestsTestPassesUnlessItThrows = false;
11 var jstestsRestoreFunction;
12 var jstestsOptions;
13
14 /*
15 * Signals to this script that the current test case should be considered to
16 * have passed if it doesn't throw an exception.
17 *
18 * Overrides the same-named function in shell.js.
19 */
20 function testPassesUnlessItThrows() {
21 jstestsTestPassesUnlessItThrows = true;
22 }
23
24 /*
25 * Requests to load the given JavaScript file before the file containing the
26 * test case.
27 */
28 function include(file) {
29 outputscripttag(file, {language: "type", mimetype: "text/javascript"});
30 }
31
32 /*
33 * Sets a restore function which restores the standard built-in ECMAScript
34 * properties after a destructive test case, and which will be called after
35 * the test case terminates.
36 */
37 function setRestoreFunction(restore) {
38 jstestsRestoreFunction = restore;
39 }
40
41 function htmlesc(str) {
42 if (str == '<')
43 return '&lt;';
44 if (str == '>')
45 return '&gt;';
46 if (str == '&')
47 return '&amp;';
48 return str;
49 }
50
51 function DocumentWrite(s)
52 {
53 try
54 {
55 var msgDiv = document.createElement('div');
56 msgDiv.innerHTML = s;
57 document.body.appendChild(msgDiv);
58 msgDiv = null;
59 }
60 catch(excp)
61 {
62 document.write(s + '<br>\n');
63 }
64 }
65
66 function print() {
67 var s = '';
68 var a;
69 for (var i = 0; i < arguments.length; i++)
70 {
71 a = arguments[i];
72 s += String(a) + ' ';
73 }
74
75 if (typeof dump == 'function')
76 {
77 dump( s + '\n');
78 }
79
80 s = s.replace(/[<>&]/g, htmlesc);
81
82 DocumentWrite(s);
83 }
84
85 function writeHeaderToLog( string ) {
86 string = String(string);
87
88 if (typeof dump == 'function')
89 {
90 dump( string + '\n');
91 }
92
93 string = string.replace(/[<>&]/g, htmlesc);
94
95 DocumentWrite( "<h2>" + string + "</h2>" );
96 }
97
98 function writeFormattedResult( expect, actual, string, passed ) {
99 string = String(string);
100
101 if (typeof dump == 'function')
102 {
103 dump( string + '\n');
104 }
105
106 string = string.replace(/[<>&]/g, htmlesc);
107
108 var s = "<tt>"+ string ;
109 s += "<b>" ;
110 s += ( passed ) ? "<font color=#009900> &nbsp;" + PASSED
111 : "<font color=#aa0000>&nbsp;" + FAILED + expect;
112
113 DocumentWrite( s + "</font></b></tt><br>" );
114 return passed;
115 }
116
117 window.onerror = function (msg, page, line)
118 {
119 jstestsTestPassesUnlessItThrows = false;
120
121 // Restore options in case a test case used this common variable name.
122 options = jstestsOptions;
123
124 // Restore the ECMAScript environment after potentially destructive tests.
125 if (typeof jstestsRestoreFunction === "function") {
126 jstestsRestoreFunction();
127 }
128
129 optionsPush();
130
131 if (typeof DESCRIPTION == 'undefined')
132 {
133 DESCRIPTION = 'Unknown';
134 }
135 if (typeof EXPECTED == 'undefined')
136 {
137 EXPECTED = 'Unknown';
138 }
139
140 var testcase = new TestCase("unknown-test-name", DESCRIPTION, EXPECTED, "error");
141
142 if (document.location.href.indexOf('-n.js') != -1)
143 {
144 // negative test
145 testcase.passed = true;
146 }
147
148 testcase.reason = page + ':' + line + ': ' + msg;
149
150 reportFailure(msg);
151
152 optionsReset();
153 };
154
155 function gc()
156 {
157 try
158 {
159 SpecialPowers.forceGC();
160 }
161 catch(ex)
162 {
163 print('gc: ' + ex);
164 }
165 }
166
167 function jsdgc()
168 {
169 try
170 {
171 var jsdIDebuggerService = SpecialPowers.Ci.jsdIDebuggerService;
172 var service = SpecialPowers.Cc['@mozilla.org/js/jsd/debugger-service;1'].
173 getService(jsdIDebuggerService);
174 service.GC();
175 }
176 catch(ex)
177 {
178 print('jsdgc: ' + ex);
179 }
180 }
181
182 function quit()
183 {
184 }
185
186 function options(aOptionName)
187 {
188 // return value of options() is a comma delimited list
189 // of the previously set values
190
191 var value = '';
192 for (var optionName in options.currvalues)
193 {
194 value += optionName + ',';
195 }
196 if (value)
197 {
198 value = value.substring(0, value.length-1);
199 }
200
201 if (aOptionName) {
202 if (!(aOptionName in SpecialPowers.Cu)) {
203 // This test is trying to flip an unsupported option, so it's
204 // likely no longer testing what it was supposed to. Fail it
205 // hard.
206 throw "Unsupported JSContext option '"+ aOptionName +"'";
207 }
208
209 if (options.currvalues.hasOwnProperty(aOptionName))
210 // option is set, toggle it to unset
211 delete options.currvalues[aOptionName];
212 else
213 // option is not set, toggle it to set
214 options.currvalues[aOptionName] = true;
215
216 SpecialPowers.Cu[aOptionName] =
217 options.currvalues.hasOwnProperty(aOptionName);
218 }
219
220 return value;
221 }
222
223 // Keep a reference to options around so that we can restore it after running
224 // a test case, which may have used this common name for one of its own
225 // variables.
226 jstestsOptions = options;
227
228 function optionsInit() {
229
230 // hash containing the set options.
231 options.currvalues = {
232 strict: true,
233 werror: true,
234 strict_mode: true
235 };
236
237 // record initial values to support resetting
238 // options to their initial values
239 options.initvalues = {};
240
241 // record values in a stack to support pushing
242 // and popping options
243 options.stackvalues = [];
244
245 for (var optionName in options.currvalues)
246 {
247 var propName = optionName;
248
249 if (!(propName in SpecialPowers.Cu))
250 {
251 throw "options.currvalues is out of sync with Components.utils";
252 }
253 if (!SpecialPowers.Cu[propName])
254 {
255 delete options.currvalues[optionName];
256 }
257 else
258 {
259 options.initvalues[optionName] = true;
260 }
261 }
262 }
263
264 function gczeal(z)
265 {
266 SpecialPowers.setGCZeal(z);
267 }
268
269 function jit(on)
270 {
271 }
272
273 function jsTestDriverBrowserInit()
274 {
275
276 if (typeof dump != 'function')
277 {
278 dump = print;
279 }
280
281 optionsInit();
282 optionsClear();
283
284 if (document.location.search.indexOf('?') != 0)
285 {
286 // not called with a query string
287 return;
288 }
289
290 var properties = {};
291 var fields = document.location.search.slice(1).split(';');
292 for (var ifield = 0; ifield < fields.length; ifield++)
293 {
294 var propertycaptures = /^([^=]+)=(.*)$/.exec(fields[ifield]);
295 if (!propertycaptures)
296 {
297 properties[fields[ifield]] = true;
298 }
299 else
300 {
301 properties[propertycaptures[1]] = decodeURIComponent(propertycaptures[2]);
302 if (propertycaptures[1] == 'language')
303 {
304 // language=(type|language);mimetype
305 properties.mimetype = fields[ifield+1];
306 }
307 }
308 }
309
310 if (properties.language != 'type')
311 {
312 try
313 {
314 properties.version = /javascript([.0-9]+)/.exec(properties.mimetype)[1];
315 }
316 catch(ex)
317 {
318 }
319 }
320
321 if (!properties.version && navigator.userAgent.indexOf('Gecko/') != -1)
322 {
323 // If the version is not specified, and the browser is Gecko,
324 // use the default version corresponding to the shell's version(0).
325 // See https://bugzilla.mozilla.org/show_bug.cgi?id=522760#c11
326 // Otherwise adjust the version to match the suite version for 1.6,
327 // and later due to the use of for-each, let, yield, etc.
328 //
329 // Note that js1_8, js1_8_1, and js1_8_5 are treated identically in
330 // the browser.
331 if (properties.test.match(/^js1_6/))
332 {
333 properties.version = '1.6';
334 }
335 else if (properties.test.match(/^js1_7/))
336 {
337 properties.version = '1.7';
338 }
339 else if (properties.test.match(/^js1_8/))
340 {
341 properties.version = '1.8';
342 }
343 }
344
345 // default to language=type;text/javascript. required for
346 // reftest style manifests.
347 if (!properties.language)
348 {
349 properties.language = 'type';
350 properties.mimetype = 'text/javascript';
351 }
352
353 gTestPath = properties.test;
354
355 if (properties.gczeal)
356 {
357 gczeal(Number(properties.gczeal));
358 }
359
360 /*
361 * since the default setting of jit changed from false to true
362 * in http://hg.mozilla.org/tracemonkey/rev/685e00e68be9
363 * bisections which depend upon jit settings can be thrown off.
364 * default jit(false) when not running jsreftests to make bisections
365 * depending upon jit settings consistent over time. This is not needed
366 * in shell tests as the default jit setting has not changed there.
367 */
368
369 if (properties.jit || !document.location.href.match(/jsreftest.html/))
370 jit(properties.jit);
371
372 var testpathparts = properties.test.split(/\//);
373
374 if (testpathparts.length < 3)
375 {
376 // must have at least suitepath/subsuite/testcase.js
377 return;
378 }
379
380 document.write('<title>' + properties.test + '<\/title>');
381
382 // XXX bc - the first document.written script is ignored if the protocol
383 // is file:. insert an empty script tag, to work around it.
384 document.write('<script></script>');
385
386 // Output script tags for shell.js, then browser.js, at each level of the
387 // test path hierarchy.
388 var prepath = "";
389 var i = 0;
390 for (end = testpathparts.length - 1; i < end; i++) {
391 prepath += testpathparts[i] + "/";
392 outputscripttag(prepath + "shell.js", properties);
393 outputscripttag(prepath + "browser.js", properties);
394 }
395
396 // Output the test script itself.
397 outputscripttag(prepath + testpathparts[i], properties);
398
399 // Finally output the driver-end script to advance to the next test.
400 outputscripttag('js-test-driver-end.js', properties);
401 return;
402 }
403
404 function outputscripttag(src, properties)
405 {
406 if (!src)
407 {
408 return;
409 }
410
411 var s = '<script src="' + src + '" charset="utf-8" ';
412
413 if (properties.language != 'type')
414 {
415 s += 'language="javascript';
416 if (properties.version)
417 {
418 s += properties.version;
419 }
420 }
421 else
422 {
423 s += 'type="' + properties.mimetype;
424 if (properties.version)
425 {
426 s += ';version=' + properties.version;
427 }
428 }
429 s += '"><\/script>';
430
431 document.write(s);
432 }
433
434 function jsTestDriverEnd()
435 {
436 // gDelayTestDriverEnd is used to
437 // delay collection of the test result and
438 // signal to Spider so that tests can continue
439 // to run after page load has fired. They are
440 // responsible for setting gDelayTestDriverEnd = true
441 // then when completed, setting gDelayTestDriverEnd = false
442 // then calling jsTestDriverEnd()
443
444 if (gDelayTestDriverEnd)
445 {
446 return;
447 }
448
449 window.onerror = null;
450
451 // Restore options in case a test case used this common variable name.
452 options = jstestsOptions;
453
454 // Restore the ECMAScript environment after potentially destructive tests.
455 if (typeof jstestsRestoreFunction === "function") {
456 jstestsRestoreFunction();
457 }
458
459 if (jstestsTestPassesUnlessItThrows) {
460 var testcase = new TestCase("unknown-test-name", "", true, true);
461 print(PASSED);
462 jstestsTestPassesUnlessItThrows = false;
463 }
464
465 try
466 {
467 optionsReset();
468 }
469 catch(ex)
470 {
471 dump('jsTestDriverEnd ' + ex);
472 }
473
474 if (window.opener && window.opener.runNextTest)
475 {
476 if (window.opener.reportCallBack)
477 {
478 window.opener.reportCallBack(window.opener.gWindow);
479 }
480 setTimeout('window.opener.runNextTest()', 250);
481 }
482 else
483 {
484 for (var i = 0; i < gTestcases.length; i++)
485 {
486 gTestcases[i].dump();
487 }
488
489 // tell reftest the test is complete.
490 document.documentElement.className = '';
491 // tell Spider page is complete
492 gPageCompleted = true;
493 }
494 }
495
496 //var dlog = (function (s) { print('debug: ' + s); });
497 var dlog = (function (s) {});
498
499 // dialog closer from http://bclary.com/projects/spider/spider/chrome/content/spider/dialog-closer.js
500
501 var gDialogCloser;
502 var gDialogCloserObserver;
503
504 function registerDialogCloser()
505 {
506 gDialogCloser = SpecialPowers.
507 Cc['@mozilla.org/embedcomp/window-watcher;1'].
508 getService(SpecialPowers.Ci.nsIWindowWatcher);
509
510 gDialogCloserObserver = {observe: dialogCloser_observe};
511
512 gDialogCloser.registerNotification(gDialogCloserObserver);
513 }
514
515 function unregisterDialogCloser()
516 {
517 gczeal(0);
518
519 if (!gDialogCloserObserver || !gDialogCloser)
520 {
521 return;
522 }
523
524 gDialogCloser.unregisterNotification(gDialogCloserObserver);
525
526 gDialogCloserObserver = null;
527 gDialogCloser = null;
528 }
529
530 // use an array to handle the case where multiple dialogs
531 // appear at one time
532 var gDialogCloserSubjects = [];
533
534 function dialogCloser_observe(subject, topic, data)
535 {
536 if (subject instanceof ChromeWindow && topic == 'domwindowopened' )
537 {
538 gDialogCloserSubjects.push(subject);
539 // timeout of 0 needed when running under reftest framework.
540 subject.setTimeout(closeDialog, 0);
541 }
542 }
543
544 function closeDialog()
545 {
546 var subject;
547
548 while ( (subject = gDialogCloserSubjects.pop()) != null)
549 {
550 if (subject.document instanceof XULDocument &&
551 subject.document.documentURI == 'chrome://global/content/commonDialog.xul')
552 {
553 subject.close();
554 }
555 else
556 {
557 // alerts inside of reftest framework are not XULDocument dialogs.
558 subject.close();
559 }
560 }
561 }
562
563 registerDialogCloser();
564 window.addEventListener('unload', unregisterDialogCloser, true);
565
566 jsTestDriverBrowserInit();

mercurial