diff options
-rwxr-xr-x[-rw-r--r--] | test/lib/shunit2 | 882 |
1 files changed, 407 insertions, 475 deletions
diff --git a/test/lib/shunit2 b/test/lib/shunit2 index d900a70..8862ffd 100644..100755 --- a/test/lib/shunit2 +++ b/test/lib/shunit2 @@ -1,44 +1,43 @@ -# $Id: shunit2 277 2008-10-29 21:20:22Z kate.ward@forestent.com $ +#! /bin/sh +# $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ # vim:et:ft=sh:sts=2:sw=2 -# vim:foldmethod=marker:foldmarker=/**,*/ # -#/** -# <?xml version="1.0" encoding="UTF-8"?> -# <s:shelldoc xmlns:s="http://www.forestent.com/projects/shelldoc/xsl/2005.0"> -# <s:header> -# shUnit 2.1.5 -# Shell Unit Test Framework +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) # -# http://shunit2.googlecode.com/ +# shUnit2 -- Unit testing framework for Unix shell scripts. +# http://code.google.com/p/shunit2/ # -# written by Kate Ward <kate.ward@forestent.com> -# released under the LGPL +# Author: kate.ward@forestent.com (Kate Ward) # -# This module implements a xUnit based unit test framework similar to JUnit. -# </s:header> -#*/ +# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is +# based on the popular JUnit unit testing framework for Java. + +# return if shunit already loaded +[ -n "${SHUNIT_VERSION:-}" ] && exit 0 -SHUNIT_VERSION='2.1.5' +SHUNIT_VERSION='2.1.6' SHUNIT_TRUE=0 SHUNIT_FALSE=1 SHUNIT_ERROR=2 +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + _shunit_warn() { echo "shunit2:WARN $@" >&2; } _shunit_error() { echo "shunit2:ERROR $@" >&2; } -_shunit_fatal() { echo "shunit2:FATAL $@" >&2; } +_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } # specific shell checks if [ -n "${ZSH_VERSION:-}" ]; then setopt |grep "^shwordsplit$" >/dev/null if [ $? -ne ${SHUNIT_TRUE} ]; then _shunit_fatal 'zsh shwordsplit option is required for proper operation' - exit ${SHUNIT_ERROR} fi if [ -z "${SHUNIT_PARENT:-}" ]; then _shunit_fatal "zsh does not pass \$0 through properly. please declare \ \"SHUNIT_PARENT=\$0\" before calling shUnit2" - exit ${SHUNIT_ERROR} fi fi @@ -47,12 +46,14 @@ fi # __SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' +__SHUNIT_MODE_SOURCED='sourced' +__SHUNIT_MODE_STANDALONE='standalone' __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} # set the constants readonly shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` -echo "${shunit_constants_}" |grep '^Binary file' >/dev/null \ - && shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ + shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` for shunit_constant_ in ${shunit_constants_}; do shunit_ro_opts_='' case ${ZSH_VERSION:-} in @@ -65,8 +66,12 @@ done unset shunit_constant_ shunit_constants_ shunit_ro_opts_ # variables -__shunit_skip=${SHUNIT_FALSE} -__shunit_suite='' +__shunit_lineno='' # line number of executed test +__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode +__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated +__shunit_script='' # filename of unittest script (standalone mode) +__shunit_skip=${SHUNIT_FALSE} # is skipping enabled +__shunit_suite='' # suite of tests to execute # counts of tests __shunit_testSuccess=${SHUNIT_TRUE} @@ -80,9 +85,6 @@ __shunit_assertsPassed=0 __shunit_assertsFailed=0 __shunit_assertsSkipped=0 -__shunit_lineno='' -__shunit_reportGenerated=${SHUNIT_FALSE} - # macros _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' @@ -90,32 +92,20 @@ _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ - # assert functions # -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertEquals</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>expected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that <emphasis>expected</emphasis> and -# <emphasis>actual</emphasis> are equal to one another. The message is -# optional.</para> -# </entry> -# </s:function> -#*/ +# Assert that two values are equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertEquals() { ${_SHUNIT_LINENO_} if [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertEquals() requires two or three arguments; $# given" - _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}" + _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} @@ -141,26 +131,14 @@ assertEquals() } _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertNotEquals</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>unexpected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that <emphasis>unexpected</emphasis> and -# <emphasis>actual</emphasis> are <emphasis role="strong">not</emphasis> -# equal to one another. The message is optional.</para> -# </entry> -# </s:function> -#*/ +# Assert that two values are not equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertNotEquals() { ${_SHUNIT_LINENO_} @@ -175,40 +153,29 @@ assertNotEquals() shunit_message_="${shunit_message_}$1" shift fi - shunit_unexpected_=$1 + shunit_expected_=$1 shunit_actual_=$2 shunit_return=${SHUNIT_TRUE} - if [ "${shunit_unexpected_}" != "${shunit_actual_}" ]; then + if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then _shunit_assertPass else failSame "${shunit_message_}" "$@" shunit_return=${SHUNIT_FALSE} fi - unset shunit_message_ shunit_unexpected_ shunit_actual_ + unset shunit_message_ shunit_expected_ shunit_actual_ return ${shunit_return} } _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertNull</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>value</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that <emphasis>value</emphasis> is <literal>null</literal>, -# or in shell terms a zero-length string. The message is optional.</para> -# </entry> -# </s:function> -#*/ +# Assert that a value is null (i.e. an empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertNull() { ${_SHUNIT_LINENO_} @@ -231,25 +198,13 @@ assertNull() } _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertNotNull</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>value</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that <emphasis>value</emphasis> is <emphasis -# role="strong">not</emphasis> <literal>null</literal>, or in shell terms not -# a zero-length string. The message is optional.</para> -# </entry> -# </s:function> -#*/ +# Assert that a value is not null (i.e. a non-empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertNotNull() { ${_SHUNIT_LINENO_} @@ -264,38 +219,29 @@ assertNotNull() shunit_message_="${shunit_message_}$1" shift fi - assertTrue "${shunit_message_}" "[ -n '${1:-}' ]" + shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` + test -n "${shunit_actual_}" + assertTrue "${shunit_message_}" $? shunit_return=$? - unset shunit_message_ + unset shunit_actual_ shunit_message_ return ${shunit_return} } _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertSame</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>expected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>This function is functionally equivalent to -# <function>assertEquals</function>.</para> -# </entry> -# </s:function> -#*/ +# Assert that two values are the same (i.e. equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertSame() { ${_SHUNIT_LINENO_} if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertSame() requires one or two arguments; $# given" + _shunit_error "assertSame() requires two or three arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} @@ -313,26 +259,14 @@ assertSame() } _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertNotSame</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>unexpected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that <emphasis>unexpected</emphasis> and -# <emphasis>actual</emphasis> are <emphasis role="strong">not</emphasis> -# equal to one another. The message is optional.</para> -# </entry> -# </s:function> -#*/ +# Assert that two values are not the same (i.e. not equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertNotSame() { ${_SHUNIT_LINENO_} @@ -355,33 +289,27 @@ assertNotSame() } _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertTrue</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>condition</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that a given shell test condition is true. The message is -# optional.</para> -# <para>Testing whether something is true or false is easy enough by using -# the assertEquals/assertNotSame functions. Shell supports much more -# complicated tests though, and a means to support them was needed. As such, -# this function tests that conditions are true or false through evaluation -# rather than just looking for a true or false.</para> -# <funcsynopsis> -# The following test will succeed: <funcsynopsisinfo>assertTrue "[ 34 -gt 23 ]"</funcsynopsisinfo> -# The folloing test will fail with a message: <funcsynopsisinfo>assertTrue "test failed" "[ -r '/non/existant/file' ]"</funcsynopsisinfo> -# </funcsynopsis> -# </entry> -# </s:function> -#*/ +# Assert that a value or shell test condition is true. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertTrue 0 +# assertTrue "[ 34 -gt 23 ]" +# The folloing test will fail with a message: +# assertTrue 123 +# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertTrue() { ${_SHUNIT_LINENO_} @@ -404,7 +332,8 @@ assertTrue() if [ -z "${shunit_condition_}" ]; then # null condition shunit_return=${SHUNIT_FALSE} - elif [ "${shunit_condition_}" = "${shunit_match_}" ]; then + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then # possible return value. treating 0 as true, and non-zero as false. [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} else @@ -425,33 +354,27 @@ assertTrue() } _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' -#/** -# <s:function group="asserts"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>assertFalse</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>condition</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Asserts that a given shell test condition is false. The message is -# optional.</para> -# <para>Testing whether something is true or false is easy enough by using -# the assertEquals/assertNotSame functions. Shell supports much more -# complicated tests though, and a means to support them was needed. As such, -# this function tests that conditions are true or false through evaluation -# rather than just looking for a true or false.</para> -# <funcsynopsis> -# The following test will succeed: <funcsynopsisinfo>assertFalse "[ 'apples' = 'oranges' ]"</funcsynopsisinfo> -# The folloing test will fail with a message: <funcsynopsisinfo>assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]"</funcsynopsisinfo> -# </funcsynopsis> -# </entry> -# </s:function> -#*/ +# Assert that a value or shell test condition is false. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertFalse 1 +# assertFalse "[ 'apples' = 'oranges' ]" +# The folloing test will fail with a message: +# assertFalse 0 +# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) assertFalse() { ${_SHUNIT_LINENO_} @@ -474,7 +397,8 @@ assertFalse() if [ -z "${shunit_condition_}" ]; then # null condition shunit_return=${SHUNIT_FALSE} - elif [ "${shunit_condition_}" = "${shunit_match_}" ]; then + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then # possible return value. treating 0 as true, and non-zero as false. [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} else @@ -499,27 +423,17 @@ _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' # failure functions # -#/** -# <s:function group="failures"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>fail</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Fails the test immediately, with the optional message.</para> -# </entry> -# </s:function> -#*/ +# Records a test failure. +# +# Args: +# message: string: failure message [optional] +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) fail() { ${_SHUNIT_LINENO_} if [ $# -gt 1 ]; then - _shunit_error "fail() requires one or two arguments; $# given" + _shunit_error "fail() requires zero or one arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} @@ -537,26 +451,14 @@ fail() } _FAIL_='eval fail --lineno "${LINENO:-}"' -#/** -# <s:function group="failures"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>failNotEquals</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>unexpected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Fails the test if <emphasis>unexpected</emphasis> and -# <emphasis>actual</emphasis> are <emphasis role="strong">not</emphasis> -# equal to one another. The message is optional.</para> -# </entry> -# </s:function> -#*/ +# Records a test failure, stating two values were not equal. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) failNotEquals() { ${_SHUNIT_LINENO_} @@ -571,33 +473,24 @@ failNotEquals() shunit_message_="${shunit_message_}$1" shift fi - shunit_unexpected_=$1 + shunit_expected_=$1 shunit_actual_=$2 - _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_unexpected_}> but was:<${shunit_actual_}>" + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" - unset shunit_message_ shunit_unexpected_ shunit_actual_ + unset shunit_message_ shunit_expected_ shunit_actual_ return ${SHUNIT_FALSE} } _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' -#/** -# <s:function group="failures"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>failSame</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Indicate test failure because arguments were the same. The message is -# optional.</para> -# </entry> -# </s:function> -#*/ +# Records a test failure, stating two values should have been the same. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) failSame() { ${_SHUNIT_LINENO_} @@ -620,25 +513,16 @@ failSame() } _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' -#/** -# <s:function group="failures"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>failNotSame</function></funcdef> -# <paramdef>string <parameter>[message]</parameter></paramdef> -# <paramdef>string <parameter>expected</parameter></paramdef> -# <paramdef>string <parameter>actual</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>Indicate test failure because arguments were not the same. The -# message is optional.</para> -# </entry> -# </s:function> -#*/ +# Records a test failure, stating two values were not equal. +# +# This is functionally equivalent to calling failNotEquals(). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) failNotSame() { ${_SHUNIT_LINENO_} @@ -665,67 +549,34 @@ _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' # skipping functions # -#/** -# <s:function group="skipping"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>startSkipping</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function forces the remaining assert and fail functions to be -# "skipped", i.e. they will have no effect. Each function skipped will be -# recorded so that the total of asserts and fails will not be altered.</para> -# </entry> -# </s:function> -#*/ +# Force remaining assert and fail functions to be "skipped". +# +# This function forces the remaining assert and fail functions to be "skipped", +# i.e. they will have no effect. Each function skipped will be recorded so that +# the total of asserts and fails will not be altered. +# +# Args: +# None startSkipping() { __shunit_skip=${SHUNIT_TRUE} } -#/** -# <s:function group="skipping"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>endSkipping</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function returns calls to the assert and fail functions to their -# default behavior, i.e. they will be called.</para> -# </entry> -# </s:function> -#*/ +# Resume the normal recording behavior of assert and fail calls. +# +# Args: +# None endSkipping() { __shunit_skip=${SHUNIT_FALSE} } -#/** -# <s:function group="skipping"> -# <entry align="right"> -# <emphasis>boolean</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>isSkipping</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function returns the state of skipping.</para> -# </entry> -# </s:function> -#*/ +# Returns the state of assert and fail call skipping. +# +# Args: +# None +# Returns: +# boolean: (TRUE/FALSE constant) isSkipping() { return ${__shunit_skip} @@ -735,49 +586,30 @@ isSkipping() # suite functions # -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>suite</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function can be optionally overridden by the user in their test -# suite.</para> -# <para>If this function exists, it will be called when -# <command>shunit2</command> is sourced. If it does not exist, shUnit2 will -# search the parent script for all functions beginning with the word -# <literal>test</literal>, and they will be added dynamically to the test -# suite.</para> -# </entry> -# </s:function> -#*/ +# Stub. This function should contains all unit test calls to be made. +# +# DEPRECATED (as of 2.1.0) +# +# This function can be optionally overridden by the user in their test suite. +# +# If this function exists, it will be called when shunit2 is sourced. If it +# does not exist, shunit2 will search the parent script for all functions +# beginning with the word 'test', and they will be added dynamically to the +# test suite. +# +# This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation -# suite() { :; } - -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>suite_addTest</function></funcdef> -# <paramdef>string <parameter>function</parameter></paramdef> -# </funcprototype> -# </funcsynopsis> -# <para>This function adds a function name to the list of tests scheduled for -# execution as part of this test suite. This function should only be called -# from within the <function>suite()</function> function.</para> -# </entry> -# </s:function> -#*/ +# +# Args: +# None +#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Adds a function name to the list of tests schedule for execution. +# +# This function should only be called from within the suite() function. +# +# Args: +# function: string: name of a function to add to current unit test suite suite_addTest() { shunit_func_=${1:-} @@ -788,108 +620,75 @@ suite_addTest() unset shunit_func_ } -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>oneTimeSetUp</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function can be be optionally overridden by the user in their -# test suite.</para> -# <para>If this function exists, it will be called once before any tests are -# run. It is useful to prepare a common environment for all tests.</para> -# </entry> -# </s:function> -#*/ +# Stub. This function will be called once before any tests are run. +# +# Common one-time environment preparation tasks shared by all tests can be +# defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called once after all tests are finished. +# +# Common one-time environment cleanup tasks shared by all tests can be defined +# here. +# +# This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation -# oneTimeSetUp() { :; } - -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>oneTimeTearDown</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function can be be optionally overridden by the user in their -# test suite.</para> -# <para>If this function exists, it will be called once after all tests are -# completed. It is useful to clean up the environment after all tests.</para> -# </entry> -# </s:function> -#*/ +# +# Args: +# None +#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called before each test is run. +# +# Common environment preparation tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation -# oneTimeTearDown() { :; } - -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>setUp</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function can be be optionally overridden by the user in their -# test suite.</para> -# <para>If this function exists, it will be called before each test is run. -# It is useful to reset the environment before each test.</para> -# </entry> -# </s:function> -#*/ +# +# Args: +# None +#setUp() { :; } + # Note: see _shunit_mktempFunc() for actual implementation -# setUp() { :; } - -#/** -# <s:function group="suites"> -# <entry align="right"> -# <emphasis>void</emphasis> -# </entry> -# <entry> -# <funcsynopsis> -# <funcprototype> -# <funcdef><function>tearDown</function></funcdef> -# <paramdef /> -# </funcprototype> -# </funcsynopsis> -# <para>This function can be be optionally overridden by the user in their -# test suite.</para> -# <para>If this function exists, it will be called after each test completes. -# It is useful to clean up the environment after each test.</para> -# </entry> -# </s:function> -#*/ +# Stub. This function will be called after each test is run. +# +# Common environment cleanup tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. # Note: see _shunit_mktempFunc() for actual implementation -# tearDown() { :; } +# +# Args: +# None +#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION #------------------------------------------------------------------------------ # internal shUnit2 functions # -# this function is a cross-platform temporary directory creation tool. not all +# Create a temporary directory to store various run-time files in. +# +# This function is a cross-platform temporary directory creation tool. Not all # OSes have the mktemp function, so one is included here. +# +# Args: +# None +# Outputs: +# string: the temporary directory that was created _shunit_mktempDir() { # try the standard mktemp function ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return # the standard mktemp didn't work. doing our own. - if [ -r '/dev/urandom' ]; then - _shunit_random_=`od -vAn -N4 -tx4 </dev/urandom |sed 's/^[^0-9a-f]*//'` + if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 </dev/urandom \ + |sed 's/^[^0-9a-f]*//'` elif [ -n "${RANDOM:-}" ]; then # $RANDOM works _shunit_random_=${RANDOM}${RANDOM}${RANDOM}$$ @@ -900,19 +699,21 @@ _shunit_mktempDir() fi _shunit_tmpDir_="${TMPDIR:-/tmp}/shunit.${_shunit_random_}" - ( umask 077 && mkdir "${_shunit_tmpDir_}" ) || { - _shunit_fatal 'could not create temporary directory! exiting' - exit ${SHUNIT_FALSE} - } + ( umask 077 && mkdir "${_shunit_tmpDir_}" ) || \ + _shunit_fatal 'could not create temporary directory! exiting' echo ${_shunit_tmpDir_} unset _shunit_date_ _shunit_random_ _shunit_tmpDir_ } -# this function is here to work around issues in Cygwin +# This function is here to work around issues in Cygwin. +# +# Args: +# None _shunit_mktempFunc() { - for _shunit_func_ in oneTimeSetUp oneTimeTearDown setUp tearDown suite; do + for _shunit_func_ in oneTimeSetUp oneTimeTearDown setUp tearDown suite noexec + do _shunit_file_="${__shunit_tmpDir}/${_shunit_func_}" cat <<EOF >"${_shunit_file_}" #! /bin/sh @@ -924,6 +725,14 @@ EOF unset _shunit_file_ } +# Final cleanup function to leave things as we found them. +# +# Besides removing the temporary directory, this function is in charge of the +# final exit code of the unit test. The exit code is based on how the script +# was ended (e.g. normal exit, or via Ctrl-C). +# +# Args: +# name: string: name of the trap called (specified when trap defined) _shunit_cleanup() { _shunit_name_=$1 @@ -958,6 +767,9 @@ _shunit_cleanup() } # The actual running of the tests happens here. +# +# Args: +# None _shunit_execSuite() { for _shunit_test_ in ${__shunit_suite}; do @@ -987,8 +799,12 @@ _shunit_execSuite() unset _shunit_test_ } -# This function exits shUnit2 with the appropriate error code and OK/FAILED -# message. +# Generates the user friendly report with appropriate OK/FAILED message. +# +# Args: +# None +# Output: +# string: the report of successful and failed tests, as well as totals. _shunit_generateReport() { _shunit_ok_=${SHUNIT_TRUE} @@ -1030,18 +846,32 @@ _shunit_generateReport() unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ } +# Test for whether a function should be skipped. +# +# Args: +# None +# Returns: +# boolean: whether the test should be skipped (TRUE/FALSE constant) _shunit_shouldSkip() { [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} _shunit_assertSkip } +# Records a successful test. +# +# Args: +# None _shunit_assertPass() { __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` } +# Records a test failure. +# +# Args: +# message: string: failure message to provide user _shunit_assertFail() { _shunit_msg_=$1 @@ -1054,23 +884,119 @@ _shunit_assertFail() unset _shunit_msg_ } +# Records a skipped test. +# +# Args: +# None _shunit_assertSkip() { __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` } +# Prepare a script filename for sourcing. +# +# Args: +# script: string: path to a script to source +# Returns: +# string: filename prefixed with ./ (if necessary) +_shunit_prepForSourcing() +{ + _shunit_script_=$1 + case "${_shunit_script_}" in + /*|./*) echo "${_shunit_script_}" ;; + *) echo "./${_shunit_script_}" ;; + esac + unset _shunit_script_ +} + +# Escape a character in a string. +# +# Args: +# c: string: unescaped character +# s: string: to escape character in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharInStr() +{ + [ -n "$2" ] || return # no point in doing work on an empty string + + # Note: using shorter variable names to prevent conflicts with + # _shunit_escapeCharactersInString(). + _shunit_c_=$1 + _shunit_s_=$2 + + + # escape the character + echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' + + unset _shunit_c_ _shunit_s_ +} + +# Escape a character in a string. +# +# Args: +# str: string: to escape characters in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharactersInString() +{ + [ -n "$1" ] || return # no point in doing work on an empty string + + _shunit_str_=$1 + + # Note: using longer variable names to prevent conflicts with + # _shunit_escapeCharInStr(). + for _shunit_char_ in '"' '$' "'" '`'; do + _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` + done + + echo "${_shunit_str_}" + unset _shunit_char_ _shunit_str_ +} + +# Extract list of functions to run tests against. +# +# Args: +# script: string: name of script to extract functions from +# Returns: +# string: of function names +_shunit_extractTestFunctions() +{ + _shunit_script_=$1 + + # extract the lines with test function names, strip of anything besides the + # function name, and output everything on a single line. + _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' + egrep "${_shunit_regex_}" "${_shunit_script_}" \ + |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |xargs + + unset _shunit_regex_ _shunit_script_ +} + #------------------------------------------------------------------------------ # main # +# determine the operating mode +if [ $# -eq 0 ]; then + __shunit_script=${__SHUNIT_PARENT} + __shunit_mode=${__SHUNIT_MODE_SOURCED} +else + __shunit_script=$1 + [ -r "${__shunit_script}" ] || \ + _shunit_fatal "unable to read from ${__shunit_script}" + __shunit_mode=${__SHUNIT_MODE_STANDALONE} +fi + # create a temporary storage location __shunit_tmpDir=`_shunit_mktempDir` # provide a public temporary directory for unit test scripts # TODO(kward): document this -shunit_tmpDir="${__shunit_tmpDir}/tmp" -mkdir "${shunit_tmpDir}" +SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" +mkdir "${SHUNIT_TMPDIR}" # setup traps to clean up after ourselves trap '_shunit_cleanup EXIT' 0 @@ -1081,6 +1007,17 @@ trap '_shunit_cleanup TERM' 15 _shunit_mktempFunc PATH="${__shunit_tmpDir}:${PATH}" +# make sure phantom functions are executable. this will bite if /tmp (or the +# current $TMPDIR) points to a path on a partition that was mounted with the +# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). +noexec 2>/dev/null || _shunit_fatal \ + 'please declare TMPDIR with path on partition with exec permission' + +# we must manually source the tests in standalone mode +if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + . "`_shunit_prepForSourcing \"${__shunit_script}\"`" +fi + # execute the oneTimeSetUp function (if it exists) oneTimeSetUp @@ -1090,8 +1027,7 @@ suite # if no suite function was defined, dynamically build a list of functions if [ -z "${__shunit_suite}" ]; then - shunit_funcs_=`grep "^[ \t]*test[A-Za-z0-9_]* *()" ${__SHUNIT_PARENT} \ - |sed 's/[^A-Za-z0-9_]//g'` + shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` for shunit_func_ in ${shunit_funcs_}; do suite_addTest ${shunit_func_} done @@ -1110,7 +1046,3 @@ _shunit_generateReport # that's it folks [ ${__shunit_testsFailed} -eq 0 ] exit $? - -#/** -# </s:shelldoc> -#*/ |