1 # ============================================================================ 2 # Copyright (c) Patrick LeBoutillier 3 # Copyright (c) 2011 University of Pennsylvania 4 # Copyright (c) 2011-2014 Andreas Schuh 7 # This program is free software; you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation; either version 2 of the License, or 12 # This program is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 17 # @sa http://testanything.org/wiki/index.php/Tap-functions 18 # ============================================================================ 20 ############################################################################## 22 # @brief Unit testing framework for BASH based on the Test Anything Protocol. 24 # @author Patrick LeBoutillier <patl at cpan.org> 26 # @note This file is a copy of the tap-functions file which is part of the 27 # JTap project (http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/). 28 # The original implementation has been modified by Andreas Schuh as 29 # part of the BASIS project at SBIA. 34 # plan_skip_all [REASON] 42 # is RESULT EXPECTED [NAME] 43 # isnt RESULT EXPECTED [NAME] 44 # like RESULT PATTERN [NAME] 45 # unlike RESULT PATTERN [NAME] 52 # skip [CONDITION] [REASON] [NB_TESTS=1] 54 # skip $feature_not_present "feature not present" 2 || 61 # Specify TODO mode by setting the TODO variable: 63 # TODO="not implemented yet" 64 # ok $result "some not implemented test" 75 # #! /usr/bin/env bash 84 # is ${USER} ${me} "I am myself" 85 # like ${HOME} ${me} "My home is mine" 86 # like "`id`" ${me} "My id matches myself" 93 # # same thing using okx shortcut 97 # # test only for root 99 # [[ "`id -u`" != "0" ]] 101 # skip ${i_am_not_root} "Must be root" || 109 # TODO="figure out how to become root..." 110 # okx [ "$HOME" == "/root" ] 114 ############################################################################## 116 # return if already loaded 117 [ -n
"${SHTAP_VERSION:-}" ] &&
return 0
121 .
"`cd -P -- \`dirname -- "${BASH_SOURCE}
"\` && pwd`/core.sh" || exit 1 #
match()
123 readonly _SHTAP_FILENAME=
'' 131 _shtap_expected_tests=0
132 _shtap_executed_tests=0
133 _shtap_failed_tests=0
135 # used to call _cleanup() on shell exit 136 trap _shtap_exit EXIT
138 trap _shtap_exit TERM
140 # ============================================================================ 142 # ============================================================================ 144 # ---------------------------------------------------------------------------- 145 ## @brief Choose not to plan number of tests in advance. 148 [ ${_shtap_plan_set} -ne 0 ] && _shtap_die
"You tried to plan twice!" 156 # ---------------------------------------------------------------------------- 157 ## @brief Plan to skip all tests. 160 local reason=${1:-
''}
162 [ ${_shtap_plan_set} -ne 0 ] && _shtap_die
"You tried to plan twice!" 164 _shtap_print_plan 0
"Skip ${reason}" 173 # ---------------------------------------------------------------------------- 174 ## @brief Plan a certain number of tests and stick to it. 179 [ ${_shtap_plan_set} -ne 0 ] && _shtap_die
"You tried to plan twice!" 180 [ ${tests} -eq 0 ] && _shtap_die
"You said to run 0 tests! You've got to run something." 182 _shtap_print_plan ${tests}
183 _shtap_expected_tests=${tests}
189 # ---------------------------------------------------------------------------- 190 ## @brief Print plan. 191 function _shtap_print_plan
194 local directive=${2:-
''}
196 echo -n
"1..${tests}" 197 [[ -n
"${directive}" ]] && echo -n
" # ${directive}" 201 # ============================================================================ 203 # ============================================================================ 205 # ---------------------------------------------------------------------------- 206 ## @brief Pass in any case and print reason. 213 # ---------------------------------------------------------------------------- 214 ## @brief Fail in any case and print reason. 221 # ============================================================================ 223 # ============================================================================ 225 # ---------------------------------------------------------------------------- 226 ## @brief Evaluate test expression and fail if it does not evaluate to 0 or 227 # check return value of function. 229 # This is the workhorse method that actually prints the tests result. 231 # @param [in] expression Test expression or return value. 232 # @param [in] name Name of test. 235 local expression=${1:?}
238 [ ${_shtap_plan_set} -eq 0 ] && _shtap_die
"You tried to run a test without a plan! Gotta have a plan." 240 (( _shtap_executed_tests++ ))
242 if [ -n
"${name}" ]; then
243 if match "${name}" "^[0-9]+$"; then
244 diag " You named your test '${name}'. You shouldn't use numbers for your test names." 245 diag " Very confusing." 249 local match=`expr
"${expression}" :
'\([0-9]*\)'`
251 if [ -z
"${expression}" ]; then
253 elif [ -n
"${match}" -a
"${expression}" =
"${match}" ]; then
254 [ ${expression} -ne 0 ] && result=1
256 ( eval ${expression} ) >/dev/null 2>&1
257 [ $? -ne 0 ] && result=1
260 if [ ${result} -ne 0 ]; then
262 (( _shtap_failed_tests++ ))
264 echo -n
"ok ${_shtap_executed_tests}" 266 if [ -n
"${name}" ]; then
268 echo -n
" - ${ename}" 271 if [ -n
"${TODO}" ]; then
272 echo -n
" # TODO ${TODO}" ;
273 if [ ${result} -ne 0 ]; then
274 (( _shtap_failed_tests-- ))
279 if [ ${result} -ne 0 ]; then
280 local file=
'_SHTAP_FILENAME' 285 local bt=$(caller ${i})
286 while match
"${bt}" "${_SHTAP_FILENAME}$";
do 291 eval $(caller ${i} | (read line func file; echo
"backtrace=\"${file}:${func}() at line ${line}.\""))
294 [ -n
"${TODO}" ] && t=
"(TODO) " 296 if [ -n
"${name}" ]; then
297 diag " Failed ${t}test '${name}'" 298 diag " in ${backtrace}" 300 diag " Failed ${t}test in ${backtrace}" 307 # ---------------------------------------------------------------------------- 308 ## @brief Execute command and check return value. 310 # @param [in] command Command to run. 316 diag "Output of '${command}':" 317 ${command} |
while read line;
do 320 ok ${PIPESTATUS[0]}
"${command}" 323 # ---------------------------------------------------------------------------- 324 ## @brief Compare actual and expected result. 326 # @param [in] result Actual result. 327 # @param [in] expected Expected result. 328 function _shtap_equals
333 if [[
"${result}" ==
"${expected}" ]] ; then
340 # ---------------------------------------------------------------------------- 341 ## @brief Diagnostic message for is(). 343 # @param [in] result Actual result. 344 # @param [in] expected Expected result. 345 function _shtap_is_diag
350 diag " got: '${result}'" 351 diag " expected: '${expected}'" 354 # ---------------------------------------------------------------------------- 355 ## @brief Test whether a given result is equal to the expected result. 357 # @param [in] result Actual result. 358 # @param [in] expected Expected result. 359 # @param [in] name Optional name of test. 361 # @returns Whether the results are equal. 363 # @retval 0 On equality. 364 # @retval 1 Otherwise. 371 _shtap_equals
"${result}" "${expected}" 375 [ ${r} -ne 0 ] && _shtap_is_diag
"${result}" "${expected}" 379 # ---------------------------------------------------------------------------- 380 ## @brief Test whether a given result is not equal the expected result. 382 # @param [in] result Actual result. 383 # @param [in] expected Expected result. 384 # @param [in] name Optional name of test. 386 # @returns Whether the results were not equal. 388 # @retval 0 Otherwise. 389 # @retval 1 On equality. 396 _shtap_equals
"${result}" "${expected}" 400 [ ${r} -ne 0 ] && _shtap_is_diag
"${result}" "${expected}" 404 # ---------------------------------------------------------------------------- 405 ## @brief Test whether a given result matches an expected pattern. 407 # @param [in] result Actual result. 408 # @param [in] pattern Expected pattern. 409 # @param [in] name Optional name of test. 411 # @returns Whether the result matched the pattern. 413 # @retval 0 On match. 414 # @retval 1 Otherwise. 421 match
"${result}" "${pattern}" 425 [ ${r} -ne 0 ] &&
diag " '${result}' doesn't match '${pattern}'" 429 # ---------------------------------------------------------------------------- 430 ## @brief Test whether a given result does not match an expected pattern. 432 # @param [in] result Actual result. 433 # @param [in] pattern Expected pattern. 434 # @param [in] name Optional name of test. 436 # @returns Whether the result did not match the pattern. 438 # @retval 0 Otherwise. 439 # @retval 1 On match. 446 match
"${result}" "${pattern}" 450 [ ${r} -ne 0 ] &&
diag " '${result}' matches '${pattern}'" 454 # ============================================================================ 456 # ============================================================================ 458 # ---------------------------------------------------------------------------- 459 ## @brief Skip tests under a certain condition. 461 # @param [in] condition The condition for skipping the tests. 462 # If 0, the tests are skipped, otherwise not. 463 # @param [in] reason An explanation for why skipping the tests. 464 # @param [in] n The number of tests which will be skipped. 466 # @returns Whether the tests were skipped. 468 # @retval 0 If tests are to be skipped. 469 # @retval 1 Otherwise. 472 local condition=${1:?}
473 local reason=${2:-
''}
476 if [ ${condition} -eq 0 ]; then
478 for (( i=0 ; i<$n ; i++ ));
do 479 (( _shtap_executed_tests++ ))
480 echo
"ok ${_shtap_executed_tests} # skip: ${reason}" 488 # ============================================================================
490 # ============================================================================
492 # ----------------------------------------------------------------------------
493 ## @brief Print diagnostic message.
495 # @param [in]
msg Diagnostic message.
502 if [ -n
"${msg}" ]; then
509 # ============================================================================ 511 # ============================================================================ 513 # ---------------------------------------------------------------------------- 516 # @param [in] reason Reason for bailing out. 518 # @returns Nothing. Instead, exits the process with error code 255. 521 local reason=${1:-
''}
523 echo
"Bail out! ${reason}" >&2
527 # ---------------------------------------------------------------------------- 528 ## @brief Abort test execution. 530 # @param [in] reason Reason for aborting the test execution. 532 # @returns Nothing. Instead, exits the process with error code 255. 535 local reason=${1:-
'<unspecified error>'}
542 # ---------------------------------------------------------------------------- 543 ## @brief Cleaning up after execution of tests and see if plan was fulfilled. 544 function _shtap_cleanup
546 local rc=0 #
return code
548 if [ ${_shtap_plan_set} -eq 0 ]; then
549 diag "Looks like your test died before it could output anything." 553 if [ ${_shtap_test_died} -ne 0 ]; then
554 diag "Looks like your test died just after ${_shtap_executed_tests}." 558 if [ ${_shtap_skip_all} -eq 0 -a ${_shtap_no_plan} -ne 0 ]; then
559 _shtap_print_plan ${_shtap_executed_tests}
563 if [ ${_shtap_no_plan} -eq 0 -a ${_shtap_expected_tests} -lt ${_shtap_executed_tests} ]; then
565 [ ${_shtap_expected_tests} -gt 1 ] && s=
's' 566 local extra=$(( _shtap_executed_tests - _shtap_expected_tests ))
567 diag "Looks like you planned ${_shtap_expected_tests} test${s} but ran ${extra} extra." 571 if [ ${_shtap_no_plan} -eq 0 -a ${_shtap_expected_tests} -gt ${_shtap_executed_tests} ]; then
573 [ ${_shtap_expected_tests} -gt 1 ] && s=
's' 574 diag "Looks like you planned ${_shtap_expected_tests} test${s} but only ran ${_shtap_executed_tests}." 577 if [ ${_shtap_failed_tests} -gt 0 ]; then
579 [ ${_shtap_failed_tests} -gt 1 ] && s=
's' 580 diag "Looks like you failed ${_shtap_failed_tests} test${s} of ${_shtap_executed_tests}." 586 # ---------------------------------------------------------------------------- 587 ## @brief Calculate exit status indicating number of failed or extra tests. 588 function _shtap_exit_status
590 if [ ${_shtap_no_plan} -ne 0 -o ${_shtap_plan_set} -eq 0 ]; then
591 return ${_shtap_failed_tests}
594 if [ ${_shtap_expected_tests} -lt ${_shtap_executed_tests} ]; then
595 return $(( _shtap_executed_tests - _shtap_expected_tests ))
598 return $(( _shtap_failed_tests + ( _shtap_expected_tests - _shtap_executed_tests )))
601 # ----------------------------------------------------------------------------
602 ## @brief Terminate execution of tests.
606 if [ -z
"${rc}" ]; then
613 [ ${alt_rc} -ne 0 ] && rc=${alt_rc}
function SHTAP_BAIL_OUT(in reason)
Bail out.
function ok(in expression, in name)
Evaluate test expression and fail if it does not evaluate to 0 or check return value of function...
function is(in result, in expected, in name)
Test whether a given result is equal to the expected result.
function isnt(in result, in expected, in name)
Test whether a given result is not equal the expected result.
function plan_tests()
Plan a certain number of tests and stick to it.
function unlike(in result, in pattern, in name)
Test whether a given result does not match an expected pattern.
function skip(in condition, in reason, in n)
Skip tests under a certain condition.
function plan_skip_all()
Plan to skip all tests.
function match(in value, in pattern)
This function implements a more portable way to do pattern matching.
function pass()
Pass in any case and print reason.
function plan_no_plan()
Choose not to plan number of tests in advance.
function like(in result, in pattern, in name)
Test whether a given result matches an expected pattern.
function okx(in command)
Execute command and check return value.
function diag(in msg)
Print diagnostic message.
function fail()
Fail in any case and print reason.