diff options
Diffstat (limited to 'lib/shunit2')
-rwxr-xr-x[-rw-r--r--] | lib/shunit2 | 976 |
1 files changed, 672 insertions, 304 deletions
diff --git a/lib/shunit2 b/lib/shunit2 index 590a5a8..2850370 100644..100755 --- a/lib/shunit2 +++ b/lib/shunit2 @@ -1,95 +1,165 @@ #! /bin/sh -# $Id: shunit2 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ # vim:et:ft=sh:sts=2:sw=2 # -# Copyright 2008 Kate Ward. All Rights Reserved. -# Released under the LGPL (GNU Lesser General Public License) +# Copyright 2008-2020 Kate Ward. All Rights Reserved. +# Released under the Apache 2.0 license. +# http://www.apache.org/licenses/LICENSE-2.0 # # shUnit2 -- Unit testing framework for Unix shell scripts. -# http://code.google.com/p/shunit2/ +# https://github.com/kward/shunit2 # # Author: kate.ward@forestent.com (Kate Ward) # # shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is # based on the popular JUnit unit testing framework for Java. +# +# $() are not fully portable (POSIX != portable). +# shellcheck disable=SC2006 +# expr may be antiquated, but it is the only solution in some cases. +# shellcheck disable=SC2003 -# return if shunit already loaded -[ -n "${SHUNIT_VERSION:-}" ] && exit 0 - -SHUNIT_VERSION='2.1.6' +# Return if shunit2 already loaded. +if test -n "${SHUNIT_VERSION:-}"; then + exit 0 +fi +SHUNIT_VERSION='2.1.9pre' +# Return values that scripts can use. SHUNIT_TRUE=0 SHUNIT_FALSE=1 SHUNIT_ERROR=2 -# enable strict mode by default -SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} +# Determine if `builtin` command exists. +__SHUNIT_BUILTIN='builtin' +# shellcheck disable=2039 +if ! ("${__SHUNIT_BUILTIN}" echo 123 >/dev/null 2>&1); then + __SHUNIT_BUILTIN='' +fi + +# Determine some reasonable command defaults. +__SHUNIT_CMD_ECHO_ESC='echo -e' +# shellcheck disable=SC2039 +if ${__SHUNIT_BUILTIN} [ "`echo -e test`" = '-e test' ]; then + __SHUNIT_CMD_ECHO_ESC='echo' +fi + +__SHUNIT_UNAME_S=`uname -s` +case "${__SHUNIT_UNAME_S}" in + BSD) __SHUNIT_CMD_EXPR='gexpr' ;; + *) __SHUNIT_CMD_EXPR='expr' ;; +esac +__SHUNIT_CMD_TPUT='tput' + +# Commands a user can override if needed. +SHUNIT_CMD_EXPR=${SHUNIT_CMD_EXPR:-${__SHUNIT_CMD_EXPR}} +SHUNIT_CMD_TPUT=${SHUNIT_CMD_TPUT:-${__SHUNIT_CMD_TPUT}} + +# Enable color output. Options are 'never', 'always', or 'auto'. +SHUNIT_COLOR=${SHUNIT_COLOR:-auto} -_shunit_warn() { echo "shunit2:WARN $@" >&2; } -_shunit_error() { echo "shunit2:ERROR $@" >&2; } -_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } +# Logging functions. +_shunit_warn() { + ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_yellow}shunit2:WARN${__shunit_ansi_none} $*" >&2 +} +_shunit_error() { + ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}shunit2:ERROR${__shunit_ansi_none} $*" >&2 +} +_shunit_fatal() { + ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}shunit2:FATAL${__shunit_ansi_none} $*" >&2 + exit ${SHUNIT_ERROR} +} -# specific shell checks -if [ -n "${ZSH_VERSION:-}" ]; then +# Specific shell checks. +if ${__SHUNIT_BUILTIN} [ -n "${ZSH_VERSION:-}" ]; then setopt |grep "^shwordsplit$" >/dev/null - if [ $? -ne ${SHUNIT_TRUE} ]; then + if ${__SHUNIT_BUILTIN} [ $? -ne ${SHUNIT_TRUE} ]; then _shunit_fatal 'zsh shwordsplit option is required for proper operation' fi - if [ -z "${SHUNIT_PARENT:-}" ]; then + if ${__SHUNIT_BUILTIN} [ -z "${SHUNIT_PARENT:-}" ]; then _shunit_fatal "zsh does not pass \$0 through properly. please declare \ \"SHUNIT_PARENT=\$0\" before calling shUnit2" fi fi # -# constants +# Constants # -__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` -for shunit_constant_ in ${shunit_constants_}; do - shunit_ro_opts_='' - case ${ZSH_VERSION:-} in - '') ;; # this isn't zsh - [123].*) ;; # early versions (1.x, 2.x, 3.x) - *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally - esac - readonly ${shunit_ro_opts_} ${shunit_constant_} +# User provided test prefix to display in front of the name of the test being +# executed. Define by setting the SHUNIT_TEST_PREFIX variable. +__SHUNIT_TEST_PREFIX=${SHUNIT_TEST_PREFIX:-} + +# ANSI colors. +__SHUNIT_ANSI_NONE='\033[0m' +__SHUNIT_ANSI_RED='\033[1;31m' +__SHUNIT_ANSI_GREEN='\033[1;32m' +__SHUNIT_ANSI_YELLOW='\033[1;33m' +__SHUNIT_ANSI_CYAN='\033[1;36m' + +# 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` +for __shunit_const in ${__shunit_constants}; do + if ${__SHUNIT_BUILTIN} [ -z "${ZSH_VERSION:-}" ]; then + readonly "${__shunit_const}" + else + case ${ZSH_VERSION} in + [123].*) readonly "${__shunit_const}" ;; + *) + # Declare readonly constants globally. + # shellcheck disable=SC2039 + readonly -g "${__shunit_const}" + esac + fi done -unset shunit_constant_ shunit_constants_ shunit_ro_opts_ +unset __shunit_const __shunit_constants + +# +# Internal variables. +# -# variables -__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 +# Variables. +__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. +__shunit_clean=${SHUNIT_FALSE} # _shunit_cleanup() was already called. -# counts of tests +# ANSI colors (populated by _shunit_configureColor()). +__shunit_ansi_none='' +__shunit_ansi_red='' +__shunit_ansi_green='' +__shunit_ansi_yellow='' +__shunit_ansi_cyan='' + +# Counts of tests. __shunit_testSuccess=${SHUNIT_TRUE} __shunit_testsTotal=0 __shunit_testsPassed=0 __shunit_testsFailed=0 -# counts of asserts +# Counts of asserts. __shunit_assertsTotal=0 __shunit_assertsPassed=0 __shunit_assertsFailed=0 __shunit_assertsSkipped=0 -# macros -_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' +# +# Macros. +# + +# shellcheck disable=SC2016,SC2089 +_SHUNIT_LINENO_='eval __shunit_lineno=""; if ${__SHUNIT_BUILTIN} [ "${1:-}" = "--lineno" ]; then if ${__SHUNIT_BUILTIN} [ -n "$2" ]; then __shunit_lineno="[$2] "; fi; shift 2; fi' #----------------------------------------------------------------------------- -# assert functions +# Assertion functions. # # Assert that two values are equal to one another. @@ -100,18 +170,20 @@ _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ - # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertEquals() -{ +assertEquals() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -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_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -119,7 +191,7 @@ assertEquals() shunit_actual_=$2 shunit_return=${SHUNIT_TRUE} - if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then + if ${__SHUNIT_BUILTIN} [ "${shunit_expected_}" = "${shunit_actual_}" ]; then _shunit_assertPass else failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" @@ -129,6 +201,7 @@ assertEquals() unset shunit_message_ shunit_expected_ shunit_actual_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' # Assert that two values are not equal to one another. @@ -139,17 +212,20 @@ _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertNotEquals() -{ +assertNotEquals() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertNotEquals() requires two or three arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -157,18 +233,102 @@ assertNotEquals() shunit_actual_=$2 shunit_return=${SHUNIT_TRUE} - if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then + if ${__SHUNIT_BUILTIN} [ "${shunit_expected_}" != "${shunit_actual_}" ]; then _shunit_assertPass else - failSame "${shunit_message_}" "$@" + failSame "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" shunit_return=${SHUNIT_FALSE} fi unset shunit_message_ shunit_expected_ shunit_actual_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' +# Assert that a container contains a content. +# +# Args: +# message: string: failure message [optional] +# container: string: container to analyze +# content: string: content to find +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertContains() { + # shellcheck disable=SC2090 + ${_SHUNIT_LINENO_} + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertContains() requires two or three arguments; $# given" + _shunit_assertFail + return ${SHUNIT_ERROR} + fi + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi + + shunit_message_=${__shunit_lineno} + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_container_=$1 + shunit_content_=$2 + shunit_return=${SHUNIT_TRUE} + if echo "${shunit_container_}" |grep -F -- "${shunit_content_}" >/dev/null; then + _shunit_assertPass + else + failNotFound "${shunit_message_}" "${shunit_content_}" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_container_ shunit_content_ + return ${shunit_return} +} +# shellcheck disable=SC2016,SC2034 +_ASSERT_CONTAINS_='eval assertContains --lineno "${LINENO:-}"' + +# Assert that a container does not contain a content. +# +# Args: +# message: string: failure message [optional] +# container: string: container to analyze +# content: string: content to look for +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotContains() { + # shellcheck disable=SC2090 + ${_SHUNIT_LINENO_} + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotContains() requires two or three arguments; $# given" + _shunit_assertFail + return ${SHUNIT_ERROR} + fi + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi + + shunit_message_=${__shunit_lineno} + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_container_=$1 + shunit_content_=$2 + + shunit_return=${SHUNIT_TRUE} + if echo "$shunit_container_" | grep -F -- "$shunit_content_" > /dev/null; then + failFound "${shunit_message_}" "${shunit_content_}" + shunit_return=${SHUNIT_FALSE} + else + _shunit_assertPass + fi + + unset shunit_message_ shunit_container_ shunit_content_ + return ${shunit_return} +} +# shellcheck disable=SC2016,SC2034 +_ASSERT_NOT_CONTAINS_='eval assertNotContains --lineno "${LINENO:-}"' + # Assert that a value is null (i.e. an empty string) # # Args: @@ -176,17 +336,20 @@ _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertNull() -{ +assertNull() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 1 -o $# -gt 2 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then _shunit_error "assertNull() requires one or two arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -196,6 +359,7 @@ assertNull() unset shunit_message_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' # Assert that a value is not null (i.e. a non-empty string) @@ -205,17 +369,21 @@ _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertNotNull() -{ +assertNotNull() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null + if ${__SHUNIT_BUILTIN} [ $# -gt 2 ]; then + # Allowing 0 arguments as $1 might actually be null. _shunit_error "assertNotNull() requires one or two arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -227,6 +395,7 @@ assertNotNull() unset shunit_actual_ shunit_message_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' # Assert that two values are the same (i.e. equal to one another). @@ -237,17 +406,20 @@ _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertSame() -{ +assertSame() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertSame() requires two or three arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -257,6 +429,7 @@ assertSame() unset shunit_message_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' # Assert that two values are not the same (i.e. not equal to one another). @@ -267,17 +440,20 @@ _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertNotSame() -{ +assertNotSame() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "assertNotSame() requires two or three arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_:-}$1" shift fi @@ -287,6 +463,7 @@ assertNotSame() unset shunit_message_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' # Assert that a value or shell test condition is true. @@ -301,57 +478,63 @@ _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' # The following test will succeed: # assertTrue 0 # assertTrue "[ 34 -gt 23 ]" -# The folloing test will fail with a message: +# The following test will fail with a message: # assertTrue 123 -# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# assertTrue "test failed" "[ -r '/non/existent/file' ]" # # Args: # message: string: failure message [optional] # condition: string: integer value or shell conditional statement # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertTrue() -{ +assertTrue() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -gt 2 ]; then - _shunit_error "assertTrue() takes one two arguments; $# given" + if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertTrue() takes one or two arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_condition_=$1 - # see if condition is an integer, i.e. a return value - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + # See if condition is an integer, i.e. a return value. shunit_return=${SHUNIT_TRUE} - if [ -z "${shunit_condition_}" ]; then - # null condition + if ${__SHUNIT_BUILTIN} [ -z "${shunit_condition_}" ]; then + # Null condition. shunit_return=${SHUNIT_FALSE} - elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + elif (expr \( "${shunit_condition_}" + '0' \) '=' "${shunit_condition_}" >/dev/null 2>&1) then - # possible return value. treating 0 as true, and non-zero as false. - [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} + # Possible return value. Treating 0 as true, and non-zero as false. + if ${__SHUNIT_BUILTIN} [ "${shunit_condition_}" -ne 0 ]; then + shunit_return=${SHUNIT_FALSE} + fi else - # (hopefully) a condition - ( eval ${shunit_condition_} ) >/dev/null 2>&1 - [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} + # Hopefully... a condition. + if ! eval "${shunit_condition_}" >/dev/null 2>&1; then + shunit_return=${SHUNIT_FALSE} + fi fi - # record the test - if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + # Record the test. + if ${__SHUNIT_BUILTIN} [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then _shunit_assertPass else _shunit_assertFail "${shunit_message_}" fi - unset shunit_message_ shunit_condition_ shunit_match_ + unset shunit_message_ shunit_condition_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' # Assert that a value or shell test condition is false. @@ -366,7 +549,7 @@ _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' # The following test will succeed: # assertFalse 1 # assertFalse "[ 'apples' = 'oranges' ]" -# The folloing test will fail with a message: +# The following test will fail with a message: # assertFalse 0 # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" # @@ -375,52 +558,58 @@ _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' # condition: string: integer value or shell conditional statement # Returns: # integer: success (TRUE/FALSE/ERROR constant) -assertFalse() -{ +assertFalse() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertFalse() quires one or two arguments; $# given" + if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertFalse() requires one or two arguments; $# given" + _shunit_assertFail return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 2 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_condition_=$1 - # see if condition is an integer, i.e. a return value - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + # See if condition is an integer, i.e. a return value. shunit_return=${SHUNIT_TRUE} - if [ -z "${shunit_condition_}" ]; then - # null condition - shunit_return=${SHUNIT_FALSE} - 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} + if ${__SHUNIT_BUILTIN} [ -z "${shunit_condition_}" ]; then + # Null condition. + shunit_return=${SHUNIT_TRUE} + elif (expr \( "${shunit_condition_}" + '0' \) '=' "${shunit_condition_}" >/dev/null 2>&1); then + # Possible return value. Treating 0 as true, and non-zero as false. + if ${__SHUNIT_BUILTIN} [ "${shunit_condition_}" -eq 0 ]; then + shunit_return=${SHUNIT_FALSE} + fi else - # (hopefully) a condition - ( eval ${shunit_condition_} ) >/dev/null 2>&1 - [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} + # Hopefully... a condition. + # shellcheck disable=SC2086 + if eval ${shunit_condition_} >/dev/null 2>&1; then + shunit_return=${SHUNIT_FALSE} + fi fi - # record the test - if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + # Record the test. + if ${__SHUNIT_BUILTIN} [ "${shunit_return}" -eq "${SHUNIT_TRUE}" ]; then _shunit_assertPass else _shunit_assertFail "${shunit_message_}" fi - unset shunit_message_ shunit_condition_ shunit_match_ - return ${shunit_return} + unset shunit_message_ shunit_condition_ + return "${shunit_return}" } +# shellcheck disable=SC2016,SC2034 _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' #----------------------------------------------------------------------------- -# failure functions +# Failure functions. # # Records a test failure. @@ -429,17 +618,19 @@ _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' # message: string: failure message [optional] # Returns: # integer: success (TRUE/FALSE/ERROR constant) -fail() -{ +fail() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -gt 1 ]; then + if ${__SHUNIT_BUILTIN} [ $# -gt 1 ]; then _shunit_error "fail() requires zero or one arguments; $# given" return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 1 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 1 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -449,6 +640,7 @@ fail() unset shunit_message_ return ${SHUNIT_FALSE} } +# shellcheck disable=SC2016,SC2034 _FAIL_='eval fail --lineno "${LINENO:-}"' # Records a test failure, stating two values were not equal. @@ -459,30 +651,101 @@ _FAIL_='eval fail --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -failNotEquals() -{ +failNotEquals() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "failNotEquals() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi shunit_expected_=$1 shunit_actual_=$2 + shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" unset shunit_message_ shunit_expected_ shunit_actual_ return ${SHUNIT_FALSE} } +# shellcheck disable=SC2016,SC2034 _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' +# Records a test failure, stating a value was found. +# +# Args: +# message: string: failure message [optional] +# content: string: found value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failFound() { + # shellcheck disable=SC2090 + ${_SHUNIT_LINENO_} + if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "failFound() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi + + shunit_message_=${__shunit_lineno} + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + shunit_message_=${shunit_message_%% } + _shunit_assertFail "${shunit_message_:+${shunit_message_} }found" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +# shellcheck disable=SC2016,SC2034 +_FAIL_FOUND_='eval failFound --lineno "${LINENO:-}"' + +# Records a test failure, stating a content was not found. +# +# Args: +# message: string: failure message [optional] +# content: string: content not found +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotFound() { + # shellcheck disable=SC2090 + ${_SHUNIT_LINENO_} + if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "failNotFound() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi + + shunit_message_=${__shunit_lineno} + if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_content_=$1 + + shunit_message_=${shunit_message_%% } + _shunit_assertFail "${shunit_message_:+${shunit_message_} }not found:<${shunit_content_}>" + + unset shunit_message_ shunit_content_ + return ${SHUNIT_FALSE} +} +# shellcheck disable=SC2016,SC2034 +_FAIL_NOT_FOUND_='eval failNotFound --lineno "${LINENO:-}"' + # Records a test failure, stating two values should have been the same. # # Args: @@ -491,26 +754,30 @@ _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -failSame() -{ +failSame() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then _shunit_error "failSame() requires two or three arguments; $# given" return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi + shunit_message_=${shunit_message_%% } _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" unset shunit_message_ return ${SHUNIT_FALSE} } +# shellcheck disable=SC2016,SC2034 _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' # Records a test failure, stating two values were not equal. @@ -523,17 +790,19 @@ _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' # actual: string: actual value # Returns: # integer: success (TRUE/FALSE/ERROR constant) -failNotSame() -{ +failNotSame() { + # shellcheck disable=SC2090 ${_SHUNIT_LINENO_} - if [ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failNotEquals() requires one or two arguments; $# given" + if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotSame() requires one or two arguments; $# given" return ${SHUNIT_ERROR} fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} + if _shunit_shouldSkip; then + return ${SHUNIT_TRUE} + fi shunit_message_=${__shunit_lineno} - if [ $# -eq 3 ]; then + if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then shunit_message_="${shunit_message_}$1" shift fi @@ -543,10 +812,11 @@ failNotSame() unset shunit_message_ return ${shunit_return} } +# shellcheck disable=SC2016,SC2034 _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' #----------------------------------------------------------------------------- -# skipping functions +# Skipping functions. # # Force remaining assert and fail functions to be "skipped". @@ -557,19 +827,13 @@ _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' # # Args: # None -startSkipping() -{ - __shunit_skip=${SHUNIT_TRUE} -} +startSkipping() { __shunit_skip=${SHUNIT_TRUE}; } # Resume the normal recording behavior of assert and fail calls. # # Args: # None -endSkipping() -{ - __shunit_skip=${SHUNIT_FALSE} -} +endSkipping() { __shunit_skip=${SHUNIT_FALSE}; } # Returns the state of assert and fail call skipping. # @@ -577,13 +841,10 @@ endSkipping() # None # Returns: # boolean: (TRUE/FALSE constant) -isSkipping() -{ - return ${__shunit_skip} -} +isSkipping() { return ${__shunit_skip}; } #----------------------------------------------------------------------------- -# suite functions +# Suite functions. # # Stub. This function should contains all unit test calls to be made. @@ -610,8 +871,7 @@ isSkipping() # # Args: # function: string: name of a function to add to current unit test suite -suite_addTest() -{ +suite_addTest() { shunit_func_=${1:-} __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" @@ -653,7 +913,7 @@ suite_addTest() # # Args: # None -#setUp() { :; } +#setUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION # Note: see _shunit_mktempFunc() for actual implementation # Stub. This function will be called after each test is run. @@ -668,41 +928,43 @@ suite_addTest() #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION #------------------------------------------------------------------------------ -# internal shUnit2 functions +# Internal shUnit2 functions. # # 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. +# 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' -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 +_shunit_mktempDir() { + # Try the standard `mktemp` function. + if ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ); then + return + fi + + # The standard `mktemp` didn't work. Use our own. + # shellcheck disable=SC2039 + if ${__SHUNIT_BUILTIN} [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 </dev/urandom |command sed 's/^[^0-9a-f]*//'` + elif ${__SHUNIT_BUILTIN} [ -n "${RANDOM:-}" ]; then # $RANDOM works _shunit_random_=${RANDOM}${RANDOM}${RANDOM}$$ else - # $RANDOM doesn't work + # `$RANDOM` doesn't work. _shunit_date_=`date '+%Y%m%d%H%M%S'` - _shunit_random_=`expr ${_shunit_date_} / $$` + _shunit_random_=`expr "${_shunit_date_}" / $$` fi _shunit_tmpDir_="${TMPDIR:-/tmp}/shunit.${_shunit_random_}" - ( umask 077 && mkdir "${_shunit_tmpDir_}" ) || \ - _shunit_fatal 'could not create temporary directory! exiting' + if ! ( umask 077 && command mkdir "${_shunit_tmpDir_}" ); then + _shunit_fatal 'could not create temporary directory! exiting' + fi - echo ${_shunit_tmpDir_} + echo "${_shunit_tmpDir_}" unset _shunit_date_ _shunit_random_ _shunit_tmpDir_ } @@ -710,16 +972,15 @@ _shunit_mktempDir() # # Args: # None -_shunit_mktempFunc() -{ +_shunit_mktempFunc() { for _shunit_func_ in oneTimeSetUp oneTimeTearDown setUp tearDown suite noexec do _shunit_file_="${__shunit_tmpDir}/${_shunit_func_}" - cat <<EOF >"${_shunit_file_}" + command cat <<EOF >"${_shunit_file_}" #! /bin/sh exit ${SHUNIT_TRUE} EOF - chmod +x "${_shunit_file_}" + command chmod +x "${_shunit_file_}" done unset _shunit_file_ @@ -733,32 +994,40 @@ EOF # # Args: # name: string: name of the trap called (specified when trap defined) -_shunit_cleanup() -{ +_shunit_cleanup() { _shunit_name_=$1 - case ${_shunit_name_} in - EXIT) _shunit_signal_=0 ;; - INT) _shunit_signal_=2 ;; - TERM) _shunit_signal_=15 ;; + _shunit_signal_=0 + case "${_shunit_name_}" in + EXIT) ;; + INT) _shunit_signal_=130 ;; # 2+128 + TERM) _shunit_signal_=143 ;; # 15+128 *) - _shunit_warn "unrecognized trap value (${_shunit_name_})" - _shunit_signal_=0 + _shunit_error "unrecognized trap value (${_shunit_name_})" ;; esac + if ${__SHUNIT_BUILTIN} [ "${_shunit_name_}" != 'EXIT' ]; then + _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" + fi - # do our work - rm -fr "${__shunit_tmpDir}" + # Do our work. + if ${__SHUNIT_BUILTIN} [ ${__shunit_clean} -eq ${SHUNIT_FALSE} ]; then + # Ensure tear downs are only called once. + __shunit_clean=${SHUNIT_TRUE} - # exit for all non-EXIT signals - if [ ${_shunit_name_} != 'EXIT' ]; then - _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" - # disable EXIT trap - trap 0 - # add 128 to signal and exit - exit `expr ${_shunit_signal_} + 128` - elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then - _shunit_assertFail 'Unknown failure encountered running a test' + tearDown || _shunit_warn 'tearDown() returned non-zero return code.' + oneTimeTearDown || \ + _shunit_warn 'oneTimeTearDown() returned non-zero return code.' + + command rm -fr "${__shunit_tmpDir}" + fi + + if ${__SHUNIT_BUILTIN} [ "${_shunit_name_}" != 'EXIT' ]; then + # Handle all non-EXIT signals. + trap - 0 # Disable EXIT trap. + exit ${_shunit_signal_} + elif ${__SHUNIT_BUILTIN} [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ]; then + _shunit_assertFail 'unknown failure encountered running a test' _shunit_generateReport exit ${SHUNIT_ERROR} fi @@ -766,30 +1035,85 @@ _shunit_cleanup() unset _shunit_name_ _shunit_signal_ } +# configureColor based on user color preference. +# +# Args: +# color: string: color mode (one of `always`, `auto`, or `none`). +_shunit_configureColor() { + _shunit_color_=${SHUNIT_FALSE} # By default, no color. + case $1 in + 'always') _shunit_color_=${SHUNIT_TRUE} ;; + 'auto') + if ${__SHUNIT_BUILTIN} [ "`_shunit_colors`" -ge 8 ]; then + _shunit_color_=${SHUNIT_TRUE} + fi + ;; + 'none') ;; + *) _shunit_fatal "unrecognized color option '$1'" ;; + esac + + case ${_shunit_color_} in + ${SHUNIT_TRUE}) + __shunit_ansi_none=${__SHUNIT_ANSI_NONE} + __shunit_ansi_red=${__SHUNIT_ANSI_RED} + __shunit_ansi_green=${__SHUNIT_ANSI_GREEN} + __shunit_ansi_yellow=${__SHUNIT_ANSI_YELLOW} + __shunit_ansi_cyan=${__SHUNIT_ANSI_CYAN} + ;; + ${SHUNIT_FALSE}) + __shunit_ansi_none='' + __shunit_ansi_red='' + __shunit_ansi_green='' + __shunit_ansi_yellow='' + __shunit_ansi_cyan='' + ;; + esac + + unset _shunit_color_ _shunit_tput_ +} + +# colors returns the number of supported colors for the TERM. +_shunit_colors() { + if _shunit_tput_=`${SHUNIT_CMD_TPUT} colors 2>/dev/null`; then + echo "${_shunit_tput_}" + else + echo 16 + fi + unset _shunit_tput_ +} + # The actual running of the tests happens here. # # Args: # None -_shunit_execSuite() -{ +_shunit_execSuite() { for _shunit_test_ in ${__shunit_suite}; do __shunit_testSuccess=${SHUNIT_TRUE} - # disable skipping + # Disable skipping. endSkipping - # execute the per-test setup function - setUp + # Execute the per-test setup function. + if ! setUp; then + _shunit_fatal "setup() returned non-zero return code." + fi - # execute the test - echo "${_shunit_test_}" - eval ${_shunit_test_} + # Execute the test. + echo "${__SHUNIT_TEST_PREFIX}${_shunit_test_}" + # shellcheck disable=SC2086 + if ! eval ${_shunit_test_}; then + _shunit_error "${_shunit_test_}() returned non-zero return code." + __shunit_testSuccess=${SHUNIT_ERROR} + _shunit_incFailedCount + fi - # execute the per-test tear-down function - tearDown + # Execute the per-test tear-down function. + if ! tearDown; then + _shunit_fatal "tearDown() returned non-zero return code." + fi - # update stats - if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then + # Update stats. + if ${__SHUNIT_BUILTIN} [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` else __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` @@ -805,45 +1129,45 @@ _shunit_execSuite() # None # Output: # string: the report of successful and failed tests, as well as totals. -_shunit_generateReport() -{ +_shunit_generateReport() { + if ${__SHUNIT_BUILTIN} [ "${__shunit_reportGenerated}" -eq ${SHUNIT_TRUE} ]; then + return + fi + _shunit_ok_=${SHUNIT_TRUE} - # if no exit code was provided one, determine an appropriate one - [ ${__shunit_testsFailed} -gt 0 \ - -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ - && _shunit_ok_=${SHUNIT_FALSE} + # If no exit code was provided, determine an appropriate one. + if ${__SHUNIT_BUILTIN} [ "${__shunit_testsFailed}" -gt 0 -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ]; then + _shunit_ok_=${SHUNIT_FALSE} + fi echo - if [ ${__shunit_testsTotal} -eq 1 ]; then - echo "Ran ${__shunit_testsTotal} test." + _shunit_msg_="Ran ${__shunit_ansi_cyan}${__shunit_testsTotal}${__shunit_ansi_none}" + if ${__SHUNIT_BUILTIN} [ "${__shunit_testsTotal}" -eq 1 ]; then + ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} test." else - echo "Ran ${__shunit_testsTotal} tests." + ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} tests." fi - _shunit_failures_='' - _shunit_skipped_='' - [ ${__shunit_assertsFailed} -gt 0 ] \ - && _shunit_failures_="failures=${__shunit_assertsFailed}" - [ ${__shunit_assertsSkipped} -gt 0 ] \ - && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" - - if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then - _shunit_msg_='OK' - [ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" + if ${__SHUNIT_BUILTIN} [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then + _shunit_msg_="${__shunit_ansi_green}OK${__shunit_ansi_none}" + if ${__SHUNIT_BUILTIN} [ "${__shunit_assertsSkipped}" -gt 0 ]; then + _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none})" + fi else - _shunit_msg_="FAILED (${_shunit_failures_}" - [ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" + _shunit_msg_="${__shunit_ansi_red}FAILED${__shunit_ansi_none}" + _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_red}failures=${__shunit_assertsFailed}${__shunit_ansi_none}" + if ${__SHUNIT_BUILTIN} [ "${__shunit_assertsSkipped}" -gt 0 ]; then + _shunit_msg_="${_shunit_msg_},${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none}" + fi _shunit_msg_="${_shunit_msg_})" fi echo - echo ${_shunit_msg_} + ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_}" __shunit_reportGenerated=${SHUNIT_TRUE} - unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ + unset _shunit_msg_ _shunit_ok_ } # Test for whether a function should be skipped. @@ -852,9 +1176,10 @@ _shunit_generateReport() # None # Returns: # boolean: whether the test should be skipped (TRUE/FALSE constant) -_shunit_shouldSkip() -{ - [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} +_shunit_shouldSkip() { + if test ${__shunit_skip} -eq ${SHUNIT_FALSE}; then + return ${SHUNIT_FALSE} + fi _shunit_assertSkip } @@ -862,8 +1187,7 @@ _shunit_shouldSkip() # # Args: # None -_shunit_assertPass() -{ +_shunit_assertPass() { __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` } @@ -872,26 +1196,44 @@ _shunit_assertPass() # # Args: # message: string: failure message to provide user -_shunit_assertFail() -{ - _shunit_msg_=$1 - +_shunit_assertFail() { __shunit_testSuccess=${SHUNIT_FALSE} - __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` - echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" + _shunit_incFailedCount - unset _shunit_msg_ + if ${__SHUNIT_BUILTIN} [ $# -gt 0 ]; then + ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}ASSERT:${__shunit_ansi_none}$*" + fi +} + +# Increment the count of failed asserts. +# +# Args: +# none +_shunit_incFailedCount() { + __shunit_assertsFailed=`expr "${__shunit_assertsFailed}" + 1` + __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` } # Records a skipped test. # # Args: # None -_shunit_assertSkip() -{ - __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +_shunit_assertSkip() { + __shunit_assertsSkipped=`expr "${__shunit_assertsSkipped}" + 1` + __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` +} + +# Dump the current test metrics. +# +# Args: +# none +_shunit_metrics() { + echo "< \ +total: ${__shunit_assertsTotal} \ +passed: ${__shunit_assertsPassed} \ +failed: ${__shunit_assertsFailed} \ +skipped: ${__shunit_assertsSkipped} \ +>" } # Prepare a script filename for sourcing. @@ -900,8 +1242,7 @@ _shunit_assertSkip() # script: string: path to a script to source # Returns: # string: filename prefixed with ./ (if necessary) -_shunit_prepForSourcing() -{ +_shunit_prepForSourcing() { _shunit_script_=$1 case "${_shunit_script_}" in /*|./*) echo "${_shunit_script_}" ;; @@ -917,18 +1258,19 @@ _shunit_prepForSourcing() # 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 +_shunit_escapeCharInStr() { + if ${__SHUNIT_BUILTIN} [ -z "$2" ]; then + return # No point in doing work on an empty string. + fi # 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' + # Escape the character. + # shellcheck disable=SC1003,SC2086 + echo ''${_shunit_s_}'' |command sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' unset _shunit_c_ _shunit_s_ } @@ -939,9 +1281,10 @@ _shunit_escapeCharInStr() # 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_escapeCharactersInString() { + if ${__SHUNIT_BUILTIN} [ -z "$1" ]; then + return # No point in doing work on an empty string. + fi _shunit_str_=$1 @@ -961,88 +1304,113 @@ _shunit_escapeCharactersInString() # script: string: name of script to extract functions from # Returns: # string: of function names -_shunit_extractTestFunctions() -{ +_shunit_extractTestFunctions() { _shunit_script_=$1 - # extract the lines with test function names, strip of anything besides the + # 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_]* *\(\)' + _shunit_regex_='^\s*((function test[A-Za-z0-9_-]*)|(test[A-Za-z0-9_-]* *\(\)))' + # shellcheck disable=SC2196 egrep "${_shunit_regex_}" "${_shunit_script_}" \ - |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |command sed 's/^[^A-Za-z0-9_-]*//;s/^function //;s/\([A-Za-z0-9_-]*\).*/\1/g' \ |xargs unset _shunit_regex_ _shunit_script_ } #------------------------------------------------------------------------------ -# main +# Main. # -# determine the operating mode -if [ $# -eq 0 ]; then +# Determine the operating mode. +if ${__SHUNIT_BUILTIN} [ $# -eq 0 -o "${1:-}" = '--' ]; 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}" + if ! ${__SHUNIT_BUILTIN} [ -r "${__shunit_script}" ]; then + _shunit_fatal "unable to read from ${__shunit_script}" + fi __shunit_mode=${__SHUNIT_MODE_STANDALONE} fi -# create a temporary storage location +# Create a temporary storage location. __shunit_tmpDir=`_shunit_mktempDir` -# provide a public temporary directory for unit test scripts -# TODO(kward): document this +# Provide a public temporary directory for unit test scripts. +# TODO(kward): document this. SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" -mkdir "${SHUNIT_TMPDIR}" +if ! command mkdir "${SHUNIT_TMPDIR}"; then + _shunit_fatal "error creating SHUNIT_TMPDIR '${SHUNIT_TMPDIR}'" +fi -# setup traps to clean up after ourselves +# Setup traps to clean up after ourselves. trap '_shunit_cleanup EXIT' 0 trap '_shunit_cleanup INT' 2 trap '_shunit_cleanup TERM' 15 -# create phantom functions to work around issues with Cygwin +# Create phantom functions to work around issues with Cygwin. _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(). +# 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' + '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}\"`" +# We must manually source the tests in standalone mode. +if ${__SHUNIT_BUILTIN} [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + # shellcheck disable=SC1090 + ${__SHUNIT_BUILTIN} . "`_shunit_prepForSourcing \"${__shunit_script}\"`" fi -# execute the oneTimeSetUp function (if it exists) -oneTimeSetUp +# Configure default output coloring behavior. +_shunit_configureColor "${SHUNIT_COLOR}" -# execute the suite function defined in the parent test script -# deprecated as of 2.1.0 -suite +# Execute the oneTimeSetUp function (if it exists). +if ! oneTimeSetUp; then + _shunit_fatal "oneTimeSetUp() returned non-zero return code." +fi -# if no suite function was defined, dynamically build a list of functions -if [ -z "${__shunit_suite}" ]; then +# Command line selected tests or suite selected tests +if ${__SHUNIT_BUILTIN} [ "$#" -ge 2 ]; then + # Argument $1 is either the filename of tests or '--'; either way, skip it. + shift + # Remaining arguments ($2 .. $#) are assumed to be test function names. + # Interate through all remaining args in "$@" in a POSIX (likely portable) way. + # Helpful tip: https://unix.stackexchange.com/questions/314032/how-to-use-arguments-like-1-2-in-a-for-loop + for _shunit_arg_ do + suite_addTest "${_shunit_arg_}" + done + unset _shunit_arg_ +else + # Execute the suite function defined in the parent test script. + # DEPRECATED as of 2.1.0. + suite +fi + +# If no tests or suite specified, dynamically build a list of functions. +if ${__SHUNIT_BUILTIN} [ -z "${__shunit_suite}" ]; then shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` for shunit_func_ in ${shunit_funcs_}; do - suite_addTest ${shunit_func_} + suite_addTest "${shunit_func_}" done fi unset shunit_func_ shunit_funcs_ -# execute the tests +# Execute the suite of unit tests. _shunit_execSuite -# execute the oneTimeTearDown function (if it exists) -oneTimeTearDown +# Execute the oneTimeTearDown function (if it exists). +if ! oneTimeTearDown; then + _shunit_fatal "oneTimeTearDown() returned non-zero return code." +fi -# generate the report +# Generate a report summary. _shunit_generateReport -# that's it folks -[ ${__shunit_testsFailed} -eq 0 ] -exit $? +# That's it folks. +if ! ${__SHUNIT_BUILTIN} [ "${__shunit_testsFailed}" -eq 0 ]; then + return ${SHUNIT_FALSE} +fi |