tests: avoid a spurious failure on MSYS
[platform/upstream/automake.git] / lib / tap-driver.sh
index 16a4e04..19aa531 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2011 Free Software Foundation, Inc.
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
 # bugs to <bug-automake@gnu.org> or send patches to
 # <automake-patches@gnu.org>.
 
-scriptversion=2011-08-24.09; # UTC
+scriptversion=2011-12-27.17; # UTC
 
 # Make unconditional expansion of undefined variables an error.  This
 # helps a lot in preventing typo-related bugs.
@@ -115,15 +115,34 @@ else
   init_colors=''
 fi
 
-{
-  { if test $merge -gt 0; then
+# :; is there to work around a bug in bash 3.2 (and earlier) which
+# does not always set '$?' properly on redirection failure.
+# See the Autoconf manual for more details.
+:;{
+  (
+    # Ignore common signals (in this subshell only!), to avoid potential
+    # problems with Korn shells.  Some Korn shells are known to propagate
+    # to themselves signals that have killed a child process they were
+    # waiting for; this is done at least for SIGINT (and usually only for
+    # it, in truth).  Without the `trap' below, such a behaviour could
+    # cause a premature exit in the current subshell, e.g., in case the
+    # test command it runs gets terminated by a SIGINT.  Thus, the awk
+    # script we are piping into would never seen the exit status it
+    # expects on its last input line (which is displayed below by the
+    # last `echo $?' statement), and would thus die reporting an internal
+    # error.
+    # For more information, see the Autoconf manual and the threads:
+    # <http://lists.gnu.org/archive/html/bug-autoconf/2011-09/msg00004.html>
+    # <http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/004121.html>
+    trap : 1 3 2 13 15
+    if test $merge -gt 0; then
       exec 2>&1
     else
       exec 2>&3
     fi
     "$@"
     echo $?
-  } | LC_ALL=C ${AM_TAP_AWK-awk} \
+  ) | LC_ALL=C ${AM_TAP_AWK-awk} \
         -v me="$me" \
         -v test_script_name="$test_name" \
         -v log_file="$log_file" \
@@ -195,35 +214,35 @@ function get_global_test_result()
 {
     if ("ERROR" in test_results_seen)
       return "ERROR"
+    if ("FAIL" in test_results_seen || "XPASS" in test_results_seen)
+      return "FAIL"
     all_skipped = 1
     for (k in test_results_seen)
       if (k != "SKIP")
         all_skipped = 0
     if (all_skipped)
       return "SKIP"
-    if ("FAIL" in test_results_seen || "XPASS" in test_results_seen)
-      return "FAIL"
     return "PASS";
 }
 
-function stringify_result_obj(obj)
+function stringify_result_obj(result_obj)
 {
-  if (obj["is_unplanned"] || obj["number"] != testno)
+  if (result_obj["is_unplanned"] || result_obj["number"] != testno)
     return "ERROR"
 
   if (plan_seen == LATE_PLAN)
     return "ERROR"
 
   if (result_obj["directive"] == "TODO")
-    return obj["is_ok"] ? "XPASS" : "XFAIL"
+    return result_obj["is_ok"] ? "XPASS" : "XFAIL"
 
   if (result_obj["directive"] == "SKIP")
-    return obj["is_ok"] ? "SKIP" : COOKED_FAIL;
+    return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL;
 
   if (length(result_obj["directive"]))
       abort("in function stringify_result_obj()")
 
-  return obj["is_ok"] ? COOKED_PASS : COOKED_FAIL
+  return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL
 }
 
 function decorate_result(result)
@@ -294,7 +313,7 @@ function handle_tap_result()
   report(stringify_result_obj(result_obj), details)
 }
 
-# `skip_reason` should be emprty whenever planned > 0.
+# `skip_reason` should be empty whenever planned > 0.
 function handle_tap_plan(planned, skip_reason)
 {
   planned += 0 # Avoid getting confused if, say, `planned` is "00"
@@ -329,11 +348,9 @@ function handle_tap_plan(planned, skip_reason)
 
 function extract_tap_comment(line)
 {
-  # FIXME: verify there is not an off-by-one bug here.
   if (index(line, diag_string) == 1)
     {
       # Strip leading `diag_string` from `line`.
-      # FIXME: verify there is not an off-by-one bug here.
       line = substr(line, length(diag_string) + 1)
       # And strip any leading and trailing whitespace left.
       sub("^[ \t]*", "", line)
@@ -384,7 +401,6 @@ function setup_result_obj(line)
   result_obj["directive"] = ""
   result_obj["explanation"] = ""
 
-  # TODO: maybe we should allow a way to escape "#"?
   if (index(line, "#") == 0)
     return # No possible directive, nothing more to do.
 
@@ -400,6 +416,20 @@ function setup_result_obj(line)
   if (!pos)
     return
 
+  # Let`s now see if the TAP directive has been escaped.  For example:
+  #  escaped:     ok \# SKIP
+  #  not escaped: ok \\# SKIP
+  #  escaped:     ok \\\\\# SKIP
+  #  not escaped: ok \ # SKIP
+  if (substr(line, pos, 1) == "#")
+    {
+      bslash_count = 0
+      for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--)
+        bslash_count += 1
+      if (bslash_count % 2)
+        return # Directive was escaped.
+    }
+
   # Strip the directive and its explanation (if any) from the test
   # description.
   result_obj["description"] = substr(line, 1, pos - 1)
@@ -429,7 +459,16 @@ function get_test_exit_message(status)
     exit_details = " (command not found?)"
   else if (status >= 128 && status <= 255)
     exit_details = sprintf(" (terminated by signal %d?)", status - 128)
-  else if (status >= 256)
+  else if (status > 256 && status <= 384)
+    # We used to report an "abnormal termination" here, but some Korn
+    # shells, when a child process die due to signal number n, can leave
+    # in $? an exit status of 256+n instead of the more standard 128+n.
+    # Apparently, both behaviours are allowed by POSIX (2008), so be
+    # prepared to handle them both.  See also Austing Group report ID
+    # 0000051 <http://www.austingroupbugs.net/view.php?id=51>
+    exit_details = sprintf(" (terminated by signal %d?)", status - 256)
+  else
+    # Never seen in practice.
     exit_details = " (abnormal termination)"
   return sprintf("exited with status %d%s", status, exit_details)
 }
@@ -537,12 +576,16 @@ while (1)
         handle_tap_plan(0, $0)
       }
     # "Bail out!" magic.
-    else if ($0 ~ /^Bail out!/)
+    # Older versions of prove and TAP::Harness (e.g., 3.17) did not
+    # recognize a "Bail out!" directive when preceded by leading
+    # whitespace, but more modern versions (e.g., 3.23) do.  So we
+    # emulate the latter, "more modern" behaviour.
+    else if ($0 ~ /^[ \t]*Bail out!/)
       {
         bailed_out = 1
         # Get the bailout message (if any), with leading and trailing
         # whitespace stripped.  The message remains stored in `$0`.
-        sub("^Bail out![ \t]*", "");
+        sub("^[ \t]*Bail out![ \t]*", "");
         sub("[ \t]*$", "");
         # Format the error message for the
         bailout_message = "Bail out!"