Bug 362433 - xpcshell-tests: add dump() to each do_check_*(), at least; (Av1a) Log check results; r=(ccooper + rcampbell)
authorSerge Gautherie <sgautherie.bz@free.fr>
Fri, 05 Jun 2009 03:10:52 +0200
changeset 25872 3bab31a7104fc464bbe1f34386412cd6e38cd6c0
parent 25871 db15a52a4fd40a48c45cf6f9b831108c7c7599d2
child 25873 5cd96b6afea3f67253657e6d4dd1e1e54849e3f6
push id1648
push usersgautherie.bz@free.fr
push dateFri, 05 Jun 2009 01:12:09 +0000
bugs362433
milestone1.9.1pre
Bug 362433 - xpcshell-tests: add dump() to each do_check_*(), at least; (Av1a) Log check results; r=(ccooper + rcampbell)
testing/xpcshell/head.js
testing/xpcshell/runxpcshelltests.py
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -18,16 +18,17 @@
  * The Initial Developer of the Original Code is Google Inc.
  * Portions created by the Initial Developer are Copyright (C) 2005
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Darin Fisher <darin@meer.net>
  *  Boris Zbarsky <bzbarsky@mit.edu>
  *  Jeff Walden <jwalden+code@mit.edu>
+ *  Serge Gautherie <sgautherie.bz@free.fr>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -40,18 +41,19 @@
 
 /*
  * This file contains common code that is loaded before each test file(s).
  * See http://developer.mozilla.org/en/docs/Writing_xpcshell-based_unit_tests
  * for more information.
  */
 
 var _quit = false;
-var _fail = false;
+var _passed = true;
 var _tests_pending = 0;
+var _passedChecks = 0, _falsePassedChecks = 0;
 
 function _TimerCallback(expr) {
   this._expr = expr;
 }
 _TimerCallback.prototype = {
   _expr: "",
   QueryInterface: function(iid) {
     if (iid.Equals(Components.interfaces.nsITimerCallback) ||
@@ -63,107 +65,140 @@ function _TimerCallback(expr) {
     eval(this._expr);
   }
 };
 
 function _do_main() {
   if (_quit)
     return;
 
-  dump("*** running event loop\n");
+  dump("TEST-INFO | (xpcshell/head.js) | running event loop\n");
+
   var thr = Components.classes["@mozilla.org/thread-manager;1"]
                       .getService().currentThread;
 
   while (!_quit)
     thr.processNextEvent(true);
 
   while (thr.hasPendingEvents())
     thr.processNextEvent(true);
 }
 
 function _do_quit() {
-  dump("*** exiting\n");
+  dump("TEST-INFO | (xpcshell/head.js) | exiting test\n");
 
   _quit = true;
 }
 
 function _execute_test() {
   try {
     do_test_pending();
     run_test();
     do_test_finished();
     _do_main();
   } catch (e) {
-    _fail = true;
-    dump(e + "\n");
+    _passed = false;
+    // Print exception, but not do_throw() result.
+    // Hopefully, this won't mask other NS_ERROR_ABORTs.
+    if (!_quit || e != Components.results.NS_ERROR_ABORT)
+      dump("TEST-UNEXPECTED-FAIL | (xpcshell/head.js) | " + e + "\n");
   }
 
-  if (_fail)
-    dump("*** FAIL ***\n");
+  if (!_passed)
+    return;
+
+  var truePassedChecks = _passedChecks - _falsePassedChecks;
+  if (truePassedChecks > 0)
+    dump("TEST-PASS | (xpcshell/head.js) | " + truePassedChecks + " (+ " +
+            _falsePassedChecks + ") check(s) passed\n");
   else
-    dump("*** PASS ***\n");
+    // ToDo: switch to TEST-UNEXPECTED-FAIL when all tests have been updated. (Bug 496443)
+    dump("TEST-INFO | (xpcshell/head.js) | No (+ " + _falsePassedChecks + ") checks actually run\n");
 }
 
 
 /************** Functions to be used from the tests **************/
 
 
 function do_timeout(delay, expr) {
   var timer = Components.classes["@mozilla.org/timer;1"]
                         .createInstance(Components.interfaces.nsITimer);
   timer.initWithCallback(new _TimerCallback(expr), delay, timer.TYPE_ONE_SHOT);
 }
 
 function do_throw(text, stack) {
   if (!stack)
     stack = Components.stack.caller;
-  _fail = true;
-  _do_quit();
-  dump("*** TEST-UNEXPECTED-FAIL | " + stack.filename + " | " + text + "\n");
+
+  _passed = false;
+  dump("TEST-UNEXPECTED-FAIL | " + stack.filename + " | " + text +
+         " - See following stack:\n");
   var frame = Components.stack;
   while (frame != null) {
     dump(frame + "\n");
     frame = frame.caller;
   }
+
+  _do_quit();
   throw Components.results.NS_ERROR_ABORT;
 }
 
 function do_check_neq(left, right, stack) {
   if (!stack)
     stack = Components.stack.caller;
+
+  var text = left + " != " + right;
   if (left == right)
-    do_throw(left + " != " + right, stack);
+    do_throw(text, stack);
+  else {
+    ++_passedChecks;
+    dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
+         stack.lineNumber + "] " + text + "\n");
+  }
 }
 
 function do_check_eq(left, right, stack) {
   if (!stack)
     stack = Components.stack.caller;
+
+  var text = left + " == " + right;
   if (left != right)
-    do_throw(left + " == " + right, stack);
+    do_throw(text, stack);
+  else {
+    ++_passedChecks;
+    dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
+         stack.lineNumber + "] " + text + "\n");
+  }
 }
 
 function do_check_true(condition, stack) {
   if (!stack)
     stack = Components.stack.caller;
+
   do_check_eq(condition, true, stack);
 }
 
 function do_check_false(condition, stack) {
   if (!stack)
     stack = Components.stack.caller;
+
   do_check_eq(condition, false, stack);
 }
 
 function do_test_pending() {
-  dump("*** test pending\n");
-  _tests_pending++;
+  ++_tests_pending;
+
+  dump("TEST-INFO | (xpcshell/head.js) | test " + _tests_pending +
+         " pending\n");
 }
 
 function do_test_finished() {
-  dump("*** test finished\n");
+  dump("TEST-INFO | (xpcshell/head.js) | test " + _tests_pending +
+         " finished\n");
+
   if (--_tests_pending == 0)
     _do_quit();
 }
 
 function do_get_file(path, allowNonexistent) {
   try {
     let lf = Components.classes["@mozilla.org/file/directory_service;1"]
       .getService(Components.interfaces.nsIProperties)
@@ -174,40 +209,45 @@ function do_get_file(path, allowNonexist
       if (bits[i]) {
         if (bits[i] == "..")
           lf = lf.parent;
         else
           lf.append(bits[i]);
       }
     }
 
-    if (!allowNonexistent) {
-      if (!lf.exists()) {
-        print(lf.path + " doesn't exist\n");
-      }
-      do_check_true(lf.exists());
+    if (!allowNonexistent && !lf.exists()) {
+      // Not using do_throw(): caller will continue.
+      _passed = false;
+      var stack = Components.stack.caller;
+      dump("TEST-UNEXPECTED-FAIL | " + stack.filename + " | [" +
+             stack.name + " : " + stack.lineNumber + "] " + lf.path +
+             " does not exist\n");
     }
 
     return lf;
   }
-  catch(ex) {
+  catch (ex) {
     do_throw(ex.toString(), Components.stack.caller);
   }
+
   return null;
 }
 
 // do_get_cwd() isn't exactly self-explanatory, so provide a helper
 function do_get_cwd() {
   return do_get_file("");
 }
 
 function do_load_module(path) {
   var lf = do_get_file(path);
   const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
   do_check_true(Components.manager instanceof nsIComponentRegistrar);
+  // Previous do_check_true() is not a test check.
+  ++_falsePassedChecks;
   Components.manager.autoRegister(lf);
 }
 
 /**
  * Parse a DOM document.
  *
  * @param aPath File path to the document.
  * @param aType Content type to use in DOMParser.
@@ -217,18 +257,19 @@ function do_load_module(path) {
 function do_parse_document(aPath, aType) {
   switch (aType) {
     case "application/xhtml+xml":
     case "application/xml":
     case "text/xml":
       break;
 
     default:
-      throw new Error("do_parse_document requires content-type of " +
-                      "application/xhtml+xml, application/xml, or text/xml.");
+      do_throw("type: expected application/xhtml+xml, application/xml or text/xml," +
+                 " got '" + aType + "'",
+               Components.stack.caller);
   }
 
   var lf = do_get_file(aPath);
   const C_i = Components.interfaces;
   const parserClass = "@mozilla.org/xmlextras/domparser;1";
   const streamClass = "@mozilla.org/network/file-input-stream;1";
   var stream = Components.classes[streamClass]
                          .createInstance(C_i.nsIFileInputStream);
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -15,33 +15,34 @@
 #
 # The Original Code is mozilla.org code.
 #
 # The Initial Developer of the Original Code is The Mozilla Foundation
 # Portions created by the Initial Developer are Copyright (C) 2009
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
+#  Serge Gautherie <sgautherie.bz@free.fr>
 #  Ted Mielczarek <ted.mielczarek@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK ***** */
 
-import sys, os, os.path
+import re, sys, os, os.path
 import tempfile
 from glob import glob
 from optparse import OptionParser
 from subprocess import Popen, PIPE, STDOUT
 
 def readManifest(manifest):
   """Given a manifest file containing a list of test directories,
   return a list of absolute paths to the directories contained within."""
@@ -197,24 +198,24 @@ def runTests(xpcshell, testdirs=[], xreP
                    env=env, cwd=testdir)
       # |stderr == None| as |pstderr| was either |None| or redirected to |stdout|.
       stdout, stderr = proc.communicate()
 
       if interactive:
         # not sure what else to do here...
         return True
 
-      if proc.returncode != 0 or (stdout is not None and stdout.find("*** PASS") == -1):
+      if proc.returncode != 0 or (stdout is not None and re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
         print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log:
   >>>>>>>
   %s
   <<<<<<<""" % (test, proc.returncode, stdout)
         success = False
       else:
-        print "TEST-PASS | %s | all tests passed" % test
+        print "TEST-PASS | %s | test passed" % test
 
       leakReport = processLeakLog(leakLogFile)
 
       if stdout is not None:
         try:
           f = open(test + '.log', 'w')
           f.write(stdout)
           if leakReport: