3 # vim:et:ft=sh:sts=2:sw=2
5 # Copyright 2008 Kate Ward. All Rights Reserved.
6 # Released under the LGPL (GNU Lesser General Public License)
8 # shUnit2 -- Unit testing framework for Unix shell scripts.
9 # http://code.google.com/p/shunit2/
11 # Author: kate.ward@forestent.com (Kate Ward)
13 # shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is
14 # based on the popular JUnit unit testing framework for Java.
16 # return if shunit already loaded
17 [ -n "${SHUNIT_VERSION:-}" ] && exit 0
18 SHUNIT_VERSION
='2.1.7pre'
20 # return values that scripts can use
26 _shunit_warn
() { echo "shunit2:WARN $@" >&2; }
27 _shunit_error
() { echo "shunit2:ERROR $@" >&2; }
28 _shunit_fatal
() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; }
30 # determine some reasonable command defaults
31 __SHUNIT_UNAME_S
=`uname -s`
32 case "${__SHUNIT_UNAME_S}" in
33 BSD
) __SHUNIT_EXPR_CMD
='gexpr' ;;
34 *) __SHUNIT_EXPR_CMD
='expr' ;;
37 # commands a user can override if needed
38 SHUNIT_EXPR_CMD
=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}}
40 # enable strict mode by default
41 SHUNIT_STRICT
=${SHUNIT_STRICT:-${SHUNIT_TRUE}}
43 # specific shell checks
44 if [ -n "${ZSH_VERSION:-}" ]; then
45 setopt |
grep "^shwordsplit$" >/dev
/null
46 if [ $?
-ne ${SHUNIT_TRUE} ]; then
47 _shunit_fatal
'zsh shwordsplit option is required for proper operation'
49 if [ -z "${SHUNIT_PARENT:-}" ]; then
50 _shunit_fatal
"zsh does not pass \$0 through properly. please declare \
51 \"SHUNIT_PARENT=\$0\" before calling shUnit2"
59 __SHUNIT_ASSERT_MSG_PREFIX
='ASSERT:'
60 __SHUNIT_MODE_SOURCED
='sourced'
61 __SHUNIT_MODE_STANDALONE
='standalone'
62 __SHUNIT_PARENT
=${SHUNIT_PARENT:-$0}
64 # set the constants readonly
65 __shunit_constants
=`set |grep '^__SHUNIT_' |cut -d= -f1`
66 echo "${__shunit_constants}" |
grep '^Binary file' >/dev
/null
&& \
67 __shunit_constants
=`set |grep -a '^__SHUNIT_' |cut -d= -f1`
68 for __shunit_const
in ${__shunit_constants}; do
69 if [ -z "${ZSH_VERSION:-}" ]; then
70 readonly ${__shunit_const}
72 case ${ZSH_VERSION} in
73 [123].
*) readonly ${__shunit_const} ;;
74 *) readonly -g ${__shunit_const} # declare readonly constants globally
78 unset __shunit_const __shunit_constants
85 __shunit_lineno
='' # line number of executed test
86 __shunit_mode
=${__SHUNIT_MODE_SOURCED} # operating mode
87 __shunit_reportGenerated
=${SHUNIT_FALSE} # is report generated
88 __shunit_script
='' # filename of unittest script (standalone mode)
89 __shunit_skip
=${SHUNIT_FALSE} # is skipping enabled
90 __shunit_suite
='' # suite of tests to execute
93 __shunit_testSuccess
=${SHUNIT_TRUE}
95 __shunit_testsPassed
=0
96 __shunit_testsFailed
=0
99 __shunit_assertsTotal
=0
100 __shunit_assertsPassed
=0
101 __shunit_assertsFailed
=0
102 __shunit_assertsSkipped
=0
105 _SHUNIT_LINENO_
='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi'
107 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
114 # Assert that two values are equal to one another.
117 # message: string: failure message [optional]
118 # expected: string: expected value
119 # actual: string: actual value
121 # integer: success (TRUE/FALSE/ERROR constant)
125 if [ $# -lt 2 -o $# -gt 3 ]; then
126 _shunit_error
"assertEquals() requires two or three arguments; $# given"
127 _shunit_error
"1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}"
128 return ${SHUNIT_ERROR}
130 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
132 shunit_message_
=${__shunit_lineno}
133 if [ $# -eq 3 ]; then
134 shunit_message_
="${shunit_message_}$1"
140 shunit_return
=${SHUNIT_TRUE}
141 if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then
144 failNotEquals
"${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}"
145 shunit_return
=${SHUNIT_FALSE}
148 unset shunit_message_ shunit_expected_ shunit_actual_
149 return ${shunit_return}
151 _ASSERT_EQUALS_
='eval assertEquals --lineno "${LINENO:-}"'
153 # Assert that two values are not equal to one another.
156 # message: string: failure message [optional]
157 # expected: string: expected value
158 # actual: string: actual value
160 # integer: success (TRUE/FALSE/ERROR constant)
164 if [ $# -lt 2 -o $# -gt 3 ]; then
165 _shunit_error
"assertNotEquals() requires two or three arguments; $# given"
166 return ${SHUNIT_ERROR}
168 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
170 shunit_message_
=${__shunit_lineno}
171 if [ $# -eq 3 ]; then
172 shunit_message_
="${shunit_message_}$1"
178 shunit_return
=${SHUNIT_TRUE}
179 if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then
182 failSame
"${shunit_message_}" "$@"
183 shunit_return
=${SHUNIT_FALSE}
186 unset shunit_message_ shunit_expected_ shunit_actual_
187 return ${shunit_return}
189 _ASSERT_NOT_EQUALS_
='eval assertNotEquals --lineno "${LINENO:-}"'
191 # Assert that a value is null (i.e. an empty string)
194 # message: string: failure message [optional]
195 # actual: string: actual value
197 # integer: success (TRUE/FALSE/ERROR constant)
201 if [ $# -lt 1 -o $# -gt 2 ]; then
202 _shunit_error
"assertNull() requires one or two arguments; $# given"
203 return ${SHUNIT_ERROR}
205 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
207 shunit_message_
=${__shunit_lineno}
208 if [ $# -eq 2 ]; then
209 shunit_message_
="${shunit_message_}$1"
212 assertTrue
"${shunit_message_}" "[ -z '$1' ]"
215 unset shunit_message_
216 return ${shunit_return}
218 _ASSERT_NULL_
='eval assertNull --lineno "${LINENO:-}"'
220 # Assert that a value is not null (i.e. a non-empty string)
223 # message: string: failure message [optional]
224 # actual: string: actual value
226 # integer: success (TRUE/FALSE/ERROR constant)
230 if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null
231 _shunit_error
"assertNotNull() requires one or two arguments; $# given"
232 return ${SHUNIT_ERROR}
234 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
236 shunit_message_
=${__shunit_lineno}
237 if [ $# -eq 2 ]; then
238 shunit_message_
="${shunit_message_}$1"
241 shunit_actual_
=`_shunit_escapeCharactersInString "${1:-}"`
242 test -n "${shunit_actual_}"
243 assertTrue
"${shunit_message_}" $?
246 unset shunit_actual_ shunit_message_
247 return ${shunit_return}
249 _ASSERT_NOT_NULL_
='eval assertNotNull --lineno "${LINENO:-}"'
251 # Assert that two values are the same (i.e. equal to one another).
254 # message: string: failure message [optional]
255 # expected: string: expected value
256 # actual: string: actual value
258 # integer: success (TRUE/FALSE/ERROR constant)
262 if [ $# -lt 2 -o $# -gt 3 ]; then
263 _shunit_error
"assertSame() requires two or three arguments; $# given"
264 return ${SHUNIT_ERROR}
266 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
268 shunit_message_
=${__shunit_lineno}
269 if [ $# -eq 3 ]; then
270 shunit_message_
="${shunit_message_}$1"
273 assertEquals
"${shunit_message_}" "$1" "$2"
276 unset shunit_message_
277 return ${shunit_return}
279 _ASSERT_SAME_
='eval assertSame --lineno "${LINENO:-}"'
281 # Assert that two values are not the same (i.e. not equal to one another).
284 # message: string: failure message [optional]
285 # expected: string: expected value
286 # actual: string: actual value
288 # integer: success (TRUE/FALSE/ERROR constant)
292 if [ $# -lt 2 -o $# -gt 3 ]; then
293 _shunit_error
"assertNotSame() requires two or three arguments; $# given"
294 return ${SHUNIT_ERROR}
296 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
298 shunit_message_
=${__shunit_lineno}
299 if [ $# -eq 3 ]; then
300 shunit_message_
="${shunit_message_:-}$1"
303 assertNotEquals
"${shunit_message_}" "$1" "$2"
306 unset shunit_message_
307 return ${shunit_return}
309 _ASSERT_NOT_SAME_
='eval assertNotSame --lineno "${LINENO:-}"'
311 # Assert that a value or shell test condition is true.
313 # In shell, a value of 0 is true and a non-zero value is false. Any integer
314 # value passed can thereby be tested.
316 # Shell supports much more complicated tests though, and a means to support
317 # them was needed. As such, this function tests that conditions are true or
318 # false through evaluation rather than just looking for a true or false.
320 # The following test will succeed:
322 # assertTrue "[ 34 -gt 23 ]"
323 # The folloing test will fail with a message:
325 # assertTrue "test failed" "[ -r '/non/existant/file' ]"
328 # message: string: failure message [optional]
329 # condition: string: integer value or shell conditional statement
331 # integer: success (TRUE/FALSE/ERROR constant)
335 if [ $# -lt 1 -o $# -gt 2 ]; then
336 _shunit_error
"assertTrue() takes one or two arguments; $# given"
337 return ${SHUNIT_ERROR}
339 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
341 shunit_message_
=${__shunit_lineno}
342 if [ $# -eq 2 ]; then
343 shunit_message_
="${shunit_message_}$1"
348 # see if condition is an integer, i.e. a return value
349 shunit_match_
=`expr "${shunit_condition_}" : '\([0-9]*\)'`
350 shunit_return
=${SHUNIT_TRUE}
351 if [ -z "${shunit_condition_}" ]; then
353 shunit_return
=${SHUNIT_FALSE}
354 elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ]
356 # possible return value. treating 0 as true, and non-zero as false.
357 [ ${shunit_condition_} -ne 0 ] && shunit_return
=${SHUNIT_FALSE}
359 # (hopefully) a condition
360 ( eval ${shunit_condition_} ) >/dev
/null
2>&1
361 [ $?
-ne 0 ] && shunit_return
=${SHUNIT_FALSE}
365 if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then
368 _shunit_assertFail
"${shunit_message_}"
371 unset shunit_message_ shunit_condition_ shunit_match_
372 return ${shunit_return}
374 _ASSERT_TRUE_
='eval assertTrue --lineno "${LINENO:-}"'
376 # Assert that a value or shell test condition is false.
378 # In shell, a value of 0 is true and a non-zero value is false. Any integer
379 # value passed can thereby be tested.
381 # Shell supports much more complicated tests though, and a means to support
382 # them was needed. As such, this function tests that conditions are true or
383 # false through evaluation rather than just looking for a true or false.
385 # The following test will succeed:
387 # assertFalse "[ 'apples' = 'oranges' ]"
388 # The folloing test will fail with a message:
390 # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]"
393 # message: string: failure message [optional]
394 # condition: string: integer value or shell conditional statement
396 # integer: success (TRUE/FALSE/ERROR constant)
400 if [ $# -lt 1 -o $# -gt 2 ]; then
401 _shunit_error
"assertFalse() quires one or two arguments; $# given"
402 return ${SHUNIT_ERROR}
404 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
406 shunit_message_
=${__shunit_lineno}
407 if [ $# -eq 2 ]; then
408 shunit_message_
="${shunit_message_}$1"
413 # see if condition is an integer, i.e. a return value
414 shunit_match_
=`expr "${shunit_condition_}" : '\([0-9]*\)'`
415 shunit_return
=${SHUNIT_TRUE}
416 if [ -z "${shunit_condition_}" ]; then
418 shunit_return
=${SHUNIT_FALSE}
419 elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ]
421 # possible return value. treating 0 as true, and non-zero as false.
422 [ ${shunit_condition_} -eq 0 ] && shunit_return
=${SHUNIT_FALSE}
424 # (hopefully) a condition
425 ( eval ${shunit_condition_} ) >/dev
/null
2>&1
426 [ $?
-eq 0 ] && shunit_return
=${SHUNIT_FALSE}
430 if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then
433 _shunit_assertFail
"${shunit_message_}"
436 unset shunit_message_ shunit_condition_ shunit_match_
437 return ${shunit_return}
439 _ASSERT_FALSE_
='eval assertFalse --lineno "${LINENO:-}"'
441 #-----------------------------------------------------------------------------
445 # Records a test failure.
448 # message: string: failure message [optional]
450 # integer: success (TRUE/FALSE/ERROR constant)
454 if [ $# -gt 1 ]; then
455 _shunit_error
"fail() requires zero or one arguments; $# given"
456 return ${SHUNIT_ERROR}
458 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
460 shunit_message_
=${__shunit_lineno}
461 if [ $# -eq 1 ]; then
462 shunit_message_
="${shunit_message_}$1"
466 _shunit_assertFail
"${shunit_message_}"
468 unset shunit_message_
469 return ${SHUNIT_FALSE}
471 _FAIL_
='eval fail --lineno "${LINENO:-}"'
473 # Records a test failure, stating two values were not equal.
476 # message: string: failure message [optional]
477 # expected: string: expected value
478 # actual: string: actual value
480 # integer: success (TRUE/FALSE/ERROR constant)
484 if [ $# -lt 2 -o $# -gt 3 ]; then
485 _shunit_error
"failNotEquals() requires one or two arguments; $# given"
486 return ${SHUNIT_ERROR}
488 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
490 shunit_message_
=${__shunit_lineno}
491 if [ $# -eq 3 ]; then
492 shunit_message_
="${shunit_message_}$1"
498 _shunit_assertFail
"${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>"
500 unset shunit_message_ shunit_expected_ shunit_actual_
501 return ${SHUNIT_FALSE}
503 _FAIL_NOT_EQUALS_
='eval failNotEquals --lineno "${LINENO:-}"'
505 # Records a test failure, stating two values should have been the same.
508 # message: string: failure message [optional]
509 # expected: string: expected value
510 # actual: string: actual value
512 # integer: success (TRUE/FALSE/ERROR constant)
516 if [ $# -lt 2 -o $# -gt 3 ]; then
517 _shunit_error
"failSame() requires two or three arguments; $# given"
518 return ${SHUNIT_ERROR}
520 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
522 shunit_message_
=${__shunit_lineno}
523 if [ $# -eq 3 ]; then
524 shunit_message_
="${shunit_message_}$1"
528 _shunit_assertFail
"${shunit_message_:+${shunit_message_} }expected not same"
530 unset shunit_message_
531 return ${SHUNIT_FALSE}
533 _FAIL_SAME_
='eval failSame --lineno "${LINENO:-}"'
535 # Records a test failure, stating two values were not equal.
537 # This is functionally equivalent to calling failNotEquals().
540 # message: string: failure message [optional]
541 # expected: string: expected value
542 # actual: string: actual value
544 # integer: success (TRUE/FALSE/ERROR constant)
548 if [ $# -lt 2 -o $# -gt 3 ]; then
549 _shunit_error
"failNotEquals() requires one or two arguments; $# given"
550 return ${SHUNIT_ERROR}
552 _shunit_shouldSkip
&& return ${SHUNIT_TRUE}
554 shunit_message_
=${__shunit_lineno}
555 if [ $# -eq 3 ]; then
556 shunit_message_
="${shunit_message_}$1"
559 failNotEquals
"${shunit_message_}" "$1" "$2"
562 unset shunit_message_
563 return ${shunit_return}
565 _FAIL_NOT_SAME_
='eval failNotSame --lineno "${LINENO:-}"'
567 #-----------------------------------------------------------------------------
571 # Force remaining assert and fail functions to be "skipped".
573 # This function forces the remaining assert and fail functions to be "skipped",
574 # i.e. they will have no effect. Each function skipped will be recorded so that
575 # the total of asserts and fails will not be altered.
581 __shunit_skip
=${SHUNIT_TRUE}
584 # Resume the normal recording behavior of assert and fail calls.
590 __shunit_skip
=${SHUNIT_FALSE}
593 # Returns the state of assert and fail call skipping.
598 # boolean: (TRUE/FALSE constant)
601 return ${__shunit_skip}
604 #-----------------------------------------------------------------------------
608 # Stub. This function should contains all unit test calls to be made.
610 # DEPRECATED (as of 2.1.0)
612 # This function can be optionally overridden by the user in their test suite.
614 # If this function exists, it will be called when shunit2 is sourced. If it
615 # does not exist, shunit2 will search the parent script for all functions
616 # beginning with the word 'test', and they will be added dynamically to the
619 # This function should be overridden by the user in their unit test suite.
620 # Note: see _shunit_mktempFunc() for actual implementation
624 #suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION
626 # Adds a function name to the list of tests schedule for execution.
628 # This function should only be called from within the suite() function.
631 # function: string: name of a function to add to current unit test suite
636 __shunit_suite
="${__shunit_suite:+${__shunit_suite} }${shunit_func_}"
637 __shunit_testsTotal
=`expr ${__shunit_testsTotal} + 1`
642 # Stub. This function will be called once before any tests are run.
644 # Common one-time environment preparation tasks shared by all tests can be
647 # This function should be overridden by the user in their unit test suite.
648 # Note: see _shunit_mktempFunc() for actual implementation
652 #oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION
654 # Stub. This function will be called once after all tests are finished.
656 # Common one-time environment cleanup tasks shared by all tests can be defined
659 # This function should be overridden by the user in their unit test suite.
660 # Note: see _shunit_mktempFunc() for actual implementation
664 #oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION
666 # Stub. This function will be called before each test is run.
668 # Common environment preparation tasks shared by all tests can be defined here.
670 # This function should be overridden by the user in their unit test suite.
671 # Note: see _shunit_mktempFunc() for actual implementation
677 # Note: see _shunit_mktempFunc() for actual implementation
678 # Stub. This function will be called after each test is run.
680 # Common environment cleanup tasks shared by all tests can be defined here.
682 # This function should be overridden by the user in their unit test suite.
683 # Note: see _shunit_mktempFunc() for actual implementation
687 #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION
689 #------------------------------------------------------------------------------
690 # internal shUnit2 functions
693 # Create a temporary directory to store various run-time files in.
695 # This function is a cross-platform temporary directory creation tool. Not all
696 # OSes have the mktemp function, so one is included here.
701 # string: the temporary directory that was created
704 # try the standard mktemp function
705 ( exec mktemp
-dqt shunit.XXXXXX
2>/dev
/null
) && return
707 # the standard mktemp didn't work. doing our own.
708 if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then
709 _shunit_random_
=`/usr/bin/od -vAn -N4 -tx4 </dev/urandom \
710 |sed 's/^[^0-9a-f]*//'`
711 elif [ -n "${RANDOM:-}" ]; then
713 _shunit_random_
=${RANDOM}${RANDOM}${RANDOM}$$
715 # $RANDOM doesn't work
716 _shunit_date_
=`date '+%Y%m%d%H%M%S'`
717 _shunit_random_
=`expr ${_shunit_date_} / $$`
720 _shunit_tmpDir_
="${TMPDIR:-/tmp}/shunit.${_shunit_random_}"
721 ( umask 077 && mkdir
"${_shunit_tmpDir_}" ) || \
722 _shunit_fatal
'could not create temporary directory! exiting'
724 echo ${_shunit_tmpDir_}
725 unset _shunit_date_ _shunit_random_ _shunit_tmpDir_
728 # This function is here to work around issues in Cygwin.
734 for _shunit_func_
in oneTimeSetUp oneTimeTearDown setUp tearDown suite noexec
736 _shunit_file_
="${__shunit_tmpDir}/${_shunit_func_}"
737 cat <<EOF >"${_shunit_file_}"
741 chmod +x
"${_shunit_file_}"
747 # Final cleanup function to leave things as we found them.
749 # Besides removing the temporary directory, this function is in charge of the
750 # final exit code of the unit test. The exit code is based on how the script
751 # was ended (e.g. normal exit, or via Ctrl-C).
754 # name: string: name of the trap called (specified when trap defined)
759 case ${_shunit_name_} in
760 EXIT
) _shunit_signal_
=0 ;;
761 INT
) _shunit_signal_
=2 ;;
762 TERM
) _shunit_signal_
=15 ;;
764 _shunit_warn
"unrecognized trap value (${_shunit_name_})"
770 rm -fr "${__shunit_tmpDir}"
772 # exit for all non-EXIT signals
773 if [ ${_shunit_name_} != 'EXIT' ]; then
774 _shunit_warn
"trapped and now handling the (${_shunit_name_}) signal"
777 # add 128 to signal and exit
778 exit `expr ${_shunit_signal_} + 128`
779 elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then
780 _shunit_assertFail
'Unknown failure encountered running a test'
781 _shunit_generateReport
785 unset _shunit_name_ _shunit_signal_
788 # The actual running of the tests happens here.
794 for _shunit_test_
in ${__shunit_suite}; do
795 __shunit_testSuccess
=${SHUNIT_TRUE}
800 # execute the per-test setup function
804 echo "${_shunit_test_}"
805 eval ${_shunit_test_}
807 # execute the per-test tear-down function
811 if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then
812 __shunit_testsPassed
=`expr ${__shunit_testsPassed} + 1`
814 __shunit_testsFailed
=`expr ${__shunit_testsFailed} + 1`
821 # Generates the user friendly report with appropriate OK/FAILED message.
826 # string: the report of successful and failed tests, as well as totals.
827 _shunit_generateReport
()
829 _shunit_ok_
=${SHUNIT_TRUE}
831 # if no exit code was provided one, determine an appropriate one
832 [ ${__shunit_testsFailed} -gt 0 \
833 -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \
834 && _shunit_ok_
=${SHUNIT_FALSE}
837 if [ ${__shunit_testsTotal} -eq 1 ]; then
838 echo "Ran ${__shunit_testsTotal} test."
840 echo "Ran ${__shunit_testsTotal} tests."
845 [ ${__shunit_assertsFailed} -gt 0 ] \
846 && _shunit_failures_
="failures=${__shunit_assertsFailed}"
847 [ ${__shunit_assertsSkipped} -gt 0 ] \
848 && _shunit_skipped_
="skipped=${__shunit_assertsSkipped}"
850 if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then
852 [ -n "${_shunit_skipped_}" ] \
853 && _shunit_msg_
="${_shunit_msg_} (${_shunit_skipped_})"
855 _shunit_msg_
="FAILED (${_shunit_failures_}"
856 [ -n "${_shunit_skipped_}" ] \
857 && _shunit_msg_
="${_shunit_msg_},${_shunit_skipped_}"
858 _shunit_msg_
="${_shunit_msg_})"
863 __shunit_reportGenerated
=${SHUNIT_TRUE}
865 unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_
868 # Test for whether a function should be skipped.
873 # boolean: whether the test should be skipped (TRUE/FALSE constant)
876 [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE}
880 # Records a successful test.
886 __shunit_assertsPassed
=`expr ${__shunit_assertsPassed} + 1`
887 __shunit_assertsTotal
=`expr ${__shunit_assertsTotal} + 1`
890 # Records a test failure.
893 # message: string: failure message to provide user
898 __shunit_testSuccess
=${SHUNIT_FALSE}
899 __shunit_assertsFailed
=`expr ${__shunit_assertsFailed} + 1`
900 __shunit_assertsTotal
=`expr ${__shunit_assertsTotal} + 1`
901 echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}"
906 # Records a skipped test.
912 __shunit_assertsSkipped
=`expr ${__shunit_assertsSkipped} + 1`
913 __shunit_assertsTotal
=`expr ${__shunit_assertsTotal} + 1`
916 # Prepare a script filename for sourcing.
919 # script: string: path to a script to source
921 # string: filename prefixed with ./ (if necessary)
922 _shunit_prepForSourcing
()
925 case "${_shunit_script_}" in
926 /*|.
/*) echo "${_shunit_script_}" ;;
927 *) echo "./${_shunit_script_}" ;;
929 unset _shunit_script_
932 # Escape a character in a string.
935 # c: string: unescaped character
936 # s: string: to escape character in
938 # string: with escaped character(s)
939 _shunit_escapeCharInStr
()
941 [ -n "$2" ] ||
return # no point in doing work on an empty string
943 # Note: using shorter variable names to prevent conflicts with
944 # _shunit_escapeCharactersInString().
949 # escape the character
950 echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g'
952 unset _shunit_c_ _shunit_s_
955 # Escape a character in a string.
958 # str: string: to escape characters in
960 # string: with escaped character(s)
961 _shunit_escapeCharactersInString
()
963 [ -n "$1" ] ||
return # no point in doing work on an empty string
967 # Note: using longer variable names to prevent conflicts with
968 # _shunit_escapeCharInStr().
969 for _shunit_char_
in '"' '$' "'" '`'; do
970 _shunit_str_
=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"`
973 echo "${_shunit_str_}"
974 unset _shunit_char_ _shunit_str_
977 # Extract list of functions to run tests against.
980 # script: string: name of script to extract functions from
982 # string: of function names
983 _shunit_extractTestFunctions
()
987 # extract the lines with test function names, strip of anything besides the
988 # function name, and output everything on a single line.
989 _shunit_regex_
='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)'
990 egrep "${_shunit_regex_}" "${_shunit_script_}" \
991 |
sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \
994 unset _shunit_regex_ _shunit_script_
997 #------------------------------------------------------------------------------
1001 # determine the operating mode
1002 if [ $# -eq 0 ]; then
1003 __shunit_script
=${__SHUNIT_PARENT}
1004 __shunit_mode
=${__SHUNIT_MODE_SOURCED}
1007 [ -r "${__shunit_script}" ] || \
1008 _shunit_fatal
"unable to read from ${__shunit_script}"
1009 __shunit_mode
=${__SHUNIT_MODE_STANDALONE}
1012 # create a temporary storage location
1013 __shunit_tmpDir
=`_shunit_mktempDir`
1015 # provide a public temporary directory for unit test scripts
1016 # TODO(kward): document this
1017 SHUNIT_TMPDIR
="${__shunit_tmpDir}/tmp"
1018 mkdir
"${SHUNIT_TMPDIR}"
1020 # setup traps to clean up after ourselves
1021 trap '_shunit_cleanup EXIT' 0
1022 trap '_shunit_cleanup INT' 2
1023 trap '_shunit_cleanup TERM' 15
1025 # create phantom functions to work around issues with Cygwin
1027 PATH
="${__shunit_tmpDir}:${PATH}"
1029 # make sure phantom functions are executable. this will bite if /tmp (or the
1030 # current $TMPDIR) points to a path on a partition that was mounted with the
1031 # 'noexec' option. the noexec command was created with _shunit_mktempFunc().
1032 noexec
2>/dev
/null || _shunit_fatal \
1033 'please declare TMPDIR with path on partition with exec permission'
1035 # we must manually source the tests in standalone mode
1036 if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then
1037 .
"`_shunit_prepForSourcing \"${__shunit_script}\"`"
1040 # execute the oneTimeSetUp function (if it exists)
1043 # execute the suite function defined in the parent test script
1044 # deprecated as of 2.1.0
1047 # if no suite function was defined, dynamically build a list of functions
1048 if [ -z "${__shunit_suite}" ]; then
1049 shunit_funcs_
=`_shunit_extractTestFunctions "${__shunit_script}"`
1050 for shunit_func_
in ${shunit_funcs_}; do
1051 suite_addTest
${shunit_func_}
1054 unset shunit_func_ shunit_funcs_
1059 # execute the oneTimeTearDown function (if it exists)
1062 # generate the report
1063 _shunit_generateReport
1066 [ ${__shunit_testsFailed} -eq 0 ]