tap-functions.sh 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # -*- shell-script -*-
  2. #
  3. # Copyright (C) 2011-2017 Free Software Foundation, Inc.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2, or (at your option)
  8. # any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. # Helper functions used by TAP-producing tests of the Automake testsuite.
  18. #
  19. # IMPORTANT: All the functions defined in this file can *not* be used
  20. # from within a subshell, unless explicitly noted otherwise.
  21. #
  22. # The counts of the TAP test results seen so far: total count and
  23. # per-result counts.
  24. tap_count_=0
  25. tap_pass_count_=0
  26. tap_skip_count_=0
  27. tap_fail_count_=0
  28. tap_xfail_count_=0
  29. tap_xpass_count_=0
  30. # not COMMAND [ARGS...]
  31. # ---------------------
  32. # Run the given command and invert its exit status.
  33. not () { ! "$@"; }
  34. # plan_ [unknown|later|lazy|now|NUMBER-OF-PLANNED-TESTS]
  35. # ------------------------------------------------------
  36. # Print a TAP plan for the given number of tests. This must be called
  37. # before reporting any test result. If called with the special argument
  38. # "unknown" or "later", it will do nothing, expecting the calling script
  39. # to declare the plan later. If called with the special argument "lazy"
  40. # or "now", it will print a TAP plan that accounts for the number of tests
  41. # seen so far.
  42. plan_ ()
  43. {
  44. if test $# -eq 0; then
  45. bailout_ "plan_: missing argument"
  46. elif test $# -ge 2; then
  47. bailout_ "plan_: too many arguments"
  48. elif test x"$planned_" != x"none" && test x"$planned_" != x"later"; then
  49. bailout_ "plan_: called to many times"
  50. elif test x"$1" = x"unknown" || test x"$1" = x"later"; then
  51. # This means we want to get back later to declaring the TAP plan.
  52. planned_=later
  53. return 0
  54. elif test x"$1" = x"lazy" || test x"$1" = x"now"; then
  55. planned_=$tap_count_ # Number of test results seen so far.
  56. elif test $1 -ge 0; then
  57. planned_=$1
  58. else
  59. bailout_ "plan_: invalid argument '$1'"
  60. fi
  61. echo "1..$planned_"
  62. }
  63. planned_=none
  64. # diag_ [EXPLANATION]
  65. # ------------------
  66. # Report the given text as TAP diagnostic. Assumes the string denoting
  67. # TAP diagnostic lines is stored in the '$diag_string_' variable; this is
  68. # done to allow better interplay with TAP drivers that allow such a string
  69. # to be configured.
  70. diag_ ()
  71. {
  72. test $# -eq 0 || echo "$diag_string_ $*"
  73. }
  74. # Used by the 'diag_' function above. User-overridable.
  75. diag_string_="#"
  76. # warn_ [EXPLANATION]
  77. # ------------------
  78. # Give a warning (using TAP diagnostic).
  79. warn_ ()
  80. {
  81. case $# in
  82. 0) diag_ "WARNING: (unknown warning)";;
  83. *) diag_ "WARNING: $*";;
  84. esac
  85. }
  86. # result_ RESULT [-D DIRECTIVE] [-r REASON] [--] [DESCRIPTION...]
  87. # ---------------------------------------------------------------
  88. # Report a test case with the given RESULT (valid values are "ok" and
  89. # "not ok") and the given DESCRIPTION (if any). If DIRECTIVE is given
  90. # and non-empty (valid values being "TODO" and "SKIP"), it will be
  91. # reported too, with the REASON (if given) appended.
  92. result_ ()
  93. {
  94. set +x # Don't pollute the log files.
  95. test $# -gt 0 || bailout_ "result_: missing argument"
  96. tap_result_=$1; shift
  97. case $tap_result_ in
  98. "ok"|"not ok") ;;
  99. *) bailout_ "result_: invalid result '$tap_result'" ;;
  100. esac
  101. tap_directive_= tap_reason_=
  102. while test $# -gt 0; do
  103. case $1 in
  104. -D|--directive) tap_directive_=$2; shift;;
  105. -r|--reason) tap_reason_=$2; shift;;
  106. --) shift; break;;
  107. -*) bailout_ "result_: invalid option '$1'";;
  108. *) break;;
  109. esac
  110. shift
  111. done
  112. case $tap_directive_ in
  113. ""|TODO|SKIP) ;;
  114. *) bailout_ "result_: invalid directive '$directive_'" ;;
  115. esac
  116. tap_count_=$(($tap_count_ + 1))
  117. case $tap_result_,$tap_directive_ in
  118. ok,) # Passed.
  119. tap_pass_count_=$(($tap_pass_count_ + 1)) ;;
  120. not\ ok,TODO) # Expected failure.
  121. tap_xfail_count_=$(($tap_xfail_count_ + 1)) ;;
  122. not\ ok,*) # Failed.
  123. tap_fail_count_=$(($tap_fail_count_ + 1)) ;;
  124. ok,TODO) # Unexpected pass.
  125. tap_xpass_count_=$(($tap_xpass_count_ + 1)) ;;
  126. ok,SKIP) # Skipped.
  127. tap_skip_count_=$(($tap_skip_count_ + 1)) ;;
  128. *) # Can't happen.
  129. bailout_ "internal error in 'result_'" ;;
  130. esac
  131. tap_text_="$tap_result_ $tap_count_"
  132. if test x"$*" != x; then
  133. tap_text_="$tap_text_ - $*"
  134. fi
  135. if test x"$tap_directive_" != x; then
  136. tap_text_="$tap_text_ # $tap_directive_"${tap_reason_:+" $tap_reason_"}
  137. fi
  138. printf '%s\n' "$tap_text_"
  139. set -x # Restore shell xtraces.
  140. }
  141. # Shorthands for common usages of 'result_'.
  142. ok_ () { result_ 'ok' ${1+"$@"}; }
  143. not_ok_ () { result_ 'not ok' ${1+"$@"}; }
  144. skip_ () { result_ 'ok' -D SKIP ${1+"$@"}; }
  145. # skip_row_ COUNT [-r REASON] [--] [DESCRIPTION...]
  146. # -------------------------------------------------
  147. # Report a COUNT of skipped test, with the given reason and descriptions
  148. # (if any). Useful to avoid cascade failures in case a fair number of
  149. # tests depend on an earlier one that failed.
  150. skip_row_ ()
  151. {
  152. skip_count_=$1; shift
  153. for i_ in $(seq_ $skip_count_); do skip_ ${1+"$@"}; done
  154. }
  155. # skip_all_ [REASON ...]
  156. # ----------------------
  157. # Skip all the tests in a test script. Must be used before calling 'plan_'
  158. # or reporting any test result. Can't be used from within a subshell.
  159. skip_all_ ()
  160. {
  161. echo "1..0 # SKIP" ${1+"$@"}
  162. planned_=0
  163. exit 0
  164. }
  165. # bailout_ [REASON ...]
  166. # ---------------------
  167. # Stop the execution of the current test suite right now, due to an
  168. # unrecoverable error. Can be called at any point, but cannot be used
  169. # from within a subshell.
  170. bailout_ ()
  171. {
  172. echo 'Bail out!' ${1+"$@"}
  173. exit 99
  174. }
  175. # fatal_ [REASON ...]
  176. # -------------------
  177. # Same as 'bailout_'; for compatibility with 'plain-functions.sh'.
  178. fatal_ ()
  179. {
  180. bailout_ ${1+"$@"}
  181. }
  182. # framework_failure_ [REASON ...]
  183. # -------------------------------
  184. # Stop the execution of the current test suite right now, due to an
  185. # unrecoverable error in the set-up of the test case. Can be called
  186. # at any point, but cannot be used from within a subshell.
  187. framework_failure_ ()
  188. {
  189. bailout_ "set-up failure"${1+": $*"}
  190. }
  191. # command_ok_ TEST-DESCRIPTION [OPTIONS..] [--] CMD [ARGS...]
  192. # -----------------------------------------------------------
  193. # Helper subroutine for when a TAP result must be determined by the
  194. # outcome of a command.
  195. command_ok_ ()
  196. {
  197. tap_directive_= tap_reason_=
  198. test $# -gt 0 || bailout_ "command_ok_: missing argument"
  199. tap_description_=$1; shift
  200. while test $# -gt 0; do
  201. case $1 in
  202. -D|--directive) tap_directive_=$2; shift;;
  203. -r|--reason) tap_reason_=$2; shift;;
  204. --) shift; break;;
  205. -*) bailout_ "command_ok_: invalid option '$1'";;
  206. *) break;;
  207. esac
  208. shift
  209. done
  210. tap_result_="ok"; "$@" || tap_result_="not ok"
  211. result_ "$tap_result_" -D "$tap_directive_" -r "$tap_reason_" \
  212. -- "$tap_description_"
  213. }
  214. :