1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/tests/browser.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,566 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +var gPageCompleted; 1.10 +var GLOBAL = this + ''; 1.11 + 1.12 +// Variables local to jstests harness. 1.13 +var jstestsTestPassesUnlessItThrows = false; 1.14 +var jstestsRestoreFunction; 1.15 +var jstestsOptions; 1.16 + 1.17 +/* 1.18 + * Signals to this script that the current test case should be considered to 1.19 + * have passed if it doesn't throw an exception. 1.20 + * 1.21 + * Overrides the same-named function in shell.js. 1.22 + */ 1.23 +function testPassesUnlessItThrows() { 1.24 + jstestsTestPassesUnlessItThrows = true; 1.25 +} 1.26 + 1.27 +/* 1.28 + * Requests to load the given JavaScript file before the file containing the 1.29 + * test case. 1.30 + */ 1.31 +function include(file) { 1.32 + outputscripttag(file, {language: "type", mimetype: "text/javascript"}); 1.33 +} 1.34 + 1.35 +/* 1.36 + * Sets a restore function which restores the standard built-in ECMAScript 1.37 + * properties after a destructive test case, and which will be called after 1.38 + * the test case terminates. 1.39 + */ 1.40 +function setRestoreFunction(restore) { 1.41 + jstestsRestoreFunction = restore; 1.42 +} 1.43 + 1.44 +function htmlesc(str) { 1.45 + if (str == '<') 1.46 + return '<'; 1.47 + if (str == '>') 1.48 + return '>'; 1.49 + if (str == '&') 1.50 + return '&'; 1.51 + return str; 1.52 +} 1.53 + 1.54 +function DocumentWrite(s) 1.55 +{ 1.56 + try 1.57 + { 1.58 + var msgDiv = document.createElement('div'); 1.59 + msgDiv.innerHTML = s; 1.60 + document.body.appendChild(msgDiv); 1.61 + msgDiv = null; 1.62 + } 1.63 + catch(excp) 1.64 + { 1.65 + document.write(s + '<br>\n'); 1.66 + } 1.67 +} 1.68 + 1.69 +function print() { 1.70 + var s = ''; 1.71 + var a; 1.72 + for (var i = 0; i < arguments.length; i++) 1.73 + { 1.74 + a = arguments[i]; 1.75 + s += String(a) + ' '; 1.76 + } 1.77 + 1.78 + if (typeof dump == 'function') 1.79 + { 1.80 + dump( s + '\n'); 1.81 + } 1.82 + 1.83 + s = s.replace(/[<>&]/g, htmlesc); 1.84 + 1.85 + DocumentWrite(s); 1.86 +} 1.87 + 1.88 +function writeHeaderToLog( string ) { 1.89 + string = String(string); 1.90 + 1.91 + if (typeof dump == 'function') 1.92 + { 1.93 + dump( string + '\n'); 1.94 + } 1.95 + 1.96 + string = string.replace(/[<>&]/g, htmlesc); 1.97 + 1.98 + DocumentWrite( "<h2>" + string + "</h2>" ); 1.99 +} 1.100 + 1.101 +function writeFormattedResult( expect, actual, string, passed ) { 1.102 + string = String(string); 1.103 + 1.104 + if (typeof dump == 'function') 1.105 + { 1.106 + dump( string + '\n'); 1.107 + } 1.108 + 1.109 + string = string.replace(/[<>&]/g, htmlesc); 1.110 + 1.111 + var s = "<tt>"+ string ; 1.112 + s += "<b>" ; 1.113 + s += ( passed ) ? "<font color=#009900> " + PASSED 1.114 + : "<font color=#aa0000> " + FAILED + expect; 1.115 + 1.116 + DocumentWrite( s + "</font></b></tt><br>" ); 1.117 + return passed; 1.118 +} 1.119 + 1.120 +window.onerror = function (msg, page, line) 1.121 +{ 1.122 + jstestsTestPassesUnlessItThrows = false; 1.123 + 1.124 + // Restore options in case a test case used this common variable name. 1.125 + options = jstestsOptions; 1.126 + 1.127 + // Restore the ECMAScript environment after potentially destructive tests. 1.128 + if (typeof jstestsRestoreFunction === "function") { 1.129 + jstestsRestoreFunction(); 1.130 + } 1.131 + 1.132 + optionsPush(); 1.133 + 1.134 + if (typeof DESCRIPTION == 'undefined') 1.135 + { 1.136 + DESCRIPTION = 'Unknown'; 1.137 + } 1.138 + if (typeof EXPECTED == 'undefined') 1.139 + { 1.140 + EXPECTED = 'Unknown'; 1.141 + } 1.142 + 1.143 + var testcase = new TestCase("unknown-test-name", DESCRIPTION, EXPECTED, "error"); 1.144 + 1.145 + if (document.location.href.indexOf('-n.js') != -1) 1.146 + { 1.147 + // negative test 1.148 + testcase.passed = true; 1.149 + } 1.150 + 1.151 + testcase.reason = page + ':' + line + ': ' + msg; 1.152 + 1.153 + reportFailure(msg); 1.154 + 1.155 + optionsReset(); 1.156 +}; 1.157 + 1.158 +function gc() 1.159 +{ 1.160 + try 1.161 + { 1.162 + SpecialPowers.forceGC(); 1.163 + } 1.164 + catch(ex) 1.165 + { 1.166 + print('gc: ' + ex); 1.167 + } 1.168 +} 1.169 + 1.170 +function jsdgc() 1.171 +{ 1.172 + try 1.173 + { 1.174 + var jsdIDebuggerService = SpecialPowers.Ci.jsdIDebuggerService; 1.175 + var service = SpecialPowers.Cc['@mozilla.org/js/jsd/debugger-service;1']. 1.176 + getService(jsdIDebuggerService); 1.177 + service.GC(); 1.178 + } 1.179 + catch(ex) 1.180 + { 1.181 + print('jsdgc: ' + ex); 1.182 + } 1.183 +} 1.184 + 1.185 +function quit() 1.186 +{ 1.187 +} 1.188 + 1.189 +function options(aOptionName) 1.190 +{ 1.191 + // return value of options() is a comma delimited list 1.192 + // of the previously set values 1.193 + 1.194 + var value = ''; 1.195 + for (var optionName in options.currvalues) 1.196 + { 1.197 + value += optionName + ','; 1.198 + } 1.199 + if (value) 1.200 + { 1.201 + value = value.substring(0, value.length-1); 1.202 + } 1.203 + 1.204 + if (aOptionName) { 1.205 + if (!(aOptionName in SpecialPowers.Cu)) { 1.206 + // This test is trying to flip an unsupported option, so it's 1.207 + // likely no longer testing what it was supposed to. Fail it 1.208 + // hard. 1.209 + throw "Unsupported JSContext option '"+ aOptionName +"'"; 1.210 + } 1.211 + 1.212 + if (options.currvalues.hasOwnProperty(aOptionName)) 1.213 + // option is set, toggle it to unset 1.214 + delete options.currvalues[aOptionName]; 1.215 + else 1.216 + // option is not set, toggle it to set 1.217 + options.currvalues[aOptionName] = true; 1.218 + 1.219 + SpecialPowers.Cu[aOptionName] = 1.220 + options.currvalues.hasOwnProperty(aOptionName); 1.221 + } 1.222 + 1.223 + return value; 1.224 +} 1.225 + 1.226 +// Keep a reference to options around so that we can restore it after running 1.227 +// a test case, which may have used this common name for one of its own 1.228 +// variables. 1.229 +jstestsOptions = options; 1.230 + 1.231 +function optionsInit() { 1.232 + 1.233 + // hash containing the set options. 1.234 + options.currvalues = { 1.235 + strict: true, 1.236 + werror: true, 1.237 + strict_mode: true 1.238 + }; 1.239 + 1.240 + // record initial values to support resetting 1.241 + // options to their initial values 1.242 + options.initvalues = {}; 1.243 + 1.244 + // record values in a stack to support pushing 1.245 + // and popping options 1.246 + options.stackvalues = []; 1.247 + 1.248 + for (var optionName in options.currvalues) 1.249 + { 1.250 + var propName = optionName; 1.251 + 1.252 + if (!(propName in SpecialPowers.Cu)) 1.253 + { 1.254 + throw "options.currvalues is out of sync with Components.utils"; 1.255 + } 1.256 + if (!SpecialPowers.Cu[propName]) 1.257 + { 1.258 + delete options.currvalues[optionName]; 1.259 + } 1.260 + else 1.261 + { 1.262 + options.initvalues[optionName] = true; 1.263 + } 1.264 + } 1.265 +} 1.266 + 1.267 +function gczeal(z) 1.268 +{ 1.269 + SpecialPowers.setGCZeal(z); 1.270 +} 1.271 + 1.272 +function jit(on) 1.273 +{ 1.274 +} 1.275 + 1.276 +function jsTestDriverBrowserInit() 1.277 +{ 1.278 + 1.279 + if (typeof dump != 'function') 1.280 + { 1.281 + dump = print; 1.282 + } 1.283 + 1.284 + optionsInit(); 1.285 + optionsClear(); 1.286 + 1.287 + if (document.location.search.indexOf('?') != 0) 1.288 + { 1.289 + // not called with a query string 1.290 + return; 1.291 + } 1.292 + 1.293 + var properties = {}; 1.294 + var fields = document.location.search.slice(1).split(';'); 1.295 + for (var ifield = 0; ifield < fields.length; ifield++) 1.296 + { 1.297 + var propertycaptures = /^([^=]+)=(.*)$/.exec(fields[ifield]); 1.298 + if (!propertycaptures) 1.299 + { 1.300 + properties[fields[ifield]] = true; 1.301 + } 1.302 + else 1.303 + { 1.304 + properties[propertycaptures[1]] = decodeURIComponent(propertycaptures[2]); 1.305 + if (propertycaptures[1] == 'language') 1.306 + { 1.307 + // language=(type|language);mimetype 1.308 + properties.mimetype = fields[ifield+1]; 1.309 + } 1.310 + } 1.311 + } 1.312 + 1.313 + if (properties.language != 'type') 1.314 + { 1.315 + try 1.316 + { 1.317 + properties.version = /javascript([.0-9]+)/.exec(properties.mimetype)[1]; 1.318 + } 1.319 + catch(ex) 1.320 + { 1.321 + } 1.322 + } 1.323 + 1.324 + if (!properties.version && navigator.userAgent.indexOf('Gecko/') != -1) 1.325 + { 1.326 + // If the version is not specified, and the browser is Gecko, 1.327 + // use the default version corresponding to the shell's version(0). 1.328 + // See https://bugzilla.mozilla.org/show_bug.cgi?id=522760#c11 1.329 + // Otherwise adjust the version to match the suite version for 1.6, 1.330 + // and later due to the use of for-each, let, yield, etc. 1.331 + // 1.332 + // Note that js1_8, js1_8_1, and js1_8_5 are treated identically in 1.333 + // the browser. 1.334 + if (properties.test.match(/^js1_6/)) 1.335 + { 1.336 + properties.version = '1.6'; 1.337 + } 1.338 + else if (properties.test.match(/^js1_7/)) 1.339 + { 1.340 + properties.version = '1.7'; 1.341 + } 1.342 + else if (properties.test.match(/^js1_8/)) 1.343 + { 1.344 + properties.version = '1.8'; 1.345 + } 1.346 + } 1.347 + 1.348 + // default to language=type;text/javascript. required for 1.349 + // reftest style manifests. 1.350 + if (!properties.language) 1.351 + { 1.352 + properties.language = 'type'; 1.353 + properties.mimetype = 'text/javascript'; 1.354 + } 1.355 + 1.356 + gTestPath = properties.test; 1.357 + 1.358 + if (properties.gczeal) 1.359 + { 1.360 + gczeal(Number(properties.gczeal)); 1.361 + } 1.362 + 1.363 + /* 1.364 + * since the default setting of jit changed from false to true 1.365 + * in http://hg.mozilla.org/tracemonkey/rev/685e00e68be9 1.366 + * bisections which depend upon jit settings can be thrown off. 1.367 + * default jit(false) when not running jsreftests to make bisections 1.368 + * depending upon jit settings consistent over time. This is not needed 1.369 + * in shell tests as the default jit setting has not changed there. 1.370 + */ 1.371 + 1.372 + if (properties.jit || !document.location.href.match(/jsreftest.html/)) 1.373 + jit(properties.jit); 1.374 + 1.375 + var testpathparts = properties.test.split(/\//); 1.376 + 1.377 + if (testpathparts.length < 3) 1.378 + { 1.379 + // must have at least suitepath/subsuite/testcase.js 1.380 + return; 1.381 + } 1.382 + 1.383 + document.write('<title>' + properties.test + '<\/title>'); 1.384 + 1.385 + // XXX bc - the first document.written script is ignored if the protocol 1.386 + // is file:. insert an empty script tag, to work around it. 1.387 + document.write('<script></script>'); 1.388 + 1.389 + // Output script tags for shell.js, then browser.js, at each level of the 1.390 + // test path hierarchy. 1.391 + var prepath = ""; 1.392 + var i = 0; 1.393 + for (end = testpathparts.length - 1; i < end; i++) { 1.394 + prepath += testpathparts[i] + "/"; 1.395 + outputscripttag(prepath + "shell.js", properties); 1.396 + outputscripttag(prepath + "browser.js", properties); 1.397 + } 1.398 + 1.399 + // Output the test script itself. 1.400 + outputscripttag(prepath + testpathparts[i], properties); 1.401 + 1.402 + // Finally output the driver-end script to advance to the next test. 1.403 + outputscripttag('js-test-driver-end.js', properties); 1.404 + return; 1.405 +} 1.406 + 1.407 +function outputscripttag(src, properties) 1.408 +{ 1.409 + if (!src) 1.410 + { 1.411 + return; 1.412 + } 1.413 + 1.414 + var s = '<script src="' + src + '" charset="utf-8" '; 1.415 + 1.416 + if (properties.language != 'type') 1.417 + { 1.418 + s += 'language="javascript'; 1.419 + if (properties.version) 1.420 + { 1.421 + s += properties.version; 1.422 + } 1.423 + } 1.424 + else 1.425 + { 1.426 + s += 'type="' + properties.mimetype; 1.427 + if (properties.version) 1.428 + { 1.429 + s += ';version=' + properties.version; 1.430 + } 1.431 + } 1.432 + s += '"><\/script>'; 1.433 + 1.434 + document.write(s); 1.435 +} 1.436 + 1.437 +function jsTestDriverEnd() 1.438 +{ 1.439 + // gDelayTestDriverEnd is used to 1.440 + // delay collection of the test result and 1.441 + // signal to Spider so that tests can continue 1.442 + // to run after page load has fired. They are 1.443 + // responsible for setting gDelayTestDriverEnd = true 1.444 + // then when completed, setting gDelayTestDriverEnd = false 1.445 + // then calling jsTestDriverEnd() 1.446 + 1.447 + if (gDelayTestDriverEnd) 1.448 + { 1.449 + return; 1.450 + } 1.451 + 1.452 + window.onerror = null; 1.453 + 1.454 + // Restore options in case a test case used this common variable name. 1.455 + options = jstestsOptions; 1.456 + 1.457 + // Restore the ECMAScript environment after potentially destructive tests. 1.458 + if (typeof jstestsRestoreFunction === "function") { 1.459 + jstestsRestoreFunction(); 1.460 + } 1.461 + 1.462 + if (jstestsTestPassesUnlessItThrows) { 1.463 + var testcase = new TestCase("unknown-test-name", "", true, true); 1.464 + print(PASSED); 1.465 + jstestsTestPassesUnlessItThrows = false; 1.466 + } 1.467 + 1.468 + try 1.469 + { 1.470 + optionsReset(); 1.471 + } 1.472 + catch(ex) 1.473 + { 1.474 + dump('jsTestDriverEnd ' + ex); 1.475 + } 1.476 + 1.477 + if (window.opener && window.opener.runNextTest) 1.478 + { 1.479 + if (window.opener.reportCallBack) 1.480 + { 1.481 + window.opener.reportCallBack(window.opener.gWindow); 1.482 + } 1.483 + setTimeout('window.opener.runNextTest()', 250); 1.484 + } 1.485 + else 1.486 + { 1.487 + for (var i = 0; i < gTestcases.length; i++) 1.488 + { 1.489 + gTestcases[i].dump(); 1.490 + } 1.491 + 1.492 + // tell reftest the test is complete. 1.493 + document.documentElement.className = ''; 1.494 + // tell Spider page is complete 1.495 + gPageCompleted = true; 1.496 + } 1.497 +} 1.498 + 1.499 +//var dlog = (function (s) { print('debug: ' + s); }); 1.500 +var dlog = (function (s) {}); 1.501 + 1.502 +// dialog closer from http://bclary.com/projects/spider/spider/chrome/content/spider/dialog-closer.js 1.503 + 1.504 +var gDialogCloser; 1.505 +var gDialogCloserObserver; 1.506 + 1.507 +function registerDialogCloser() 1.508 +{ 1.509 + gDialogCloser = SpecialPowers. 1.510 + Cc['@mozilla.org/embedcomp/window-watcher;1']. 1.511 + getService(SpecialPowers.Ci.nsIWindowWatcher); 1.512 + 1.513 + gDialogCloserObserver = {observe: dialogCloser_observe}; 1.514 + 1.515 + gDialogCloser.registerNotification(gDialogCloserObserver); 1.516 +} 1.517 + 1.518 +function unregisterDialogCloser() 1.519 +{ 1.520 + gczeal(0); 1.521 + 1.522 + if (!gDialogCloserObserver || !gDialogCloser) 1.523 + { 1.524 + return; 1.525 + } 1.526 + 1.527 + gDialogCloser.unregisterNotification(gDialogCloserObserver); 1.528 + 1.529 + gDialogCloserObserver = null; 1.530 + gDialogCloser = null; 1.531 +} 1.532 + 1.533 +// use an array to handle the case where multiple dialogs 1.534 +// appear at one time 1.535 +var gDialogCloserSubjects = []; 1.536 + 1.537 +function dialogCloser_observe(subject, topic, data) 1.538 +{ 1.539 + if (subject instanceof ChromeWindow && topic == 'domwindowopened' ) 1.540 + { 1.541 + gDialogCloserSubjects.push(subject); 1.542 + // timeout of 0 needed when running under reftest framework. 1.543 + subject.setTimeout(closeDialog, 0); 1.544 + } 1.545 +} 1.546 + 1.547 +function closeDialog() 1.548 +{ 1.549 + var subject; 1.550 + 1.551 + while ( (subject = gDialogCloserSubjects.pop()) != null) 1.552 + { 1.553 + if (subject.document instanceof XULDocument && 1.554 + subject.document.documentURI == 'chrome://global/content/commonDialog.xul') 1.555 + { 1.556 + subject.close(); 1.557 + } 1.558 + else 1.559 + { 1.560 + // alerts inside of reftest framework are not XULDocument dialogs. 1.561 + subject.close(); 1.562 + } 1.563 + } 1.564 +} 1.565 + 1.566 +registerDialogCloser(); 1.567 +window.addEventListener('unload', unregisterDialogCloser, true); 1.568 + 1.569 +jsTestDriverBrowserInit();