testing/mochitest/tests/SimpleTest/TestRunner.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mochitest/tests/SimpleTest/TestRunner.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,618 @@
     1.4 +/* -*- js-indent-level: 4 -*- */
     1.5 +/*
     1.6 + * e10s event dispatcher from content->chrome
     1.7 + *
     1.8 + * type = eventName (QuitApplication)
     1.9 + * data = json object {"filename":filename} <- for LoggerInit
    1.10 + */
    1.11 +function getElement(id) {
    1.12 +    return ((typeof(id) == "string") ?
    1.13 +        document.getElementById(id) : id);
    1.14 +}
    1.15 +
    1.16 +this.$ = this.getElement;
    1.17 +
    1.18 +function contentDispatchEvent(type, data, sync) {
    1.19 +  if (typeof(data) == "undefined") {
    1.20 +    data = {};
    1.21 +  }
    1.22 +
    1.23 +  var event = new CustomEvent("contentEvent", {
    1.24 +    bubbles: true,
    1.25 +    detail: {
    1.26 +      "sync": sync,
    1.27 +      "type": type,
    1.28 +      "data": JSON.stringify(data)
    1.29 +    }
    1.30 +  });
    1.31 +  document.dispatchEvent(event);
    1.32 +}
    1.33 +
    1.34 +function contentAsyncEvent(type, data) {
    1.35 +  contentDispatchEvent(type, data, 0);
    1.36 +}
    1.37 +
    1.38 +/* Helper Function */
    1.39 +function extend(obj, /* optional */ skip) {
    1.40 +    // Extend an array with an array-like object starting
    1.41 +    // from the skip index
    1.42 +    if (!skip) {
    1.43 +        skip = 0;
    1.44 +    }
    1.45 +    if (obj) {
    1.46 +        var l = obj.length;
    1.47 +        var ret = [];
    1.48 +        for (var i = skip; i < l; i++) {
    1.49 +            ret.push(obj[i]);
    1.50 +        }
    1.51 +    }
    1.52 +    return ret;
    1.53 +}
    1.54 +
    1.55 +function flattenArguments(lst/* ...*/) {
    1.56 +    var res = [];
    1.57 +    var args = extend(arguments);
    1.58 +    while (args.length) {
    1.59 +        var o = args.shift();
    1.60 +        if (o && typeof(o) == "object" && typeof(o.length) == "number") {
    1.61 +            for (var i = o.length - 1; i >= 0; i--) {
    1.62 +                args.unshift(o[i]);
    1.63 +            }
    1.64 +        } else {
    1.65 +            res.push(o);
    1.66 +        }
    1.67 +    }
    1.68 +    return res;
    1.69 +}
    1.70 +
    1.71 +/**
    1.72 + * TestRunner: A test runner for SimpleTest
    1.73 + * TODO:
    1.74 + *
    1.75 + *  * Avoid moving iframes: That causes reloads on mozilla and opera.
    1.76 + *
    1.77 + *
    1.78 +**/
    1.79 +var TestRunner = {};
    1.80 +TestRunner.logEnabled = false;
    1.81 +TestRunner._currentTest = 0;
    1.82 +TestRunner._lastTestFinished = -1;
    1.83 +TestRunner._loopIsRestarting = false;
    1.84 +TestRunner.currentTestURL = "";
    1.85 +TestRunner.originalTestURL = "";
    1.86 +TestRunner._urls = [];
    1.87 +TestRunner._lastAssertionCount = 0;
    1.88 +TestRunner._expectedMinAsserts = 0;
    1.89 +TestRunner._expectedMaxAsserts = 0;
    1.90 +
    1.91 +TestRunner.timeout = 5 * 60 * 1000; // 5 minutes.
    1.92 +TestRunner.maxTimeouts = 4; // halt testing after too many timeouts
    1.93 +TestRunner.runSlower = false;
    1.94 +TestRunner.dumpOutputDirectory = "";
    1.95 +TestRunner.dumpAboutMemoryAfterTest = false;
    1.96 +TestRunner.dumpDMDAfterTest = false;
    1.97 +TestRunner.quiet = false;
    1.98 +TestRunner.slowestTestTime = 0;
    1.99 +TestRunner.slowestTestURL = "";
   1.100 +
   1.101 +TestRunner._expectingProcessCrash = false;
   1.102 +
   1.103 +/**
   1.104 + * Make sure the tests don't hang indefinitely.
   1.105 +**/
   1.106 +TestRunner._numTimeouts = 0;
   1.107 +TestRunner._currentTestStartTime = new Date().valueOf();
   1.108 +TestRunner._timeoutFactor = 1;
   1.109 +
   1.110 +TestRunner._checkForHangs = function() {
   1.111 +  function reportError(win, msg) {
   1.112 +    if ("SimpleTest" in win) {
   1.113 +      win.SimpleTest.ok(false, msg);
   1.114 +    } else if ("W3CTest" in win) {
   1.115 +      win.W3CTest.logFailure(msg);
   1.116 +    }
   1.117 +  }
   1.118 +
   1.119 +  function killTest(win) {
   1.120 +    if ("SimpleTest" in win) {
   1.121 +      win.SimpleTest.finish();
   1.122 +    } else if ("W3CTest" in win) {
   1.123 +      win.W3CTest.timeout();
   1.124 +    }
   1.125 +  }
   1.126 +
   1.127 +  if (TestRunner._currentTest < TestRunner._urls.length) {
   1.128 +    var runtime = new Date().valueOf() - TestRunner._currentTestStartTime;
   1.129 +    if (runtime >= TestRunner.timeout * TestRunner._timeoutFactor) {
   1.130 +      var frameWindow = $('testframe').contentWindow.wrappedJSObject ||
   1.131 +                          $('testframe').contentWindow;
   1.132 +      reportError(frameWindow, "Test timed out.");
   1.133 +
   1.134 +      // If we have too many timeouts, give up. We don't want to wait hours
   1.135 +      // for results if some bug causes lots of tests to time out.
   1.136 +      if (++TestRunner._numTimeouts >= TestRunner.maxTimeouts) {
   1.137 +        TestRunner._haltTests = true;
   1.138 +
   1.139 +        TestRunner.currentTestURL = "(SimpleTest/TestRunner.js)";
   1.140 +        reportError(frameWindow, TestRunner.maxTimeouts + " test timeouts, giving up.");
   1.141 +        var skippedTests = TestRunner._urls.length - TestRunner._currentTest;
   1.142 +        reportError(frameWindow, "Skipping " + skippedTests + " remaining tests.");
   1.143 +      }
   1.144 +
   1.145 +      // Add a little (1 second) delay to ensure automation.py has time to notice
   1.146 +      // "Test timed out" log and process it (= take a screenshot).
   1.147 +      setTimeout(function delayedKillTest() { killTest(frameWindow); }, 1000);
   1.148 +
   1.149 +      if (TestRunner._haltTests)
   1.150 +        return;
   1.151 +    }
   1.152 +
   1.153 +    setTimeout(TestRunner._checkForHangs, 30000);
   1.154 +  }
   1.155 +}
   1.156 +
   1.157 +TestRunner.requestLongerTimeout = function(factor) {
   1.158 +    TestRunner._timeoutFactor = factor;
   1.159 +}
   1.160 +
   1.161 +/**
   1.162 + * This is used to loop tests
   1.163 +**/
   1.164 +TestRunner.repeat = 0;
   1.165 +TestRunner._currentLoop = 1;
   1.166 +
   1.167 +TestRunner.expectAssertions = function(min, max) {
   1.168 +    if (typeof(max) == "undefined") {
   1.169 +        max = min;
   1.170 +    }
   1.171 +    if (typeof(min) != "number" || typeof(max) != "number" ||
   1.172 +        min < 0 || max < min) {
   1.173 +        throw "bad parameter to expectAssertions";
   1.174 +    }
   1.175 +    TestRunner._expectedMinAsserts = min;
   1.176 +    TestRunner._expectedMaxAsserts = max;
   1.177 +}
   1.178 +
   1.179 +/**
   1.180 + * This function is called after generating the summary.
   1.181 +**/
   1.182 +TestRunner.onComplete = null;
   1.183 +
   1.184 +/**
   1.185 + * Adds a failed test case to a list so we can rerun only the failed tests
   1.186 + **/
   1.187 +TestRunner._failedTests = {};
   1.188 +TestRunner._failureFile = "";
   1.189 +
   1.190 +TestRunner.addFailedTest = function(testName) {
   1.191 +    if (TestRunner._failedTests[testName] == undefined) {
   1.192 +        TestRunner._failedTests[testName] = "";
   1.193 +    }
   1.194 +};
   1.195 +
   1.196 +TestRunner.setFailureFile = function(fileName) {
   1.197 +    TestRunner._failureFile = fileName;
   1.198 +}
   1.199 +
   1.200 +TestRunner.generateFailureList = function () {
   1.201 +    if (TestRunner._failureFile) {
   1.202 +        var failures = new SpecialPowersLogger(TestRunner._failureFile);
   1.203 +        failures.log(JSON.stringify(TestRunner._failedTests));
   1.204 +        failures.close();
   1.205 +    }
   1.206 +};
   1.207 +
   1.208 +/**
   1.209 + * If logEnabled is true, this is the logger that will be used.
   1.210 +**/
   1.211 +TestRunner.logger = LogController;
   1.212 +
   1.213 +TestRunner.log = function(msg) {
   1.214 +    if (TestRunner.logEnabled) {
   1.215 +        TestRunner.logger.log(msg);
   1.216 +    } else {
   1.217 +        dump(msg + "\n");
   1.218 +    }
   1.219 +};
   1.220 +
   1.221 +TestRunner.error = function(msg) {
   1.222 +    if (TestRunner.logEnabled) {
   1.223 +        TestRunner.logger.error(msg);
   1.224 +    } else {
   1.225 +        dump(msg + "\n");
   1.226 +    }
   1.227 +
   1.228 +    if (TestRunner.runUntilFailure) {
   1.229 +      TestRunner._haltTests = true;
   1.230 +    }
   1.231 +
   1.232 +    if (TestRunner.debugOnFailure) {
   1.233 +      // You've hit this line because you requested to break into the
   1.234 +      // debugger upon a testcase failure on your test run.
   1.235 +      debugger;
   1.236 +    }
   1.237 +};
   1.238 +
   1.239 +/**
   1.240 + * Toggle element visibility
   1.241 +**/
   1.242 +TestRunner._toggle = function(el) {
   1.243 +    if (el.className == "noshow") {
   1.244 +        el.className = "";
   1.245 +        el.style.cssText = "";
   1.246 +    } else {
   1.247 +        el.className = "noshow";
   1.248 +        el.style.cssText = "width:0px; height:0px; border:0px;";
   1.249 +    }
   1.250 +};
   1.251 +
   1.252 +/**
   1.253 + * Creates the iframe that contains a test
   1.254 +**/
   1.255 +TestRunner._makeIframe = function (url, retry) {
   1.256 +    var iframe = $('testframe');
   1.257 +    if (url != "about:blank" &&
   1.258 +        (("hasFocus" in document && !document.hasFocus()) ||
   1.259 +         ("activeElement" in document && document.activeElement != iframe))) {
   1.260 +
   1.261 +        contentAsyncEvent("Focus");
   1.262 +        window.focus();
   1.263 +        SpecialPowers.focus();
   1.264 +        iframe.focus();
   1.265 +        if (retry < 3) {
   1.266 +            window.setTimeout('TestRunner._makeIframe("'+url+'", '+(retry+1)+')', 1000);
   1.267 +            return;
   1.268 +        }
   1.269 +
   1.270 +        TestRunner.log("Error: Unable to restore focus, expect failures and timeouts.");
   1.271 +    }
   1.272 +    window.scrollTo(0, $('indicator').offsetTop);
   1.273 +    iframe.src = url;
   1.274 +    iframe.name = url;
   1.275 +    iframe.width = "500";
   1.276 +    return iframe;
   1.277 +};
   1.278 +
   1.279 +/**
   1.280 + * Returns the current test URL.
   1.281 + * We use this to tell whether the test has navigated to another test without
   1.282 + * being finished first.
   1.283 + */
   1.284 +TestRunner.getLoadedTestURL = function () {
   1.285 +    var prefix = "";
   1.286 +    // handle mochitest-chrome URIs
   1.287 +    if ($('testframe').contentWindow.location.protocol == "chrome:") {
   1.288 +      prefix = "chrome://mochitests";
   1.289 +    }
   1.290 +    return prefix + $('testframe').contentWindow.location.pathname;
   1.291 +};
   1.292 +
   1.293 +/**
   1.294 + * TestRunner entry point.
   1.295 + *
   1.296 + * The arguments are the URLs of the test to be ran.
   1.297 + *
   1.298 +**/
   1.299 +TestRunner.runTests = function (/*url...*/) {
   1.300 +    TestRunner.log("SimpleTest START");
   1.301 +    TestRunner.originalTestURL = $("current-test").innerHTML;
   1.302 +
   1.303 +    SpecialPowers.registerProcessCrashObservers();
   1.304 +
   1.305 +    TestRunner._urls = flattenArguments(arguments);
   1.306 +    $('testframe').src="";
   1.307 +    TestRunner._checkForHangs();
   1.308 +    TestRunner.runNextTest();
   1.309 +};
   1.310 +
   1.311 +/**
   1.312 + * Used for running a set of tests in a loop for debugging purposes
   1.313 + * Takes an array of URLs
   1.314 +**/
   1.315 +TestRunner.resetTests = function(listURLs) {
   1.316 +  TestRunner._currentTest = 0;
   1.317 +  // Reset our "Current-test" line - functionality depends on it
   1.318 +  $("current-test").innerHTML = TestRunner.originalTestURL;
   1.319 +  if (TestRunner.logEnabled)
   1.320 +    TestRunner.log("SimpleTest START Loop " + TestRunner._currentLoop);
   1.321 +
   1.322 +  TestRunner._urls = listURLs;
   1.323 +  $('testframe').src="";
   1.324 +  TestRunner._checkForHangs();
   1.325 +  TestRunner.runNextTest();
   1.326 +}
   1.327 +
   1.328 +/**
   1.329 + * Run the next test. If no test remains, calls onComplete().
   1.330 + **/
   1.331 +TestRunner._haltTests = false;
   1.332 +TestRunner.runNextTest = function() {
   1.333 +    if (TestRunner._currentTest < TestRunner._urls.length &&
   1.334 +        !TestRunner._haltTests)
   1.335 +    {
   1.336 +        var url = TestRunner._urls[TestRunner._currentTest];
   1.337 +        TestRunner.currentTestURL = url;
   1.338 +
   1.339 +        $("current-test-path").innerHTML = url;
   1.340 +
   1.341 +        TestRunner._currentTestStartTime = new Date().valueOf();
   1.342 +        TestRunner._timeoutFactor = 1;
   1.343 +        TestRunner._expectedMinAsserts = 0;
   1.344 +        TestRunner._expectedMaxAsserts = 0;
   1.345 +
   1.346 +        TestRunner.log("TEST-START | " + url); // used by automation.py
   1.347 +
   1.348 +        TestRunner._makeIframe(url, 0);
   1.349 +    } else {
   1.350 +        $("current-test").innerHTML = "<b>Finished</b>";
   1.351 +        TestRunner._makeIframe("about:blank", 0);
   1.352 +
   1.353 +        if (parseInt($("pass-count").innerHTML) == 0 &&
   1.354 +            parseInt($("fail-count").innerHTML) == 0 &&
   1.355 +            parseInt($("todo-count").innerHTML) == 0)
   1.356 +        {
   1.357 +          // No |$('testframe').contentWindow|, so manually update: ...
   1.358 +          // ... the log,
   1.359 +          TestRunner.error("TEST-UNEXPECTED-FAIL | (SimpleTest/TestRunner.js) | No checks actually run.");
   1.360 +          // ... the count,
   1.361 +          $("fail-count").innerHTML = 1;
   1.362 +          // ... the indicator.
   1.363 +          var indicator = $("indicator");
   1.364 +          indicator.innerHTML = "Status: Fail (No checks actually run)";
   1.365 +          indicator.style.backgroundColor = "red";
   1.366 +        }
   1.367 +
   1.368 +        SpecialPowers.unregisterProcessCrashObservers();
   1.369 +
   1.370 +        TestRunner.log("TEST-START | Shutdown"); // used by automation.py
   1.371 +        TestRunner.log("Passed:  " + $("pass-count").innerHTML);
   1.372 +        TestRunner.log("Failed:  " + $("fail-count").innerHTML);
   1.373 +        TestRunner.log("Todo:    " + $("todo-count").innerHTML);
   1.374 +        TestRunner.log("Slowest: " + TestRunner.slowestTestTime + 'ms - ' + TestRunner.slowestTestURL);
   1.375 +        // If we are looping, don't send this cause it closes the log file
   1.376 +        if (TestRunner.repeat == 0) {
   1.377 +          TestRunner.log("SimpleTest FINISHED");
   1.378 +        }
   1.379 +
   1.380 +        if (TestRunner.repeat == 0 && TestRunner.onComplete) {
   1.381 +             TestRunner.onComplete();
   1.382 +         }
   1.383 +
   1.384 +        if (TestRunner._currentLoop <= TestRunner.repeat && !TestRunner._haltTests) {
   1.385 +          TestRunner._currentLoop++;
   1.386 +          TestRunner.resetTests(TestRunner._urls);
   1.387 +          TestRunner._loopIsRestarting = true;
   1.388 +        } else {
   1.389 +          // Loops are finished
   1.390 +          if (TestRunner.logEnabled) {
   1.391 +            TestRunner.log("TEST-INFO | Ran " + TestRunner._currentLoop + " Loops");
   1.392 +            TestRunner.log("SimpleTest FINISHED");
   1.393 +          }
   1.394 +
   1.395 +          if (TestRunner.onComplete)
   1.396 +            TestRunner.onComplete();
   1.397 +       }
   1.398 +       TestRunner.generateFailureList();
   1.399 +    }
   1.400 +};
   1.401 +
   1.402 +TestRunner.expectChildProcessCrash = function() {
   1.403 +    TestRunner._expectingProcessCrash = true;
   1.404 +};
   1.405 +
   1.406 +/**
   1.407 + * This stub is called by SimpleTest when a test is finished.
   1.408 +**/
   1.409 +TestRunner.testFinished = function(tests) {
   1.410 +    // Prevent a test from calling finish() multiple times before we
   1.411 +    // have a chance to unload it.
   1.412 +    if (TestRunner._currentTest == TestRunner._lastTestFinished &&
   1.413 +        !TestRunner._loopIsRestarting) {
   1.414 +        TestRunner.error("TEST-UNEXPECTED-FAIL | " +
   1.415 +                         TestRunner.currentTestURL +
   1.416 +                         " | called finish() multiple times");
   1.417 +        TestRunner.updateUI([{ result: false }]);
   1.418 +        return;
   1.419 +    }
   1.420 +    TestRunner._lastTestFinished = TestRunner._currentTest;
   1.421 +    TestRunner._loopIsRestarting = false;
   1.422 +
   1.423 +    MemoryStats.dump(TestRunner.log, TestRunner._currentTest,
   1.424 +                     TestRunner.currentTestURL,
   1.425 +                     TestRunner.dumpOutputDirectory,
   1.426 +                     TestRunner.dumpAboutMemoryAfterTest,
   1.427 +                     TestRunner.dumpDMDAfterTest);
   1.428 +
   1.429 +    function cleanUpCrashDumpFiles() {
   1.430 +        if (!SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
   1.431 +            TestRunner.error("TEST-UNEXPECTED-FAIL | " +
   1.432 +                             TestRunner.currentTestURL +
   1.433 +                             " | This test did not leave any crash dumps behind, but we were expecting some!");
   1.434 +            tests.push({ result: false });
   1.435 +        }
   1.436 +        var unexpectedCrashDumpFiles =
   1.437 +            SpecialPowers.findUnexpectedCrashDumpFiles();
   1.438 +        TestRunner._expectingProcessCrash = false;
   1.439 +        if (unexpectedCrashDumpFiles.length) {
   1.440 +            TestRunner.error("TEST-UNEXPECTED-FAIL | " +
   1.441 +                             TestRunner.currentTestURL +
   1.442 +                             " | This test left crash dumps behind, but we " +
   1.443 +                             "weren't expecting it to!");
   1.444 +            tests.push({ result: false });
   1.445 +            unexpectedCrashDumpFiles.sort().forEach(function(aFilename) {
   1.446 +                TestRunner.log("TEST-INFO | Found unexpected crash dump file " +
   1.447 +                               aFilename + ".");
   1.448 +            });
   1.449 +        }
   1.450 +    }
   1.451 +
   1.452 +    function runNextTest() {
   1.453 +        if (TestRunner.currentTestURL != TestRunner.getLoadedTestURL()) {
   1.454 +            TestRunner.error("TEST-UNEXPECTED-FAIL | " +
   1.455 +                             TestRunner.currentTestURL +
   1.456 +                             " | " + TestRunner.getLoadedTestURL() +
   1.457 +                             " finished in a non-clean fashion, probably" +
   1.458 +                             " because it didn't call SimpleTest.finish()");
   1.459 +            tests.push({ result: false });
   1.460 +        }
   1.461 +
   1.462 +        var runtime = new Date().valueOf() - TestRunner._currentTestStartTime;
   1.463 +        TestRunner.log("TEST-END | " +
   1.464 +                       TestRunner.currentTestURL +
   1.465 +                       " | finished in " + runtime + "ms");
   1.466 +        if (TestRunner.slowestTestTime < runtime && TestRunner._timeoutFactor == 1) {
   1.467 +          TestRunner.slowestTestTime = runtime;
   1.468 +          TestRunner.slowestTestURL = TestRunner.currentTestURL;
   1.469 +        }
   1.470 +
   1.471 +        TestRunner.updateUI(tests);
   1.472 +
   1.473 +        var interstitialURL;
   1.474 +        if ($('testframe').contentWindow.location.protocol == "chrome:") {
   1.475 +            interstitialURL = "tests/SimpleTest/iframe-between-tests.html";
   1.476 +        } else {
   1.477 +            interstitialURL = "/tests/SimpleTest/iframe-between-tests.html";
   1.478 +        }
   1.479 +        TestRunner._makeIframe(interstitialURL, 0);
   1.480 +    }
   1.481 +
   1.482 +    SpecialPowers.executeAfterFlushingMessageQueue(function() {
   1.483 +        cleanUpCrashDumpFiles();
   1.484 +        SpecialPowers.flushAllAppsLaunchable();
   1.485 +        SpecialPowers.flushPermissions(function () { SpecialPowers.flushPrefEnv(runNextTest); });
   1.486 +    });
   1.487 +};
   1.488 +
   1.489 +TestRunner.testUnloaded = function() {
   1.490 +    // If we're in a debug build, check assertion counts.  This code is
   1.491 +    // similar to the code in Tester_nextTest in browser-test.js used
   1.492 +    // for browser-chrome mochitests.
   1.493 +    if (SpecialPowers.isDebugBuild) {
   1.494 +        var newAssertionCount = SpecialPowers.assertionCount();
   1.495 +        var numAsserts = newAssertionCount - TestRunner._lastAssertionCount;
   1.496 +        TestRunner._lastAssertionCount = newAssertionCount;
   1.497 +
   1.498 +        var url = TestRunner._urls[TestRunner._currentTest];
   1.499 +        var max = TestRunner._expectedMaxAsserts;
   1.500 +        var min = TestRunner._expectedMinAsserts;
   1.501 +        if (numAsserts > max) {
   1.502 +            TestRunner.error("TEST-UNEXPECTED-FAIL | " + url + " | Assertion count " + numAsserts + " is greater than expected range " + min + "-" + max + " assertions.");
   1.503 +            TestRunner.updateUI([{ result: false }]);
   1.504 +        } else if (numAsserts < min) {
   1.505 +            TestRunner.error("TEST-UNEXPECTED-PASS | " + url + " | Assertion count " + numAsserts + " is less than expected range " + min + "-" + max + " assertions.");
   1.506 +            TestRunner.updateUI([{ result: false }]);
   1.507 +        } else if (numAsserts > 0) {
   1.508 +            TestRunner.log("TEST-KNOWN-FAIL | " + url + " | Assertion count " + numAsserts + " within expected range " + min + "-" + max + " assertions.");
   1.509 +        }
   1.510 +    }
   1.511 +    TestRunner._currentTest++;
   1.512 +    if (TestRunner.runSlower) {
   1.513 +        setTimeout(TestRunner.runNextTest, 1000);
   1.514 +    } else {
   1.515 +        TestRunner.runNextTest();
   1.516 +    }
   1.517 +};
   1.518 +
   1.519 +/**
   1.520 + * Get the results.
   1.521 + */
   1.522 +TestRunner.countResults = function(tests) {
   1.523 +  var nOK = 0;
   1.524 +  var nNotOK = 0;
   1.525 +  var nTodo = 0;
   1.526 +  for (var i = 0; i < tests.length; ++i) {
   1.527 +    var test = tests[i];
   1.528 +    if (test.todo && !test.result) {
   1.529 +      nTodo++;
   1.530 +    } else if (test.result && !test.todo) {
   1.531 +      nOK++;
   1.532 +    } else {
   1.533 +      nNotOK++;
   1.534 +    }
   1.535 +  }
   1.536 +  return {"OK": nOK, "notOK": nNotOK, "todo": nTodo};
   1.537 +}
   1.538 +
   1.539 +/**
   1.540 + * Print out table of any error messages found during looped run
   1.541 + */
   1.542 +TestRunner.displayLoopErrors = function(tableName, tests) {
   1.543 +  if(TestRunner.countResults(tests).notOK >0){
   1.544 +    var table = $(tableName);
   1.545 +    var curtest;
   1.546 +    if (table.rows.length == 0) {
   1.547 +      //if table headers are not yet generated, make them
   1.548 +      var row = table.insertRow(table.rows.length);
   1.549 +      var cell = row.insertCell(0);
   1.550 +      var textNode = document.createTextNode("Test File Name:");
   1.551 +      cell.appendChild(textNode);
   1.552 +      cell = row.insertCell(1);
   1.553 +      textNode = document.createTextNode("Test:");
   1.554 +      cell.appendChild(textNode);
   1.555 +      cell = row.insertCell(2);
   1.556 +      textNode = document.createTextNode("Error message:");
   1.557 +      cell.appendChild(textNode);
   1.558 +    }
   1.559 +
   1.560 +    //find the broken test
   1.561 +    for (var testnum in tests){
   1.562 +      curtest = tests[testnum];
   1.563 +      if( !((curtest.todo && !curtest.result) || (curtest.result && !curtest.todo)) ){
   1.564 +        //this is a failed test or the result of todo test. Display the related message
   1.565 +        row = table.insertRow(table.rows.length);
   1.566 +        cell = row.insertCell(0);
   1.567 +        textNode = document.createTextNode(TestRunner.currentTestURL);
   1.568 +        cell.appendChild(textNode);
   1.569 +        cell = row.insertCell(1);
   1.570 +        textNode = document.createTextNode(curtest.name);
   1.571 +        cell.appendChild(textNode);
   1.572 +        cell = row.insertCell(2);
   1.573 +        textNode = document.createTextNode((curtest.diag ? curtest.diag : "" ));
   1.574 +        cell.appendChild(textNode);
   1.575 +      }
   1.576 +    }
   1.577 +  }
   1.578 +}
   1.579 +
   1.580 +TestRunner.updateUI = function(tests) {
   1.581 +  var results = TestRunner.countResults(tests);
   1.582 +  var passCount = parseInt($("pass-count").innerHTML) + results.OK;
   1.583 +  var failCount = parseInt($("fail-count").innerHTML) + results.notOK;
   1.584 +  var todoCount = parseInt($("todo-count").innerHTML) + results.todo;
   1.585 +  $("pass-count").innerHTML = passCount;
   1.586 +  $("fail-count").innerHTML = failCount;
   1.587 +  $("todo-count").innerHTML = todoCount;
   1.588 +
   1.589 +  // Set the top Green/Red bar
   1.590 +  var indicator = $("indicator");
   1.591 +  if (failCount > 0) {
   1.592 +    indicator.innerHTML = "Status: Fail";
   1.593 +    indicator.style.backgroundColor = "red";
   1.594 +  } else if (passCount > 0) {
   1.595 +    indicator.innerHTML = "Status: Pass";
   1.596 +    indicator.style.backgroundColor = "#0d0";
   1.597 +  } else {
   1.598 +    indicator.innerHTML = "Status: ToDo";
   1.599 +    indicator.style.backgroundColor = "orange";
   1.600 +  }
   1.601 +
   1.602 +  // Set the table values
   1.603 +  var trID = "tr-" + $('current-test-path').innerHTML;
   1.604 +  var row = $(trID);
   1.605 +
   1.606 +  // Only update the row if it actually exists (autoUI)
   1.607 +  if (row != null) {
   1.608 +    var tds = row.getElementsByTagName("td");
   1.609 +    tds[0].style.backgroundColor = "#0d0";
   1.610 +    tds[0].innerHTML = parseInt(tds[0].innerHTML) + parseInt(results.OK);
   1.611 +    tds[1].style.backgroundColor = results.notOK > 0 ? "red" : "#0d0";
   1.612 +    tds[1].innerHTML = parseInt(tds[1].innerHTML) + parseInt(results.notOK);
   1.613 +    tds[2].style.backgroundColor = results.todo > 0 ? "orange" : "#0d0";
   1.614 +    tds[2].innerHTML = parseInt(tds[2].innerHTML) + parseInt(results.todo);
   1.615 +  }
   1.616 +
   1.617 +  //if we ran in a loop, display any found errors
   1.618 +  if (TestRunner.repeat > 0) {
   1.619 +    TestRunner.displayLoopErrors('fail-table', tests);
   1.620 +  }
   1.621 +}

mercurial