js/src/tests/shell.js

changeset 0
6474c204b198
     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 */

mercurial