1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/tests/shell.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,878 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; 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 +// Explicitly set the default version. 1.10 +// See https://bugzilla.mozilla.org/show_bug.cgi?id=522760#c11 1.11 +if (typeof version != 'undefined') 1.12 +{ 1.13 + version(0); 1.14 +} 1.15 + 1.16 +var STATUS = "STATUS: "; 1.17 +var VERBOSE = false; 1.18 +var SECT_PREFIX = 'Section '; 1.19 +var SECT_SUFFIX = ' of test - '; 1.20 +var callStack = new Array(); 1.21 + 1.22 +var gDelayTestDriverEnd = false; 1.23 + 1.24 +var gTestcases = new Array(); 1.25 +var gTc = gTestcases.length; 1.26 +var BUGNUMBER = ''; 1.27 +var summary = ''; 1.28 +var description = ''; 1.29 +var expected = ''; 1.30 +var actual = ''; 1.31 +var msg = ''; 1.32 + 1.33 +var SECTION = ""; 1.34 +var VERSION = ""; 1.35 +var BUGNUMBER = ""; 1.36 + 1.37 +/* 1.38 + * constant strings 1.39 + */ 1.40 +var GLOBAL = this + ''; 1.41 +var PASSED = " PASSED! "; 1.42 +var FAILED = " FAILED! "; 1.43 + 1.44 +var DEBUG = false; 1.45 + 1.46 +var DESCRIPTION; 1.47 +var EXPECTED; 1.48 + 1.49 +/* 1.50 + * Signals to results.py that the current test case should be considered to 1.51 + * have passed if it doesn't throw an exception. 1.52 + * 1.53 + * When the test suite is run in the browser, this function gets overridden by 1.54 + * the same-named function in browser.js. 1.55 + */ 1.56 +function testPassesUnlessItThrows() { 1.57 + print(PASSED); 1.58 +} 1.59 + 1.60 +/* 1.61 + * wrapper for test case constructor that doesn't require the SECTION 1.62 + * argument. 1.63 + */ 1.64 + 1.65 +function AddTestCase( description, expect, actual ) { 1.66 + new TestCase( SECTION, description, expect, actual ); 1.67 +} 1.68 + 1.69 +/* 1.70 + * Set up test environment. 1.71 + * 1.72 + */ 1.73 +function startTest() { 1.74 + // print out bugnumber 1.75 + 1.76 + if ( BUGNUMBER ) { 1.77 + print ("BUGNUMBER: " + BUGNUMBER ); 1.78 + } 1.79 +} 1.80 + 1.81 +function TestCase(n, d, e, a) 1.82 +{ 1.83 + this.name = n; 1.84 + this.description = d; 1.85 + this.expect = e; 1.86 + this.actual = a; 1.87 + this.passed = getTestCaseResult(e, a); 1.88 + this.reason = ''; 1.89 + this.bugnumber = typeof(BUGNUMER) != 'undefined' ? BUGNUMBER : ''; 1.90 + this.type = (typeof window == 'undefined' ? 'shell' : 'browser'); 1.91 + gTestcases[gTc++] = this; 1.92 +} 1.93 + 1.94 +gFailureExpected = false; 1.95 + 1.96 +TestCase.prototype.dump = function () { 1.97 + // let reftest handle error reporting, otherwise 1.98 + // output a summary line. 1.99 + if (typeof document != "object" || 1.100 + !document.location.href.match(/jsreftest.html/)) 1.101 + { 1.102 + dump('\njstest: ' + this.path + ' ' + 1.103 + 'bug: ' + this.bugnumber + ' ' + 1.104 + 'result: ' + (this.passed ? 'PASSED':'FAILED') + ' ' + 1.105 + 'type: ' + this.type + ' ' + 1.106 + 'description: ' + toPrinted(this.description) + ' ' + 1.107 +// 'expected: ' + toPrinted(this.expect) + ' ' + 1.108 +// 'actual: ' + toPrinted(this.actual) + ' ' + 1.109 + 'reason: ' + toPrinted(this.reason) + '\n'); 1.110 + } 1.111 +}; 1.112 + 1.113 +TestCase.prototype.testPassed = (function TestCase_testPassed() { return this.passed; }); 1.114 +TestCase.prototype.testFailed = (function TestCase_testFailed() { return !this.passed; }); 1.115 +TestCase.prototype.testDescription = (function TestCase_testDescription() { return this.description + ' ' + this.reason; }); 1.116 + 1.117 +function getTestCases() 1.118 +{ 1.119 + return gTestcases; 1.120 +} 1.121 + 1.122 +/* 1.123 + * The test driver searches for such a phrase in the test output. 1.124 + * If such phrase exists, it will set n as the expected exit code. 1.125 + */ 1.126 +function expectExitCode(n) 1.127 +{ 1.128 + print('--- NOTE: IN THIS TESTCASE, WE EXPECT EXIT CODE ' + n + ' ---'); 1.129 +} 1.130 + 1.131 +/* 1.132 + * Statuses current section of a test 1.133 + */ 1.134 +function inSection(x) 1.135 +{ 1.136 + return SECT_PREFIX + x + SECT_SUFFIX; 1.137 +} 1.138 + 1.139 +/* 1.140 + * Report a failure in the 'accepted' manner 1.141 + */ 1.142 +function reportFailure (msg) 1.143 +{ 1.144 + var lines = msg.split ("\n"); 1.145 + var l; 1.146 + var funcName = currentFunc(); 1.147 + var prefix = (funcName) ? "[reported from " + funcName + "] ": ""; 1.148 + 1.149 + for (var i=0; i<lines.length; i++) 1.150 + print (FAILED + prefix + lines[i]); 1.151 +} 1.152 + 1.153 +/* 1.154 + * Print a non-failure message. 1.155 + */ 1.156 +function printStatus (msg) 1.157 +{ 1.158 +/* js1_6 had... 1.159 + msg = String(msg); 1.160 + msg = msg.toString(); 1.161 +*/ 1.162 + msg = msg.toString(); 1.163 + var lines = msg.split ("\n"); 1.164 + var l; 1.165 + 1.166 + for (var i=0; i<lines.length; i++) 1.167 + print (STATUS + lines[i]); 1.168 +} 1.169 + 1.170 +/* 1.171 + * Print a bugnumber message. 1.172 + */ 1.173 +function printBugNumber (num) 1.174 +{ 1.175 + BUGNUMBER = num; 1.176 + print ('BUGNUMBER: ' + num); 1.177 +} 1.178 + 1.179 +function toPrinted(value) 1.180 +{ 1.181 + value = String(value); 1.182 + value = value.replace(/\\n/g, 'NL') 1.183 + .replace(/\n/g, 'NL') 1.184 + .replace(/\\r/g, 'CR') 1.185 + .replace(/[^\x20-\x7E]+/g, escapeString); 1.186 + return value; 1.187 +} 1.188 + 1.189 +function escapeString (str) 1.190 +{ 1.191 + var a, b, c, d; 1.192 + var len = str.length; 1.193 + var result = ""; 1.194 + var digits = ["0", "1", "2", "3", "4", "5", "6", "7", 1.195 + "8", "9", "A", "B", "C", "D", "E", "F"]; 1.196 + 1.197 + for (var i=0; i<len; i++) 1.198 + { 1.199 + var ch = str.charCodeAt(i); 1.200 + 1.201 + a = digits[ch & 0xf]; 1.202 + ch >>= 4; 1.203 + b = digits[ch & 0xf]; 1.204 + ch >>= 4; 1.205 + 1.206 + if (ch) 1.207 + { 1.208 + c = digits[ch & 0xf]; 1.209 + ch >>= 4; 1.210 + d = digits[ch & 0xf]; 1.211 + 1.212 + result += "\\u" + d + c + b + a; 1.213 + } 1.214 + else 1.215 + { 1.216 + result += "\\x" + b + a; 1.217 + } 1.218 + } 1.219 + 1.220 + return result; 1.221 +} 1.222 + 1.223 +/* 1.224 + * assertEq(actual, expected [, message]) 1.225 + * Throw if the two arguments are not the same. The sameness of two values 1.226 + * is determined as follows. If both values are zero, they are the same iff 1.227 + * their signs are the same. Otherwise, if both values are NaN, they are the 1.228 + * same. Otherwise, they are the same if they compare equal using ===. 1.229 + * see https://bugzilla.mozilla.org/show_bug.cgi?id=480199 and 1.230 + * https://bugzilla.mozilla.org/show_bug.cgi?id=515285 1.231 + */ 1.232 +if (typeof assertEq == 'undefined') 1.233 +{ 1.234 + var assertEq = 1.235 + function (actual, expected, message) 1.236 + { 1.237 + function SameValue(v1, v2) 1.238 + { 1.239 + if (v1 === 0 && v2 === 0) 1.240 + return 1 / v1 === 1 / v2; 1.241 + if (v1 !== v1 && v2 !== v2) 1.242 + return true; 1.243 + return v1 === v2; 1.244 + } 1.245 + if (!SameValue(actual, expected)) 1.246 + { 1.247 + throw new TypeError('Assertion failed: got "' + actual + '", expected "' + expected + 1.248 + (message ? ": " + message : "")); 1.249 + } 1.250 + }; 1.251 +} 1.252 + 1.253 +/* 1.254 + * Compare expected result to actual result, if they differ (in value and/or 1.255 + * type) report a failure. If description is provided, include it in the 1.256 + * failure report. 1.257 + */ 1.258 +function reportCompare (expected, actual, description) { 1.259 + var expected_t = typeof expected; 1.260 + var actual_t = typeof actual; 1.261 + var output = ""; 1.262 + 1.263 + if (typeof description == "undefined") 1.264 + { 1.265 + description = ''; 1.266 + } 1.267 + else if (VERBOSE) 1.268 + { 1.269 + printStatus ("Comparing '" + description + "'"); 1.270 + } 1.271 + 1.272 + if (expected_t != actual_t) 1.273 + { 1.274 + output += "Type mismatch, expected type " + expected_t + 1.275 + ", actual type " + actual_t + " "; 1.276 + } 1.277 + else if (VERBOSE) 1.278 + { 1.279 + printStatus ("Expected type '" + expected_t + "' matched actual " + 1.280 + "type '" + actual_t + "'"); 1.281 + } 1.282 + 1.283 + if (expected != actual) 1.284 + { 1.285 + output += "Expected value '" + toPrinted(expected) + 1.286 + "', Actual value '" + toPrinted(actual) + "' "; 1.287 + } 1.288 + else if (VERBOSE) 1.289 + { 1.290 + printStatus ("Expected value '" + toPrinted(expected) + 1.291 + "' matched actual value '" + toPrinted(actual) + "'"); 1.292 + } 1.293 + 1.294 + var testcase = new TestCase("unknown-test-name", description, expected, actual); 1.295 + testcase.reason = output; 1.296 + 1.297 + // if running under reftest, let it handle result reporting. 1.298 + if (typeof document != "object" || 1.299 + !document.location.href.match(/jsreftest.html/)) { 1.300 + if (testcase.passed) 1.301 + { 1.302 + print(PASSED + description); 1.303 + } 1.304 + else 1.305 + { 1.306 + reportFailure (description + " : " + output); 1.307 + } 1.308 + } 1.309 + return testcase.passed; 1.310 +} 1.311 + 1.312 +/* 1.313 + * Attempt to match a regular expression describing the result to 1.314 + * the actual result, if they differ (in value and/or 1.315 + * type) report a failure. If description is provided, include it in the 1.316 + * failure report. 1.317 + */ 1.318 +function reportMatch (expectedRegExp, actual, description) { 1.319 + var expected_t = "string"; 1.320 + var actual_t = typeof actual; 1.321 + var output = ""; 1.322 + 1.323 + if (typeof description == "undefined") 1.324 + { 1.325 + description = ''; 1.326 + } 1.327 + else if (VERBOSE) 1.328 + { 1.329 + printStatus ("Comparing '" + description + "'"); 1.330 + } 1.331 + 1.332 + if (expected_t != actual_t) 1.333 + { 1.334 + output += "Type mismatch, expected type " + expected_t + 1.335 + ", actual type " + actual_t + " "; 1.336 + } 1.337 + else if (VERBOSE) 1.338 + { 1.339 + printStatus ("Expected type '" + expected_t + "' matched actual " + 1.340 + "type '" + actual_t + "'"); 1.341 + } 1.342 + 1.343 + var matches = expectedRegExp.test(actual); 1.344 + if (!matches) 1.345 + { 1.346 + output += "Expected match to '" + toPrinted(expectedRegExp) + 1.347 + "', Actual value '" + toPrinted(actual) + "' "; 1.348 + } 1.349 + else if (VERBOSE) 1.350 + { 1.351 + printStatus ("Expected match to '" + toPrinted(expectedRegExp) + 1.352 + "' matched actual value '" + toPrinted(actual) + "'"); 1.353 + } 1.354 + 1.355 + var testcase = new TestCase("unknown-test-name", description, true, matches); 1.356 + testcase.reason = output; 1.357 + 1.358 + // if running under reftest, let it handle result reporting. 1.359 + if (typeof document != "object" || 1.360 + !document.location.href.match(/jsreftest.html/)) { 1.361 + if (testcase.passed) 1.362 + { 1.363 + print(PASSED + description); 1.364 + } 1.365 + else 1.366 + { 1.367 + reportFailure (description + " : " + output); 1.368 + } 1.369 + } 1.370 + return testcase.passed; 1.371 +} 1.372 + 1.373 +/* 1.374 + * Puts funcName at the top of the call stack. This stack is used to show 1.375 + * a function-reported-from field when reporting failures. 1.376 + */ 1.377 +function enterFunc (funcName) 1.378 +{ 1.379 + if (!funcName.match(/\(\)$/)) 1.380 + funcName += "()"; 1.381 + 1.382 + callStack.push(funcName); 1.383 +} 1.384 + 1.385 +/* 1.386 + * Pops the top funcName off the call stack. funcName is optional, and can be 1.387 + * used to check push-pop balance. 1.388 + */ 1.389 +function exitFunc (funcName) 1.390 +{ 1.391 + var lastFunc = callStack.pop(); 1.392 + 1.393 + if (funcName) 1.394 + { 1.395 + if (!funcName.match(/\(\)$/)) 1.396 + funcName += "()"; 1.397 + 1.398 + if (lastFunc != funcName) 1.399 + reportCompare(funcName, lastFunc, "Test driver failure wrong exit function "); 1.400 + } 1.401 +} 1.402 + 1.403 +/* 1.404 + * Peeks at the top of the call stack. 1.405 + */ 1.406 +function currentFunc() 1.407 +{ 1.408 + return callStack[callStack.length - 1]; 1.409 +} 1.410 + 1.411 +/* 1.412 + Calculate the "order" of a set of data points {X: [], Y: []} 1.413 + by computing successive "derivatives" of the data until 1.414 + the data is exhausted or the derivative is linear. 1.415 +*/ 1.416 +function BigO(data) 1.417 +{ 1.418 + var order = 0; 1.419 + var origLength = data.X.length; 1.420 + 1.421 + while (data.X.length > 2) 1.422 + { 1.423 + var lr = new LinearRegression(data); 1.424 + if (lr.b > 1e-6) 1.425 + { 1.426 + // only increase the order if the slope 1.427 + // is "great" enough 1.428 + order++; 1.429 + } 1.430 + 1.431 + if (lr.r > 0.98 || lr.Syx < 1 || lr.b < 1e-6) 1.432 + { 1.433 + // terminate if close to a line lr.r 1.434 + // small error lr.Syx 1.435 + // small slope lr.b 1.436 + break; 1.437 + } 1.438 + data = dataDeriv(data); 1.439 + } 1.440 + 1.441 + if (2 == origLength - order) 1.442 + { 1.443 + order = Number.POSITIVE_INFINITY; 1.444 + } 1.445 + return order; 1.446 + 1.447 + function LinearRegression(data) 1.448 + { 1.449 + /* 1.450 + y = a + bx 1.451 + for data points (Xi, Yi); 0 <= i < n 1.452 + 1.453 + b = (n*SUM(XiYi) - SUM(Xi)*SUM(Yi))/(n*SUM(Xi*Xi) - SUM(Xi)*SUM(Xi)) 1.454 + a = (SUM(Yi) - b*SUM(Xi))/n 1.455 + */ 1.456 + var i; 1.457 + 1.458 + if (data.X.length != data.Y.length) 1.459 + { 1.460 + throw 'LinearRegression: data point length mismatch'; 1.461 + } 1.462 + if (data.X.length < 3) 1.463 + { 1.464 + throw 'LinearRegression: data point length < 2'; 1.465 + } 1.466 + var n = data.X.length; 1.467 + var X = data.X; 1.468 + var Y = data.Y; 1.469 + 1.470 + this.Xavg = 0; 1.471 + this.Yavg = 0; 1.472 + 1.473 + var SUM_X = 0; 1.474 + var SUM_XY = 0; 1.475 + var SUM_XX = 0; 1.476 + var SUM_Y = 0; 1.477 + var SUM_YY = 0; 1.478 + 1.479 + for (i = 0; i < n; i++) 1.480 + { 1.481 + SUM_X += X[i]; 1.482 + SUM_XY += X[i]*Y[i]; 1.483 + SUM_XX += X[i]*X[i]; 1.484 + SUM_Y += Y[i]; 1.485 + SUM_YY += Y[i]*Y[i]; 1.486 + } 1.487 + 1.488 + this.b = (n * SUM_XY - SUM_X * SUM_Y)/(n * SUM_XX - SUM_X * SUM_X); 1.489 + this.a = (SUM_Y - this.b * SUM_X)/n; 1.490 + 1.491 + this.Xavg = SUM_X/n; 1.492 + this.Yavg = SUM_Y/n; 1.493 + 1.494 + var SUM_Ydiff2 = 0; 1.495 + var SUM_Xdiff2 = 0; 1.496 + var SUM_XdiffYdiff = 0; 1.497 + 1.498 + for (i = 0; i < n; i++) 1.499 + { 1.500 + var Ydiff = Y[i] - this.Yavg; 1.501 + var Xdiff = X[i] - this.Xavg; 1.502 + 1.503 + SUM_Ydiff2 += Ydiff * Ydiff; 1.504 + SUM_Xdiff2 += Xdiff * Xdiff; 1.505 + SUM_XdiffYdiff += Xdiff * Ydiff; 1.506 + } 1.507 + 1.508 + var Syx2 = (SUM_Ydiff2 - Math.pow(SUM_XdiffYdiff/SUM_Xdiff2, 2))/(n - 2); 1.509 + var r2 = Math.pow((n*SUM_XY - SUM_X * SUM_Y), 2) / 1.510 + ((n*SUM_XX - SUM_X*SUM_X)*(n*SUM_YY-SUM_Y*SUM_Y)); 1.511 + 1.512 + this.Syx = Math.sqrt(Syx2); 1.513 + this.r = Math.sqrt(r2); 1.514 + 1.515 + } 1.516 + 1.517 + function dataDeriv(data) 1.518 + { 1.519 + if (data.X.length != data.Y.length) 1.520 + { 1.521 + throw 'length mismatch'; 1.522 + } 1.523 + var length = data.X.length; 1.524 + 1.525 + if (length < 2) 1.526 + { 1.527 + throw 'length ' + length + ' must be >= 2'; 1.528 + } 1.529 + var X = data.X; 1.530 + var Y = data.Y; 1.531 + 1.532 + var deriv = {X: [], Y: [] }; 1.533 + 1.534 + for (var i = 0; i < length - 1; i++) 1.535 + { 1.536 + deriv.X[i] = (X[i] + X[i+1])/2; 1.537 + deriv.Y[i] = (Y[i+1] - Y[i])/(X[i+1] - X[i]); 1.538 + } 1.539 + return deriv; 1.540 + } 1.541 + 1.542 + return 0; 1.543 +} 1.544 + 1.545 +function compareSource(expect, actual, summary) 1.546 +{ 1.547 + // compare source 1.548 + var expectP = expect. 1.549 + replace(/([(){},.:\[\]])/mg, ' $1 '). 1.550 + replace(/(\w+)/mg, ' $1 '). 1.551 + replace(/<(\/)? (\w+) (\/)?>/mg, '<$1$2$3>'). 1.552 + replace(/\s+/mg, ' '). 1.553 + replace(/new (\w+)\s*\(\s*\)/mg, 'new $1'); 1.554 + 1.555 + var actualP = actual. 1.556 + replace(/([(){},.:\[\]])/mg, ' $1 '). 1.557 + replace(/(\w+)/mg, ' $1 '). 1.558 + replace(/<(\/)? (\w+) (\/)?>/mg, '<$1$2$3>'). 1.559 + replace(/\s+/mg, ' '). 1.560 + replace(/new (\w+)\s*\(\s*\)/mg, 'new $1'); 1.561 + 1.562 + print('expect:\n' + expectP); 1.563 + print('actual:\n' + actualP); 1.564 + 1.565 + reportCompare(expectP, actualP, summary); 1.566 + 1.567 + // actual must be compilable if expect is? 1.568 + try 1.569 + { 1.570 + var expectCompile = 'No Error'; 1.571 + var actualCompile; 1.572 + 1.573 + eval(expect); 1.574 + try 1.575 + { 1.576 + eval(actual); 1.577 + actualCompile = 'No Error'; 1.578 + } 1.579 + catch(ex1) 1.580 + { 1.581 + actualCompile = ex1 + ''; 1.582 + } 1.583 + reportCompare(expectCompile, actualCompile, 1.584 + summary + ': compile actual'); 1.585 + } 1.586 + catch(ex) 1.587 + { 1.588 + } 1.589 +} 1.590 + 1.591 +function optionsInit() { 1.592 + 1.593 + // record initial values to support resetting 1.594 + // options to their initial values 1.595 + options.initvalues = {}; 1.596 + 1.597 + // record values in a stack to support pushing 1.598 + // and popping options 1.599 + options.stackvalues = []; 1.600 + 1.601 + var optionNames = options().split(','); 1.602 + 1.603 + for (var i = 0; i < optionNames.length; i++) 1.604 + { 1.605 + var optionName = optionNames[i]; 1.606 + if (optionName) 1.607 + { 1.608 + options.initvalues[optionName] = ''; 1.609 + } 1.610 + } 1.611 +} 1.612 + 1.613 +function optionsClear() { 1.614 + 1.615 + // turn off current settings 1.616 + // except jit. 1.617 + var optionNames = options().split(','); 1.618 + for (var i = 0; i < optionNames.length; i++) 1.619 + { 1.620 + var optionName = optionNames[i]; 1.621 + if (optionName && 1.622 + optionName != "methodjit" && 1.623 + optionName != "methodjit_always" && 1.624 + optionName != "ion") 1.625 + { 1.626 + options(optionName); 1.627 + } 1.628 + } 1.629 +} 1.630 + 1.631 +function optionsPush() 1.632 +{ 1.633 + var optionsframe = {}; 1.634 + 1.635 + options.stackvalues.push(optionsframe); 1.636 + 1.637 + var optionNames = options().split(','); 1.638 + 1.639 + for (var i = 0; i < optionNames.length; i++) 1.640 + { 1.641 + var optionName = optionNames[i]; 1.642 + if (optionName) 1.643 + { 1.644 + optionsframe[optionName] = ''; 1.645 + } 1.646 + } 1.647 + 1.648 + optionsClear(); 1.649 +} 1.650 + 1.651 +function optionsPop() 1.652 +{ 1.653 + var optionsframe = options.stackvalues.pop(); 1.654 + 1.655 + optionsClear(); 1.656 + 1.657 + for (optionName in optionsframe) 1.658 + { 1.659 + options(optionName); 1.660 + } 1.661 + 1.662 +} 1.663 + 1.664 +function optionsReset() { 1.665 + 1.666 + try 1.667 + { 1.668 + optionsClear(); 1.669 + 1.670 + // turn on initial settings 1.671 + for (var optionName in options.initvalues) 1.672 + { 1.673 + if (!options.hasOwnProperty(optionName)) 1.674 + continue; 1.675 + options(optionName); 1.676 + } 1.677 + } 1.678 + catch(ex) 1.679 + { 1.680 + print('optionsReset: caught ' + ex); 1.681 + } 1.682 + 1.683 +} 1.684 + 1.685 +if (typeof options == 'function') 1.686 +{ 1.687 + optionsInit(); 1.688 + optionsClear(); 1.689 +} 1.690 + 1.691 +function getTestCaseResult(expected, actual) 1.692 +{ 1.693 + if (typeof expected != typeof actual) 1.694 + return false; 1.695 + if (typeof expected != 'number') 1.696 + // Note that many tests depend on the use of '==' here, not '==='. 1.697 + return actual == expected; 1.698 + 1.699 + // Distinguish NaN from other values. Using x != x comparisons here 1.700 + // works even if tests redefine isNaN. 1.701 + if (actual != actual) 1.702 + return expected != expected; 1.703 + if (expected != expected) 1.704 + return false; 1.705 + 1.706 + // Tolerate a certain degree of error. 1.707 + if (actual != expected) 1.708 + return Math.abs(actual - expected) <= 1E-10; 1.709 + 1.710 + // Here would be a good place to distinguish 0 and -0, if we wanted 1.711 + // to. However, doing so would introduce a number of failures in 1.712 + // areas where they don't seem important. For example, the WeekDay 1.713 + // function in ECMA-262 returns -0 for Sundays before the epoch, but 1.714 + // the Date functions in SpiderMonkey specified in terms of WeekDay 1.715 + // often don't. This seems unimportant. 1.716 + return true; 1.717 +} 1.718 + 1.719 +if (typeof dump == 'undefined') 1.720 +{ 1.721 + if (typeof window == 'undefined' && 1.722 + typeof print == 'function') 1.723 + { 1.724 + dump = print; 1.725 + } 1.726 + else 1.727 + { 1.728 + dump = (function () {}); 1.729 + } 1.730 +} 1.731 + 1.732 +function test() { 1.733 + for ( gTc=0; gTc < gTestcases.length; gTc++ ) { 1.734 + // temporary hack to work around some unknown issue in 1.7 1.735 + try 1.736 + { 1.737 + gTestcases[gTc].passed = writeTestCaseResult( 1.738 + gTestcases[gTc].expect, 1.739 + gTestcases[gTc].actual, 1.740 + gTestcases[gTc].description +" = "+ gTestcases[gTc].actual ); 1.741 + gTestcases[gTc].reason += ( gTestcases[gTc].passed ) ? "" : "wrong value "; 1.742 + } 1.743 + catch(e) 1.744 + { 1.745 + print('test(): empty testcase for gTc = ' + gTc + ' ' + e); 1.746 + } 1.747 + } 1.748 + stopTest(); 1.749 + return ( gTestcases ); 1.750 +} 1.751 + 1.752 +/* 1.753 + * Begin printing functions. These functions use the shell's 1.754 + * print function. When running tests in the browser, these 1.755 + * functions, override these functions with functions that use 1.756 + * document.write. 1.757 + */ 1.758 + 1.759 +function writeTestCaseResult( expect, actual, string ) { 1.760 + var passed = getTestCaseResult( expect, actual ); 1.761 + // if running under reftest, let it handle result reporting. 1.762 + if (typeof document != "object" || 1.763 + !document.location.href.match(/jsreftest.html/)) { 1.764 + writeFormattedResult( expect, actual, string, passed ); 1.765 + } 1.766 + return passed; 1.767 +} 1.768 +function writeFormattedResult( expect, actual, string, passed ) { 1.769 + var s = ( passed ? PASSED : FAILED ) + string + ' expected: ' + expect; 1.770 + print(s); 1.771 + return passed; 1.772 +} 1.773 + 1.774 +function writeHeaderToLog( string ) { 1.775 + print( string ); 1.776 +} 1.777 +/* end of print functions */ 1.778 + 1.779 + 1.780 +/* 1.781 + * When running in the shell, run the garbage collector after the 1.782 + * test has completed. 1.783 + */ 1.784 + 1.785 +function stopTest() { 1.786 + var gc; 1.787 + if ( gc != undefined ) { 1.788 + gc(); 1.789 + } 1.790 +} 1.791 + 1.792 +/* 1.793 + * Convenience function for displaying failed test cases. Useful 1.794 + * when running tests manually. 1.795 + * 1.796 + */ 1.797 +function getFailedCases() { 1.798 + for ( var i = 0; i < gTestcases.length; i++ ) { 1.799 + if ( ! gTestcases[i].passed ) { 1.800 + print( gTestcases[i].description + " = " +gTestcases[i].actual + 1.801 + " expected: " + gTestcases[i].expect ); 1.802 + } 1.803 + } 1.804 +} 1.805 + 1.806 +function jsTestDriverEnd() 1.807 +{ 1.808 + // gDelayTestDriverEnd is used to 1.809 + // delay collection of the test result and 1.810 + // signal to Spider so that tests can continue 1.811 + // to run after page load has fired. They are 1.812 + // responsible for setting gDelayTestDriverEnd = true 1.813 + // then when completed, setting gDelayTestDriverEnd = false 1.814 + // then calling jsTestDriverEnd() 1.815 + 1.816 + if (gDelayTestDriverEnd) 1.817 + { 1.818 + return; 1.819 + } 1.820 + 1.821 + try 1.822 + { 1.823 + optionsReset(); 1.824 + } 1.825 + catch(ex) 1.826 + { 1.827 + dump('jsTestDriverEnd ' + ex); 1.828 + } 1.829 + 1.830 + for (var i = 0; i < gTestcases.length; i++) 1.831 + { 1.832 + gTestcases[i].dump(); 1.833 + } 1.834 + 1.835 +} 1.836 + 1.837 +function jit(on) 1.838 +{ 1.839 +} 1.840 + 1.841 +function assertEqArray(a1, a2) { 1.842 + assertEq(a1.length, a2.length); 1.843 + for (var i = 0; i < a1.length; i++) { 1.844 + try { 1.845 + assertEq(a1[i], a2[i]); 1.846 + } catch (e) { 1.847 + throw new Error("At index " + i + ": " + e); 1.848 + } 1.849 + } 1.850 +} 1.851 + 1.852 +function assertThrows(f) { 1.853 + var ok = false; 1.854 + try { 1.855 + f(); 1.856 + } catch (exc) { 1.857 + ok = true; 1.858 + } 1.859 + if (!ok) 1.860 + throw new Error("Assertion failed: " + f + " did not throw as expected"); 1.861 +} 1.862 + 1.863 +/* 1.864 + * Some tests need to know if we are in Rhino as opposed to SpiderMonkey 1.865 + */ 1.866 +function inRhino() 1.867 +{ 1.868 + return (typeof defineClass == "function"); 1.869 +} 1.870 + 1.871 +/* these functions are useful for running tests manually in Rhino */ 1.872 + 1.873 +function GetContext() { 1.874 + return Packages.com.netscape.javascript.Context.getCurrentContext(); 1.875 +} 1.876 +function OptLevel( i ) { 1.877 + i = Number(i); 1.878 + var cx = GetContext(); 1.879 + cx.setOptimizationLevel(i); 1.880 +} 1.881 +/* end of Rhino functions */