michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Explicitly set the default version. michael@0: // See https://bugzilla.mozilla.org/show_bug.cgi?id=522760#c11 michael@0: if (typeof version != 'undefined') michael@0: { michael@0: version(0); michael@0: } michael@0: michael@0: var STATUS = "STATUS: "; michael@0: var VERBOSE = false; michael@0: var SECT_PREFIX = 'Section '; michael@0: var SECT_SUFFIX = ' of test - '; michael@0: var callStack = new Array(); michael@0: michael@0: var gDelayTestDriverEnd = false; michael@0: michael@0: var gTestcases = new Array(); michael@0: var gTc = gTestcases.length; michael@0: var BUGNUMBER = ''; michael@0: var summary = ''; michael@0: var description = ''; michael@0: var expected = ''; michael@0: var actual = ''; michael@0: var msg = ''; michael@0: michael@0: var SECTION = ""; michael@0: var VERSION = ""; michael@0: var BUGNUMBER = ""; michael@0: michael@0: /* michael@0: * constant strings michael@0: */ michael@0: var GLOBAL = this + ''; michael@0: var PASSED = " PASSED! "; michael@0: var FAILED = " FAILED! "; michael@0: michael@0: var DEBUG = false; michael@0: michael@0: var DESCRIPTION; michael@0: var EXPECTED; michael@0: michael@0: /* michael@0: * Signals to results.py that the current test case should be considered to michael@0: * have passed if it doesn't throw an exception. michael@0: * michael@0: * When the test suite is run in the browser, this function gets overridden by michael@0: * the same-named function in browser.js. michael@0: */ michael@0: function testPassesUnlessItThrows() { michael@0: print(PASSED); michael@0: } michael@0: michael@0: /* michael@0: * wrapper for test case constructor that doesn't require the SECTION michael@0: * argument. michael@0: */ michael@0: michael@0: function AddTestCase( description, expect, actual ) { michael@0: new TestCase( SECTION, description, expect, actual ); michael@0: } michael@0: michael@0: /* michael@0: * Set up test environment. michael@0: * michael@0: */ michael@0: function startTest() { michael@0: // print out bugnumber michael@0: michael@0: if ( BUGNUMBER ) { michael@0: print ("BUGNUMBER: " + BUGNUMBER ); michael@0: } michael@0: } michael@0: michael@0: function TestCase(n, d, e, a) michael@0: { michael@0: this.name = n; michael@0: this.description = d; michael@0: this.expect = e; michael@0: this.actual = a; michael@0: this.passed = getTestCaseResult(e, a); michael@0: this.reason = ''; michael@0: this.bugnumber = typeof(BUGNUMER) != 'undefined' ? BUGNUMBER : ''; michael@0: this.type = (typeof window == 'undefined' ? 'shell' : 'browser'); michael@0: gTestcases[gTc++] = this; michael@0: } michael@0: michael@0: gFailureExpected = false; michael@0: michael@0: TestCase.prototype.dump = function () { michael@0: // let reftest handle error reporting, otherwise michael@0: // output a summary line. michael@0: if (typeof document != "object" || michael@0: !document.location.href.match(/jsreftest.html/)) michael@0: { michael@0: dump('\njstest: ' + this.path + ' ' + michael@0: 'bug: ' + this.bugnumber + ' ' + michael@0: 'result: ' + (this.passed ? 'PASSED':'FAILED') + ' ' + michael@0: 'type: ' + this.type + ' ' + michael@0: 'description: ' + toPrinted(this.description) + ' ' + michael@0: // 'expected: ' + toPrinted(this.expect) + ' ' + michael@0: // 'actual: ' + toPrinted(this.actual) + ' ' + michael@0: 'reason: ' + toPrinted(this.reason) + '\n'); michael@0: } michael@0: }; michael@0: michael@0: TestCase.prototype.testPassed = (function TestCase_testPassed() { return this.passed; }); michael@0: TestCase.prototype.testFailed = (function TestCase_testFailed() { return !this.passed; }); michael@0: TestCase.prototype.testDescription = (function TestCase_testDescription() { return this.description + ' ' + this.reason; }); michael@0: michael@0: function getTestCases() michael@0: { michael@0: return gTestcases; michael@0: } michael@0: michael@0: /* michael@0: * The test driver searches for such a phrase in the test output. michael@0: * If such phrase exists, it will set n as the expected exit code. michael@0: */ michael@0: function expectExitCode(n) michael@0: { michael@0: print('--- NOTE: IN THIS TESTCASE, WE EXPECT EXIT CODE ' + n + ' ---'); michael@0: } michael@0: michael@0: /* michael@0: * Statuses current section of a test michael@0: */ michael@0: function inSection(x) michael@0: { michael@0: return SECT_PREFIX + x + SECT_SUFFIX; michael@0: } michael@0: michael@0: /* michael@0: * Report a failure in the 'accepted' manner michael@0: */ michael@0: function reportFailure (msg) michael@0: { michael@0: var lines = msg.split ("\n"); michael@0: var l; michael@0: var funcName = currentFunc(); michael@0: var prefix = (funcName) ? "[reported from " + funcName + "] ": ""; michael@0: michael@0: for (var i=0; i>= 4; michael@0: b = digits[ch & 0xf]; michael@0: ch >>= 4; michael@0: michael@0: if (ch) michael@0: { michael@0: c = digits[ch & 0xf]; michael@0: ch >>= 4; michael@0: d = digits[ch & 0xf]; michael@0: michael@0: result += "\\u" + d + c + b + a; michael@0: } michael@0: else michael@0: { michael@0: result += "\\x" + b + a; michael@0: } michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: /* michael@0: * assertEq(actual, expected [, message]) michael@0: * Throw if the two arguments are not the same. The sameness of two values michael@0: * is determined as follows. If both values are zero, they are the same iff michael@0: * their signs are the same. Otherwise, if both values are NaN, they are the michael@0: * same. Otherwise, they are the same if they compare equal using ===. michael@0: * see https://bugzilla.mozilla.org/show_bug.cgi?id=480199 and michael@0: * https://bugzilla.mozilla.org/show_bug.cgi?id=515285 michael@0: */ michael@0: if (typeof assertEq == 'undefined') michael@0: { michael@0: var assertEq = michael@0: function (actual, expected, message) michael@0: { michael@0: function SameValue(v1, v2) michael@0: { michael@0: if (v1 === 0 && v2 === 0) michael@0: return 1 / v1 === 1 / v2; michael@0: if (v1 !== v1 && v2 !== v2) michael@0: return true; michael@0: return v1 === v2; michael@0: } michael@0: if (!SameValue(actual, expected)) michael@0: { michael@0: throw new TypeError('Assertion failed: got "' + actual + '", expected "' + expected + michael@0: (message ? ": " + message : "")); michael@0: } michael@0: }; michael@0: } michael@0: michael@0: /* michael@0: * Compare expected result to actual result, if they differ (in value and/or michael@0: * type) report a failure. If description is provided, include it in the michael@0: * failure report. michael@0: */ michael@0: function reportCompare (expected, actual, description) { michael@0: var expected_t = typeof expected; michael@0: var actual_t = typeof actual; michael@0: var output = ""; michael@0: michael@0: if (typeof description == "undefined") michael@0: { michael@0: description = ''; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Comparing '" + description + "'"); michael@0: } michael@0: michael@0: if (expected_t != actual_t) michael@0: { michael@0: output += "Type mismatch, expected type " + expected_t + michael@0: ", actual type " + actual_t + " "; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Expected type '" + expected_t + "' matched actual " + michael@0: "type '" + actual_t + "'"); michael@0: } michael@0: michael@0: if (expected != actual) michael@0: { michael@0: output += "Expected value '" + toPrinted(expected) + michael@0: "', Actual value '" + toPrinted(actual) + "' "; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Expected value '" + toPrinted(expected) + michael@0: "' matched actual value '" + toPrinted(actual) + "'"); michael@0: } michael@0: michael@0: var testcase = new TestCase("unknown-test-name", description, expected, actual); michael@0: testcase.reason = output; michael@0: michael@0: // if running under reftest, let it handle result reporting. michael@0: if (typeof document != "object" || michael@0: !document.location.href.match(/jsreftest.html/)) { michael@0: if (testcase.passed) michael@0: { michael@0: print(PASSED + description); michael@0: } michael@0: else michael@0: { michael@0: reportFailure (description + " : " + output); michael@0: } michael@0: } michael@0: return testcase.passed; michael@0: } michael@0: michael@0: /* michael@0: * Attempt to match a regular expression describing the result to michael@0: * the actual result, if they differ (in value and/or michael@0: * type) report a failure. If description is provided, include it in the michael@0: * failure report. michael@0: */ michael@0: function reportMatch (expectedRegExp, actual, description) { michael@0: var expected_t = "string"; michael@0: var actual_t = typeof actual; michael@0: var output = ""; michael@0: michael@0: if (typeof description == "undefined") michael@0: { michael@0: description = ''; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Comparing '" + description + "'"); michael@0: } michael@0: michael@0: if (expected_t != actual_t) michael@0: { michael@0: output += "Type mismatch, expected type " + expected_t + michael@0: ", actual type " + actual_t + " "; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Expected type '" + expected_t + "' matched actual " + michael@0: "type '" + actual_t + "'"); michael@0: } michael@0: michael@0: var matches = expectedRegExp.test(actual); michael@0: if (!matches) michael@0: { michael@0: output += "Expected match to '" + toPrinted(expectedRegExp) + michael@0: "', Actual value '" + toPrinted(actual) + "' "; michael@0: } michael@0: else if (VERBOSE) michael@0: { michael@0: printStatus ("Expected match to '" + toPrinted(expectedRegExp) + michael@0: "' matched actual value '" + toPrinted(actual) + "'"); michael@0: } michael@0: michael@0: var testcase = new TestCase("unknown-test-name", description, true, matches); michael@0: testcase.reason = output; michael@0: michael@0: // if running under reftest, let it handle result reporting. michael@0: if (typeof document != "object" || michael@0: !document.location.href.match(/jsreftest.html/)) { michael@0: if (testcase.passed) michael@0: { michael@0: print(PASSED + description); michael@0: } michael@0: else michael@0: { michael@0: reportFailure (description + " : " + output); michael@0: } michael@0: } michael@0: return testcase.passed; michael@0: } michael@0: michael@0: /* michael@0: * Puts funcName at the top of the call stack. This stack is used to show michael@0: * a function-reported-from field when reporting failures. michael@0: */ michael@0: function enterFunc (funcName) michael@0: { michael@0: if (!funcName.match(/\(\)$/)) michael@0: funcName += "()"; michael@0: michael@0: callStack.push(funcName); michael@0: } michael@0: michael@0: /* michael@0: * Pops the top funcName off the call stack. funcName is optional, and can be michael@0: * used to check push-pop balance. michael@0: */ michael@0: function exitFunc (funcName) michael@0: { michael@0: var lastFunc = callStack.pop(); michael@0: michael@0: if (funcName) michael@0: { michael@0: if (!funcName.match(/\(\)$/)) michael@0: funcName += "()"; michael@0: michael@0: if (lastFunc != funcName) michael@0: reportCompare(funcName, lastFunc, "Test driver failure wrong exit function "); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Peeks at the top of the call stack. michael@0: */ michael@0: function currentFunc() michael@0: { michael@0: return callStack[callStack.length - 1]; michael@0: } michael@0: michael@0: /* michael@0: Calculate the "order" of a set of data points {X: [], Y: []} michael@0: by computing successive "derivatives" of the data until michael@0: the data is exhausted or the derivative is linear. michael@0: */ michael@0: function BigO(data) michael@0: { michael@0: var order = 0; michael@0: var origLength = data.X.length; michael@0: michael@0: while (data.X.length > 2) michael@0: { michael@0: var lr = new LinearRegression(data); michael@0: if (lr.b > 1e-6) michael@0: { michael@0: // only increase the order if the slope michael@0: // is "great" enough michael@0: order++; michael@0: } michael@0: michael@0: if (lr.r > 0.98 || lr.Syx < 1 || lr.b < 1e-6) michael@0: { michael@0: // terminate if close to a line lr.r michael@0: // small error lr.Syx michael@0: // small slope lr.b michael@0: break; michael@0: } michael@0: data = dataDeriv(data); michael@0: } michael@0: michael@0: if (2 == origLength - order) michael@0: { michael@0: order = Number.POSITIVE_INFINITY; michael@0: } michael@0: return order; michael@0: michael@0: function LinearRegression(data) michael@0: { michael@0: /* michael@0: y = a + bx michael@0: for data points (Xi, Yi); 0 <= i < n michael@0: michael@0: b = (n*SUM(XiYi) - SUM(Xi)*SUM(Yi))/(n*SUM(Xi*Xi) - SUM(Xi)*SUM(Xi)) michael@0: a = (SUM(Yi) - b*SUM(Xi))/n michael@0: */ michael@0: var i; michael@0: michael@0: if (data.X.length != data.Y.length) michael@0: { michael@0: throw 'LinearRegression: data point length mismatch'; michael@0: } michael@0: if (data.X.length < 3) michael@0: { michael@0: throw 'LinearRegression: data point length < 2'; michael@0: } michael@0: var n = data.X.length; michael@0: var X = data.X; michael@0: var Y = data.Y; michael@0: michael@0: this.Xavg = 0; michael@0: this.Yavg = 0; michael@0: michael@0: var SUM_X = 0; michael@0: var SUM_XY = 0; michael@0: var SUM_XX = 0; michael@0: var SUM_Y = 0; michael@0: var SUM_YY = 0; michael@0: michael@0: for (i = 0; i < n; i++) michael@0: { michael@0: SUM_X += X[i]; michael@0: SUM_XY += X[i]*Y[i]; michael@0: SUM_XX += X[i]*X[i]; michael@0: SUM_Y += Y[i]; michael@0: SUM_YY += Y[i]*Y[i]; michael@0: } michael@0: michael@0: this.b = (n * SUM_XY - SUM_X * SUM_Y)/(n * SUM_XX - SUM_X * SUM_X); michael@0: this.a = (SUM_Y - this.b * SUM_X)/n; michael@0: michael@0: this.Xavg = SUM_X/n; michael@0: this.Yavg = SUM_Y/n; michael@0: michael@0: var SUM_Ydiff2 = 0; michael@0: var SUM_Xdiff2 = 0; michael@0: var SUM_XdiffYdiff = 0; michael@0: michael@0: for (i = 0; i < n; i++) michael@0: { michael@0: var Ydiff = Y[i] - this.Yavg; michael@0: var Xdiff = X[i] - this.Xavg; michael@0: michael@0: SUM_Ydiff2 += Ydiff * Ydiff; michael@0: SUM_Xdiff2 += Xdiff * Xdiff; michael@0: SUM_XdiffYdiff += Xdiff * Ydiff; michael@0: } michael@0: michael@0: var Syx2 = (SUM_Ydiff2 - Math.pow(SUM_XdiffYdiff/SUM_Xdiff2, 2))/(n - 2); michael@0: var r2 = Math.pow((n*SUM_XY - SUM_X * SUM_Y), 2) / michael@0: ((n*SUM_XX - SUM_X*SUM_X)*(n*SUM_YY-SUM_Y*SUM_Y)); michael@0: michael@0: this.Syx = Math.sqrt(Syx2); michael@0: this.r = Math.sqrt(r2); michael@0: michael@0: } michael@0: michael@0: function dataDeriv(data) michael@0: { michael@0: if (data.X.length != data.Y.length) michael@0: { michael@0: throw 'length mismatch'; michael@0: } michael@0: var length = data.X.length; michael@0: michael@0: if (length < 2) michael@0: { michael@0: throw 'length ' + length + ' must be >= 2'; michael@0: } michael@0: var X = data.X; michael@0: var Y = data.Y; michael@0: michael@0: var deriv = {X: [], Y: [] }; michael@0: michael@0: for (var i = 0; i < length - 1; i++) michael@0: { michael@0: deriv.X[i] = (X[i] + X[i+1])/2; michael@0: deriv.Y[i] = (Y[i+1] - Y[i])/(X[i+1] - X[i]); michael@0: } michael@0: return deriv; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: function compareSource(expect, actual, summary) michael@0: { michael@0: // compare source michael@0: var expectP = expect. michael@0: replace(/([(){},.:\[\]])/mg, ' $1 '). michael@0: replace(/(\w+)/mg, ' $1 '). michael@0: replace(/<(\/)? (\w+) (\/)?>/mg, '<$1$2$3>'). michael@0: replace(/\s+/mg, ' '). michael@0: replace(/new (\w+)\s*\(\s*\)/mg, 'new $1'); michael@0: michael@0: var actualP = actual. michael@0: replace(/([(){},.:\[\]])/mg, ' $1 '). michael@0: replace(/(\w+)/mg, ' $1 '). michael@0: replace(/<(\/)? (\w+) (\/)?>/mg, '<$1$2$3>'). michael@0: replace(/\s+/mg, ' '). michael@0: replace(/new (\w+)\s*\(\s*\)/mg, 'new $1'); michael@0: michael@0: print('expect:\n' + expectP); michael@0: print('actual:\n' + actualP); michael@0: michael@0: reportCompare(expectP, actualP, summary); michael@0: michael@0: // actual must be compilable if expect is? michael@0: try michael@0: { michael@0: var expectCompile = 'No Error'; michael@0: var actualCompile; michael@0: michael@0: eval(expect); michael@0: try michael@0: { michael@0: eval(actual); michael@0: actualCompile = 'No Error'; michael@0: } michael@0: catch(ex1) michael@0: { michael@0: actualCompile = ex1 + ''; michael@0: } michael@0: reportCompare(expectCompile, actualCompile, michael@0: summary + ': compile actual'); michael@0: } michael@0: catch(ex) michael@0: { michael@0: } michael@0: } michael@0: michael@0: function optionsInit() { michael@0: michael@0: // record initial values to support resetting michael@0: // options to their initial values michael@0: options.initvalues = {}; michael@0: michael@0: // record values in a stack to support pushing michael@0: // and popping options michael@0: options.stackvalues = []; michael@0: michael@0: var optionNames = options().split(','); michael@0: michael@0: for (var i = 0; i < optionNames.length; i++) michael@0: { michael@0: var optionName = optionNames[i]; michael@0: if (optionName) michael@0: { michael@0: options.initvalues[optionName] = ''; michael@0: } michael@0: } michael@0: } michael@0: michael@0: function optionsClear() { michael@0: michael@0: // turn off current settings michael@0: // except jit. michael@0: var optionNames = options().split(','); michael@0: for (var i = 0; i < optionNames.length; i++) michael@0: { michael@0: var optionName = optionNames[i]; michael@0: if (optionName && michael@0: optionName != "methodjit" && michael@0: optionName != "methodjit_always" && michael@0: optionName != "ion") michael@0: { michael@0: options(optionName); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function optionsPush() michael@0: { michael@0: var optionsframe = {}; michael@0: michael@0: options.stackvalues.push(optionsframe); michael@0: michael@0: var optionNames = options().split(','); michael@0: michael@0: for (var i = 0; i < optionNames.length; i++) michael@0: { michael@0: var optionName = optionNames[i]; michael@0: if (optionName) michael@0: { michael@0: optionsframe[optionName] = ''; michael@0: } michael@0: } michael@0: michael@0: optionsClear(); michael@0: } michael@0: michael@0: function optionsPop() michael@0: { michael@0: var optionsframe = options.stackvalues.pop(); michael@0: michael@0: optionsClear(); michael@0: michael@0: for (optionName in optionsframe) michael@0: { michael@0: options(optionName); michael@0: } michael@0: michael@0: } michael@0: michael@0: function optionsReset() { michael@0: michael@0: try michael@0: { michael@0: optionsClear(); michael@0: michael@0: // turn on initial settings michael@0: for (var optionName in options.initvalues) michael@0: { michael@0: if (!options.hasOwnProperty(optionName)) michael@0: continue; michael@0: options(optionName); michael@0: } michael@0: } michael@0: catch(ex) michael@0: { michael@0: print('optionsReset: caught ' + ex); michael@0: } michael@0: michael@0: } michael@0: michael@0: if (typeof options == 'function') michael@0: { michael@0: optionsInit(); michael@0: optionsClear(); michael@0: } michael@0: michael@0: function getTestCaseResult(expected, actual) michael@0: { michael@0: if (typeof expected != typeof actual) michael@0: return false; michael@0: if (typeof expected != 'number') michael@0: // Note that many tests depend on the use of '==' here, not '==='. michael@0: return actual == expected; michael@0: michael@0: // Distinguish NaN from other values. Using x != x comparisons here michael@0: // works even if tests redefine isNaN. michael@0: if (actual != actual) michael@0: return expected != expected; michael@0: if (expected != expected) michael@0: return false; michael@0: michael@0: // Tolerate a certain degree of error. michael@0: if (actual != expected) michael@0: return Math.abs(actual - expected) <= 1E-10; michael@0: michael@0: // Here would be a good place to distinguish 0 and -0, if we wanted michael@0: // to. However, doing so would introduce a number of failures in michael@0: // areas where they don't seem important. For example, the WeekDay michael@0: // function in ECMA-262 returns -0 for Sundays before the epoch, but michael@0: // the Date functions in SpiderMonkey specified in terms of WeekDay michael@0: // often don't. This seems unimportant. michael@0: return true; michael@0: } michael@0: michael@0: if (typeof dump == 'undefined') michael@0: { michael@0: if (typeof window == 'undefined' && michael@0: typeof print == 'function') michael@0: { michael@0: dump = print; michael@0: } michael@0: else michael@0: { michael@0: dump = (function () {}); michael@0: } michael@0: } michael@0: michael@0: function test() { michael@0: for ( gTc=0; gTc < gTestcases.length; gTc++ ) { michael@0: // temporary hack to work around some unknown issue in 1.7 michael@0: try michael@0: { michael@0: gTestcases[gTc].passed = writeTestCaseResult( michael@0: gTestcases[gTc].expect, michael@0: gTestcases[gTc].actual, michael@0: gTestcases[gTc].description +" = "+ gTestcases[gTc].actual ); michael@0: gTestcases[gTc].reason += ( gTestcases[gTc].passed ) ? "" : "wrong value "; michael@0: } michael@0: catch(e) michael@0: { michael@0: print('test(): empty testcase for gTc = ' + gTc + ' ' + e); michael@0: } michael@0: } michael@0: stopTest(); michael@0: return ( gTestcases ); michael@0: } michael@0: michael@0: /* michael@0: * Begin printing functions. These functions use the shell's michael@0: * print function. When running tests in the browser, these michael@0: * functions, override these functions with functions that use michael@0: * document.write. michael@0: */ michael@0: michael@0: function writeTestCaseResult( expect, actual, string ) { michael@0: var passed = getTestCaseResult( expect, actual ); michael@0: // if running under reftest, let it handle result reporting. michael@0: if (typeof document != "object" || michael@0: !document.location.href.match(/jsreftest.html/)) { michael@0: writeFormattedResult( expect, actual, string, passed ); michael@0: } michael@0: return passed; michael@0: } michael@0: function writeFormattedResult( expect, actual, string, passed ) { michael@0: var s = ( passed ? PASSED : FAILED ) + string + ' expected: ' + expect; michael@0: print(s); michael@0: return passed; michael@0: } michael@0: michael@0: function writeHeaderToLog( string ) { michael@0: print( string ); michael@0: } michael@0: /* end of print functions */ michael@0: michael@0: michael@0: /* michael@0: * When running in the shell, run the garbage collector after the michael@0: * test has completed. michael@0: */ michael@0: michael@0: function stopTest() { michael@0: var gc; michael@0: if ( gc != undefined ) { michael@0: gc(); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Convenience function for displaying failed test cases. Useful michael@0: * when running tests manually. michael@0: * michael@0: */ michael@0: function getFailedCases() { michael@0: for ( var i = 0; i < gTestcases.length; i++ ) { michael@0: if ( ! gTestcases[i].passed ) { michael@0: print( gTestcases[i].description + " = " +gTestcases[i].actual + michael@0: " expected: " + gTestcases[i].expect ); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function jsTestDriverEnd() michael@0: { michael@0: // gDelayTestDriverEnd is used to michael@0: // delay collection of the test result and michael@0: // signal to Spider so that tests can continue michael@0: // to run after page load has fired. They are michael@0: // responsible for setting gDelayTestDriverEnd = true michael@0: // then when completed, setting gDelayTestDriverEnd = false michael@0: // then calling jsTestDriverEnd() michael@0: michael@0: if (gDelayTestDriverEnd) michael@0: { michael@0: return; michael@0: } michael@0: michael@0: try michael@0: { michael@0: optionsReset(); michael@0: } michael@0: catch(ex) michael@0: { michael@0: dump('jsTestDriverEnd ' + ex); michael@0: } michael@0: michael@0: for (var i = 0; i < gTestcases.length; i++) michael@0: { michael@0: gTestcases[i].dump(); michael@0: } michael@0: michael@0: } michael@0: michael@0: function jit(on) michael@0: { michael@0: } michael@0: michael@0: function assertEqArray(a1, a2) { michael@0: assertEq(a1.length, a2.length); michael@0: for (var i = 0; i < a1.length; i++) { michael@0: try { michael@0: assertEq(a1[i], a2[i]); michael@0: } catch (e) { michael@0: throw new Error("At index " + i + ": " + e); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function assertThrows(f) { michael@0: var ok = false; michael@0: try { michael@0: f(); michael@0: } catch (exc) { michael@0: ok = true; michael@0: } michael@0: if (!ok) michael@0: throw new Error("Assertion failed: " + f + " did not throw as expected"); michael@0: } michael@0: michael@0: /* michael@0: * Some tests need to know if we are in Rhino as opposed to SpiderMonkey michael@0: */ michael@0: function inRhino() michael@0: { michael@0: return (typeof defineClass == "function"); michael@0: } michael@0: michael@0: /* these functions are useful for running tests manually in Rhino */ michael@0: michael@0: function GetContext() { michael@0: return Packages.com.netscape.javascript.Context.getCurrentContext(); michael@0: } michael@0: function OptLevel( i ) { michael@0: i = Number(i); michael@0: var cx = GetContext(); michael@0: cx.setOptimizationLevel(i); michael@0: } michael@0: /* end of Rhino functions */