Bug 384339 - The check-interactive code executes head, tail scripts before the user runs; (Dv1c) Load head, test and tail files from _execute_test(); r=jwalden+bmo
authorSerge Gautherie <sgautherie.bz@free.fr>
Sat, 13 Jun 2009 20:28:55 +0200
changeset 25972 a08e2e4571d61e0cbd918024327176be6e2d5424
parent 25971 ac7a280846953f02add1b16f7d46d21ad757a6f7
child 25973 1aa4492403b26d12ec2ce512e21df2ada997c537
push id1703
push usersgautherie.bz@free.fr
push dateSat, 13 Jun 2009 18:29:30 +0000
reviewersjwalden
bugs384339
milestone1.9.1pre
Bug 384339 - The check-interactive code executes head, tail scripts before the user runs; (Dv1c) Load head, test and tail files from _execute_test(); r=jwalden+bmo CLOSED TREE
testing/xpcshell/head.js
testing/xpcshell/runxpcshelltests.py
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -45,27 +45,31 @@
  * for more information.
  */
 
 var _quit = 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) ||
         iid.Equals(Components.interfaces.nsISupports))
       return this;
+
     throw Components.results.NS_ERROR_NO_INTERFACE;
   },
+
   notify: function(timer) {
     eval(this._expr);
   }
 };
 
 function _do_main() {
   if (_quit)
     return;
@@ -84,41 +88,62 @@ function _do_main() {
 
 function _do_quit() {
   dump("TEST-INFO | (xpcshell/head.js) | exiting test\n");
 
   _quit = true;
 }
 
 function _execute_test() {
+  // _HEAD_FILES is dynamically defined by <runxpcshelltests.py>.
+  _load_files(_HEAD_FILES);
+  // _TEST_FILE is dynamically defined by <runxpcshelltests.py>.
+  _load_files(_TEST_FILE);
+
   try {
     do_test_pending();
     run_test();
     do_test_finished();
     _do_main();
   } catch (e) {
     _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");
   }
 
+  // _TAIL_FILES is dynamically defined by <runxpcshelltests.py>.
+  _load_files(_TAIL_FILES);
+
   if (!_passed)
     return;
 
   var truePassedChecks = _passedChecks - _falsePassedChecks;
   if (truePassedChecks > 0)
     dump("TEST-PASS | (xpcshell/head.js) | " + truePassedChecks + " (+ " +
             _falsePassedChecks + ") check(s) passed\n");
   else
     // 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");
 }
 
+/**
+ * Loads files.
+ *
+ * @param aFiles Array of files to load.
+ */
+function _load_files(aFiles) {
+  function loadTailFile(element, index, array) {
+    load(element);
+  }
+
+  aFiles.forEach(loadTailFile);
+}
+
 
 /************** 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);
@@ -232,16 +257,24 @@ function do_get_file(path, allowNonexist
   return null;
 }
 
 // do_get_cwd() isn't exactly self-explanatory, so provide a helper
 function do_get_cwd() {
   return do_get_file("");
 }
 
+/**
+ * Loads _HTTPD_JS_PATH file, which is dynamically defined by
+ * <runxpcshelltests.py>.
+ */
+function do_load_httpd_js() {
+  load(_HTTPD_JS_PATH);
+}
+
 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);
 }
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -64,17 +64,17 @@ def runTests(xpcshell, testdirs=[], xreP
              manifest=None, interactive=False):
   """Run the tests in |testdirs| using the |xpcshell| executable.
 
   |xrePath|, if provided, is the path to the XRE to use.
   |testPath|, if provided, indicates a single path and/or test to run.
   |manifest|, if provided, is a file containing a list of
     test directories to run.
   |interactive|, if set to True, indicates to provide an xpcshell prompt
-    instead of automatically executing  the test.
+    instead of automatically executing the test.
   """
 
   if not testdirs and not manifest:
     # nothing to test!
     print >>sys.stderr, "Error: No test dirs or test manifest specified!"
     return False
 
   testharnessdir = os.path.dirname(os.path.abspath(__file__))
@@ -116,23 +116,38 @@ def runTests(xpcshell, testdirs=[], xreP
     env["PATH"] = env["PATH"] + ";" + xrePath
   elif sys.platform in ('os2emx', 'os2knix'):
     os.environ["BEGINLIBPATH"] = xrePath + ";" + env["BEGINLIBPATH"]
     os.environ["LIBPATHSTRICT"] = "T"
   elif sys.platform == 'osx':
     env["DYLD_LIBRARY_PATH"] = xrePath
   else: # unix or linux?
     env["LD_LIBRARY_PATH"] = xrePath
-  args = [xpcshell, '-g', xrePath, '-j', '-s']
 
-  headfiles = ['-f', os.path.join(testharnessdir, 'head.js'),
-               '-e', 'function do_load_httpd_js() {load("%s");}' % httpdJSPath]
-  tailfiles = ['-f', os.path.join(testharnessdir, 'tail.js')]
-  if not interactive:
-    tailfiles += ['-e', '_execute_test();']
+  # xpcsRunArgs: <head.js> function to call to run the test.
+  # pStdout, pStderr: Parameter values for later |Popen()| call.
+  if interactive:
+    xpcsRunArgs = [
+      '-e', 'print("To start the test, type |_execute_test();|.");',
+      '-i']
+    pStdout = None
+    pStderr = None
+  else:
+    xpcsRunArgs = ['-e', '_execute_test();']
+    if sys.platform == 'os2emx':
+      pStdout = None 
+    else:
+      pStdout = PIPE
+    pStderr = STDOUT
+
+  # <head.js> has to be loaded by xpchell: it can't load itself.
+  xpcsCmd = [xpcshell, '-g', xrePath, '-j', '-s'] + \
+            ['-e', 'const _HTTPD_JS_PATH = "%s";' % httpdJSPath,
+             '-f', os.path.join(testharnessdir, 'head.js')]
+  xpcsTailFile = [os.path.join(testharnessdir, 'tail.js')]
 
   # |testPath| will be the optional path only, or |None|.
   # |singleFile| will be the optional test only, or |None|.
   singleFile = None
   if testPath:
     if testPath.endswith('.js'):
       # Split into path and file.
       if testPath.find('/') == -1:
@@ -157,51 +172,51 @@ def runTests(xpcshell, testdirs=[], xreP
   success = True
   for testdir in testdirs:
     if testPath and not testdir.endswith(testPath):
       continue
 
     testdir = os.path.abspath(testdir)
 
     # get the list of head and tail files from the directory
-    testheadfiles = []
+    testHeadFiles = []
     for f in sorted(glob(os.path.join(testdir, "head_*.js"))):
       if os.path.isfile(f):
-        testheadfiles += ['-f', f]
-    testtailfiles = []
-    for f in sorted(glob(os.path.join(testdir, "tail_*.js"))):
+        testHeadFiles += [f]
+    testTailFiles = []
+    # Tails are executed in the reverse order, to "match" heads order,
+    # as in "h1-h2-h3 then t3-t2-t1".
+    for f in reversed(sorted(glob(os.path.join(testdir, "tail_*.js")))):
       if os.path.isfile(f):
-        testtailfiles += ['-f', f]
+        testTailFiles += [f]
 
     # if a single test file was specified, we only want to execute that test
     testfiles = sorted(glob(os.path.join(testdir, "test_*.js")))
     if singleFile:
       if singleFile in [os.path.basename(x) for x in testfiles]:
         testfiles = [os.path.join(testdir, singleFile)]
       else: # not in this dir? skip it
         continue
 
+    cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
+                       for f in testHeadFiles])
+    cmdT = ", ".join(['"' + f.replace('\\', '/') + '"'
+                       for f in (testTailFiles + xpcsTailFile)])
+    cmdH = xpcsCmd + \
+           ['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
+           ['-e', 'const _TAIL_FILES = [%s];' % cmdT]
+
     # Now execute each test individually.
     for test in testfiles:
-      if sys.platform == 'os2emx':
-        pstdout = None 
-      else:
-        pstdout = PIPE
-      pstderr = STDOUT
-      interactiveargs = []
-      if interactive:
-        pstdout = None
-        pstderr = None
-        interactiveargs = ['-e', 'print("To start the test, type _execute_test();")', '-i']
-      full_args = args + headfiles + testheadfiles \
-                  + ['-f', test] \
-                  + tailfiles + testtailfiles + interactiveargs
-      proc = Popen(full_args, stdout=pstdout, stderr=pstderr,
-                   env=env, cwd=testdir)
-      # |stderr == None| as |pstderr| was either |None| or redirected to |stdout|.
+      # The test file will have to be loaded after the head files.
+      cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
+                      os.path.join(testdir, test).replace('\\', '/')]
+      proc = Popen(cmdH + cmdT + xpcsRunArgs,
+                   stdout=pStdout, stderr=pStderr, 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 re.search("^TEST-UNEXPECTED-FAIL", stdout, re.MULTILINE)):
         print """TEST-UNEXPECTED-FAIL | %s | test failed (with xpcshell return code: %d), see following log: