1#! /bin/sh 2# vim:et:ft=sh:sts=2:sw=2 3# 4# Copyright 2008-2020 Kate Ward. All Rights Reserved. 5# Released under the Apache 2.0 license. 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# shUnit2 -- Unit testing framework for Unix shell scripts. 9# https://github.com/kward/shunit2 10# 11# Author: kate.ward@forestent.com (Kate Ward) 12# 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. 15# 16# $() are not fully portable (POSIX != portable). 17# shellcheck disable=SC2006 18# expr may be antiquated, but it is the only solution in some cases. 19# shellcheck disable=SC2003 20 21# Return if shunit2 already loaded. 22if test -n "${SHUNIT_VERSION:-}"; then 23 exit 0 24fi 25SHUNIT_VERSION='2.1.9pre' 26 27# Return values that scripts can use. 28SHUNIT_TRUE=0 29SHUNIT_FALSE=1 30SHUNIT_ERROR=2 31 32# Determine if `builtin` command exists. 33__SHUNIT_BUILTIN='builtin' 34# shellcheck disable=2039 35if ! ("${__SHUNIT_BUILTIN}" echo 123 >/dev/null 2>&1); then 36 __SHUNIT_BUILTIN='' 37fi 38 39# Determine some reasonable command defaults. 40__SHUNIT_CMD_ECHO_ESC='echo -e' 41# shellcheck disable=SC2039 42if ${__SHUNIT_BUILTIN} [ "`echo -e test`" = '-e test' ]; then 43 __SHUNIT_CMD_ECHO_ESC='echo' 44fi 45 46__SHUNIT_UNAME_S=`uname -s` 47case "${__SHUNIT_UNAME_S}" in 48 BSD) __SHUNIT_CMD_EXPR='gexpr' ;; 49 *) __SHUNIT_CMD_EXPR='expr' ;; 50esac 51__SHUNIT_CMD_TPUT='tput' 52 53# Commands a user can override if needed. 54SHUNIT_CMD_EXPR=${SHUNIT_CMD_EXPR:-${__SHUNIT_CMD_EXPR}} 55SHUNIT_CMD_TPUT=${SHUNIT_CMD_TPUT:-${__SHUNIT_CMD_TPUT}} 56 57# Enable color output. Options are 'never', 'always', or 'auto'. 58SHUNIT_COLOR=${SHUNIT_COLOR:-auto} 59 60# Logging functions. 61_shunit_warn() { 62 ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_yellow}shunit2:WARN${__shunit_ansi_none} $*" >&2 63} 64_shunit_error() { 65 ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}shunit2:ERROR${__shunit_ansi_none} $*" >&2 66} 67_shunit_fatal() { 68 ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}shunit2:FATAL${__shunit_ansi_none} $*" >&2 69 exit ${SHUNIT_ERROR} 70} 71 72# Specific shell checks. 73if ${__SHUNIT_BUILTIN} [ -n "${ZSH_VERSION:-}" ]; then 74 setopt |grep "^shwordsplit$" >/dev/null 75 if ${__SHUNIT_BUILTIN} [ $? -ne ${SHUNIT_TRUE} ]; then 76 _shunit_fatal 'zsh shwordsplit option is required for proper operation' 77 fi 78 if ${__SHUNIT_BUILTIN} [ -z "${SHUNIT_PARENT:-}" ]; then 79 _shunit_fatal "zsh does not pass \$0 through properly. please declare \ 80\"SHUNIT_PARENT=\$0\" before calling shUnit2" 81 fi 82fi 83 84# 85# Constants 86# 87 88__SHUNIT_MODE_SOURCED='sourced' 89__SHUNIT_MODE_STANDALONE='standalone' 90__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} 91 92# User provided test prefix to display in front of the name of the test being 93# executed. Define by setting the SHUNIT_TEST_PREFIX variable. 94__SHUNIT_TEST_PREFIX=${SHUNIT_TEST_PREFIX:-} 95 96# ANSI colors. 97__SHUNIT_ANSI_NONE='\033[0m' 98__SHUNIT_ANSI_RED='\033[1;31m' 99__SHUNIT_ANSI_GREEN='\033[1;32m' 100__SHUNIT_ANSI_YELLOW='\033[1;33m' 101__SHUNIT_ANSI_CYAN='\033[1;36m' 102 103# Set the constants readonly. 104__shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` 105echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ 106 __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` 107for __shunit_const in ${__shunit_constants}; do 108 if ${__SHUNIT_BUILTIN} [ -z "${ZSH_VERSION:-}" ]; then 109 readonly "${__shunit_const}" 110 else 111 case ${ZSH_VERSION} in 112 [123].*) readonly "${__shunit_const}" ;; 113 *) 114 # Declare readonly constants globally. 115 # shellcheck disable=SC2039 116 readonly -g "${__shunit_const}" 117 esac 118 fi 119done 120unset __shunit_const __shunit_constants 121 122# 123# Internal variables. 124# 125 126# Variables. 127__shunit_lineno='' # Line number of executed test. 128__shunit_mode=${__SHUNIT_MODE_SOURCED} # Operating mode. 129__shunit_reportGenerated=${SHUNIT_FALSE} # Is report generated. 130__shunit_script='' # Filename of unittest script (standalone mode). 131__shunit_skip=${SHUNIT_FALSE} # Is skipping enabled. 132__shunit_suite='' # Suite of tests to execute. 133__shunit_clean=${SHUNIT_FALSE} # _shunit_cleanup() was already called. 134 135# ANSI colors (populated by _shunit_configureColor()). 136__shunit_ansi_none='' 137__shunit_ansi_red='' 138__shunit_ansi_green='' 139__shunit_ansi_yellow='' 140__shunit_ansi_cyan='' 141 142# Counts of tests. 143__shunit_testSuccess=${SHUNIT_TRUE} 144__shunit_testsTotal=0 145__shunit_testsPassed=0 146__shunit_testsFailed=0 147 148# Counts of asserts. 149__shunit_assertsTotal=0 150__shunit_assertsPassed=0 151__shunit_assertsFailed=0 152__shunit_assertsSkipped=0 153 154# 155# Macros. 156# 157 158# shellcheck disable=SC2016,SC2089 159_SHUNIT_LINENO_='eval __shunit_lineno=""; if ${__SHUNIT_BUILTIN} [ "${1:-}" = "--lineno" ]; then if ${__SHUNIT_BUILTIN} [ -n "$2" ]; then __shunit_lineno="[$2] "; fi; shift 2; fi' 160 161#----------------------------------------------------------------------------- 162# Assertion functions. 163# 164 165# Assert that two values are equal to one another. 166# 167# Args: 168# message: string: failure message [optional] 169# expected: string: expected value 170# actual: string: actual value 171# Returns: 172# integer: success (TRUE/FALSE/ERROR constant) 173assertEquals() { 174 # shellcheck disable=SC2090 175 ${_SHUNIT_LINENO_} 176 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 177 _shunit_error "assertEquals() requires two or three arguments; $# given" 178 _shunit_assertFail 179 return ${SHUNIT_ERROR} 180 fi 181 if _shunit_shouldSkip; then 182 return ${SHUNIT_TRUE} 183 fi 184 185 shunit_message_=${__shunit_lineno} 186 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 187 shunit_message_="${shunit_message_}$1" 188 shift 189 fi 190 shunit_expected_=$1 191 shunit_actual_=$2 192 193 shunit_return=${SHUNIT_TRUE} 194 if ${__SHUNIT_BUILTIN} [ "${shunit_expected_}" = "${shunit_actual_}" ]; then 195 _shunit_assertPass 196 else 197 failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" 198 shunit_return=${SHUNIT_FALSE} 199 fi 200 201 unset shunit_message_ shunit_expected_ shunit_actual_ 202 return ${shunit_return} 203} 204# shellcheck disable=SC2016,SC2034 205_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' 206 207# Assert that two values are not equal to one another. 208# 209# Args: 210# message: string: failure message [optional] 211# expected: string: expected value 212# actual: string: actual value 213# Returns: 214# integer: success (TRUE/FALSE/ERROR constant) 215assertNotEquals() { 216 # shellcheck disable=SC2090 217 ${_SHUNIT_LINENO_} 218 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 219 _shunit_error "assertNotEquals() requires two or three arguments; $# given" 220 _shunit_assertFail 221 return ${SHUNIT_ERROR} 222 fi 223 if _shunit_shouldSkip; then 224 return ${SHUNIT_TRUE} 225 fi 226 227 shunit_message_=${__shunit_lineno} 228 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 229 shunit_message_="${shunit_message_}$1" 230 shift 231 fi 232 shunit_expected_=$1 233 shunit_actual_=$2 234 235 shunit_return=${SHUNIT_TRUE} 236 if ${__SHUNIT_BUILTIN} [ "${shunit_expected_}" != "${shunit_actual_}" ]; then 237 _shunit_assertPass 238 else 239 failSame "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" 240 shunit_return=${SHUNIT_FALSE} 241 fi 242 243 unset shunit_message_ shunit_expected_ shunit_actual_ 244 return ${shunit_return} 245} 246# shellcheck disable=SC2016,SC2034 247_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' 248 249# Assert that a container contains a content. 250# 251# Args: 252# message: string: failure message [optional] 253# container: string: container to analyze 254# content: string: content to find 255# Returns: 256# integer: success (TRUE/FALSE/ERROR constant) 257assertContains() { 258 # shellcheck disable=SC2090 259 ${_SHUNIT_LINENO_} 260 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 261 _shunit_error "assertContains() requires two or three arguments; $# given" 262 _shunit_assertFail 263 return ${SHUNIT_ERROR} 264 fi 265 if _shunit_shouldSkip; then 266 return ${SHUNIT_TRUE} 267 fi 268 269 shunit_message_=${__shunit_lineno} 270 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 271 shunit_message_="${shunit_message_}$1" 272 shift 273 fi 274 shunit_container_=$1 275 shunit_content_=$2 276 shunit_return=${SHUNIT_TRUE} 277 if echo "${shunit_container_}" |grep -F -- "${shunit_content_}" >/dev/null; then 278 _shunit_assertPass 279 else 280 failNotFound "${shunit_message_}" "${shunit_content_}" 281 shunit_return=${SHUNIT_FALSE} 282 fi 283 284 unset shunit_message_ shunit_container_ shunit_content_ 285 return ${shunit_return} 286} 287# shellcheck disable=SC2016,SC2034 288_ASSERT_CONTAINS_='eval assertContains --lineno "${LINENO:-}"' 289 290# Assert that a container does not contain a content. 291# 292# Args: 293# message: string: failure message [optional] 294# container: string: container to analyze 295# content: string: content to look for 296# Returns: 297# integer: success (TRUE/FALSE/ERROR constant) 298assertNotContains() { 299 # shellcheck disable=SC2090 300 ${_SHUNIT_LINENO_} 301 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 302 _shunit_error "assertNotContains() requires two or three arguments; $# given" 303 _shunit_assertFail 304 return ${SHUNIT_ERROR} 305 fi 306 if _shunit_shouldSkip; then 307 return ${SHUNIT_TRUE} 308 fi 309 310 shunit_message_=${__shunit_lineno} 311 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 312 shunit_message_="${shunit_message_}$1" 313 shift 314 fi 315 shunit_container_=$1 316 shunit_content_=$2 317 318 shunit_return=${SHUNIT_TRUE} 319 if echo "$shunit_container_" | grep -F -- "$shunit_content_" > /dev/null; then 320 failFound "${shunit_message_}" "${shunit_content_}" 321 shunit_return=${SHUNIT_FALSE} 322 else 323 _shunit_assertPass 324 fi 325 326 unset shunit_message_ shunit_container_ shunit_content_ 327 return ${shunit_return} 328} 329# shellcheck disable=SC2016,SC2034 330_ASSERT_NOT_CONTAINS_='eval assertNotContains --lineno "${LINENO:-}"' 331 332# Assert that a value is null (i.e. an empty string) 333# 334# Args: 335# message: string: failure message [optional] 336# actual: string: actual value 337# Returns: 338# integer: success (TRUE/FALSE/ERROR constant) 339assertNull() { 340 # shellcheck disable=SC2090 341 ${_SHUNIT_LINENO_} 342 if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then 343 _shunit_error "assertNull() requires one or two arguments; $# given" 344 _shunit_assertFail 345 return ${SHUNIT_ERROR} 346 fi 347 if _shunit_shouldSkip; then 348 return ${SHUNIT_TRUE} 349 fi 350 351 shunit_message_=${__shunit_lineno} 352 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 353 shunit_message_="${shunit_message_}$1" 354 shift 355 fi 356 assertTrue "${shunit_message_}" "[ -z '$1' ]" 357 shunit_return=$? 358 359 unset shunit_message_ 360 return ${shunit_return} 361} 362# shellcheck disable=SC2016,SC2034 363_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' 364 365# Assert that a value is not null (i.e. a non-empty string) 366# 367# Args: 368# message: string: failure message [optional] 369# actual: string: actual value 370# Returns: 371# integer: success (TRUE/FALSE/ERROR constant) 372assertNotNull() { 373 # shellcheck disable=SC2090 374 ${_SHUNIT_LINENO_} 375 if ${__SHUNIT_BUILTIN} [ $# -gt 2 ]; then 376 # Allowing 0 arguments as $1 might actually be null. 377 _shunit_error "assertNotNull() requires one or two arguments; $# given" 378 _shunit_assertFail 379 return ${SHUNIT_ERROR} 380 fi 381 if _shunit_shouldSkip; then 382 return ${SHUNIT_TRUE} 383 fi 384 385 shunit_message_=${__shunit_lineno} 386 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 387 shunit_message_="${shunit_message_}$1" 388 shift 389 fi 390 shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` 391 test -n "${shunit_actual_}" 392 assertTrue "${shunit_message_}" $? 393 shunit_return=$? 394 395 unset shunit_actual_ shunit_message_ 396 return ${shunit_return} 397} 398# shellcheck disable=SC2016,SC2034 399_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' 400 401# Assert that two values are the same (i.e. equal to one another). 402# 403# Args: 404# message: string: failure message [optional] 405# expected: string: expected value 406# actual: string: actual value 407# Returns: 408# integer: success (TRUE/FALSE/ERROR constant) 409assertSame() { 410 # shellcheck disable=SC2090 411 ${_SHUNIT_LINENO_} 412 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 413 _shunit_error "assertSame() requires two or three arguments; $# given" 414 _shunit_assertFail 415 return ${SHUNIT_ERROR} 416 fi 417 if _shunit_shouldSkip; then 418 return ${SHUNIT_TRUE} 419 fi 420 421 shunit_message_=${__shunit_lineno} 422 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 423 shunit_message_="${shunit_message_}$1" 424 shift 425 fi 426 assertEquals "${shunit_message_}" "$1" "$2" 427 shunit_return=$? 428 429 unset shunit_message_ 430 return ${shunit_return} 431} 432# shellcheck disable=SC2016,SC2034 433_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' 434 435# Assert that two values are not the same (i.e. not equal to one another). 436# 437# Args: 438# message: string: failure message [optional] 439# expected: string: expected value 440# actual: string: actual value 441# Returns: 442# integer: success (TRUE/FALSE/ERROR constant) 443assertNotSame() { 444 # shellcheck disable=SC2090 445 ${_SHUNIT_LINENO_} 446 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 447 _shunit_error "assertNotSame() requires two or three arguments; $# given" 448 _shunit_assertFail 449 return ${SHUNIT_ERROR} 450 fi 451 if _shunit_shouldSkip; then 452 return ${SHUNIT_TRUE} 453 fi 454 455 shunit_message_=${__shunit_lineno} 456 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 457 shunit_message_="${shunit_message_:-}$1" 458 shift 459 fi 460 assertNotEquals "${shunit_message_}" "$1" "$2" 461 shunit_return=$? 462 463 unset shunit_message_ 464 return ${shunit_return} 465} 466# shellcheck disable=SC2016,SC2034 467_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' 468 469# Assert that a value or shell test condition is true. 470# 471# In shell, a value of 0 is true and a non-zero value is false. Any integer 472# value passed can thereby be tested. 473# 474# Shell supports much more complicated tests though, and a means to support 475# them was needed. As such, this function tests that conditions are true or 476# false through evaluation rather than just looking for a true or false. 477# 478# The following test will succeed: 479# assertTrue 0 480# assertTrue "[ 34 -gt 23 ]" 481# The following test will fail with a message: 482# assertTrue 123 483# assertTrue "test failed" "[ -r '/non/existent/file' ]" 484# 485# Args: 486# message: string: failure message [optional] 487# condition: string: integer value or shell conditional statement 488# Returns: 489# integer: success (TRUE/FALSE/ERROR constant) 490assertTrue() { 491 # shellcheck disable=SC2090 492 ${_SHUNIT_LINENO_} 493 if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then 494 _shunit_error "assertTrue() takes one or two arguments; $# given" 495 _shunit_assertFail 496 return ${SHUNIT_ERROR} 497 fi 498 if _shunit_shouldSkip; then 499 return ${SHUNIT_TRUE} 500 fi 501 502 shunit_message_=${__shunit_lineno} 503 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 504 shunit_message_="${shunit_message_}$1" 505 shift 506 fi 507 shunit_condition_=$1 508 509 # See if condition is an integer, i.e. a return value. 510 shunit_return=${SHUNIT_TRUE} 511 if ${__SHUNIT_BUILTIN} [ -z "${shunit_condition_}" ]; then 512 # Null condition. 513 shunit_return=${SHUNIT_FALSE} 514 elif (expr \( "${shunit_condition_}" + '0' \) '=' "${shunit_condition_}" >/dev/null 2>&1) 515 then 516 # Possible return value. Treating 0 as true, and non-zero as false. 517 if ${__SHUNIT_BUILTIN} [ "${shunit_condition_}" -ne 0 ]; then 518 shunit_return=${SHUNIT_FALSE} 519 fi 520 else 521 # Hopefully... a condition. 522 if ! eval "${shunit_condition_}" >/dev/null 2>&1; then 523 shunit_return=${SHUNIT_FALSE} 524 fi 525 fi 526 527 # Record the test. 528 if ${__SHUNIT_BUILTIN} [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 529 _shunit_assertPass 530 else 531 _shunit_assertFail "${shunit_message_}" 532 fi 533 534 unset shunit_message_ shunit_condition_ 535 return ${shunit_return} 536} 537# shellcheck disable=SC2016,SC2034 538_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' 539 540# Assert that a value or shell test condition is false. 541# 542# In shell, a value of 0 is true and a non-zero value is false. Any integer 543# value passed can thereby be tested. 544# 545# Shell supports much more complicated tests though, and a means to support 546# them was needed. As such, this function tests that conditions are true or 547# false through evaluation rather than just looking for a true or false. 548# 549# The following test will succeed: 550# assertFalse 1 551# assertFalse "[ 'apples' = 'oranges' ]" 552# The following test will fail with a message: 553# assertFalse 0 554# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" 555# 556# Args: 557# message: string: failure message [optional] 558# condition: string: integer value or shell conditional statement 559# Returns: 560# integer: success (TRUE/FALSE/ERROR constant) 561assertFalse() { 562 # shellcheck disable=SC2090 563 ${_SHUNIT_LINENO_} 564 if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then 565 _shunit_error "assertFalse() requires one or two arguments; $# given" 566 _shunit_assertFail 567 return ${SHUNIT_ERROR} 568 fi 569 if _shunit_shouldSkip; then 570 return ${SHUNIT_TRUE} 571 fi 572 573 shunit_message_=${__shunit_lineno} 574 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 575 shunit_message_="${shunit_message_}$1" 576 shift 577 fi 578 shunit_condition_=$1 579 580 # See if condition is an integer, i.e. a return value. 581 shunit_return=${SHUNIT_TRUE} 582 if ${__SHUNIT_BUILTIN} [ -z "${shunit_condition_}" ]; then 583 # Null condition. 584 shunit_return=${SHUNIT_TRUE} 585 elif (expr \( "${shunit_condition_}" + '0' \) '=' "${shunit_condition_}" >/dev/null 2>&1); then 586 # Possible return value. Treating 0 as true, and non-zero as false. 587 if ${__SHUNIT_BUILTIN} [ "${shunit_condition_}" -eq 0 ]; then 588 shunit_return=${SHUNIT_FALSE} 589 fi 590 else 591 # Hopefully... a condition. 592 # shellcheck disable=SC2086 593 if eval ${shunit_condition_} >/dev/null 2>&1; then 594 shunit_return=${SHUNIT_FALSE} 595 fi 596 fi 597 598 # Record the test. 599 if ${__SHUNIT_BUILTIN} [ "${shunit_return}" -eq "${SHUNIT_TRUE}" ]; then 600 _shunit_assertPass 601 else 602 _shunit_assertFail "${shunit_message_}" 603 fi 604 605 unset shunit_message_ shunit_condition_ 606 return "${shunit_return}" 607} 608# shellcheck disable=SC2016,SC2034 609_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' 610 611#----------------------------------------------------------------------------- 612# Failure functions. 613# 614 615# Records a test failure. 616# 617# Args: 618# message: string: failure message [optional] 619# Returns: 620# integer: success (TRUE/FALSE/ERROR constant) 621fail() { 622 # shellcheck disable=SC2090 623 ${_SHUNIT_LINENO_} 624 if ${__SHUNIT_BUILTIN} [ $# -gt 1 ]; then 625 _shunit_error "fail() requires zero or one arguments; $# given" 626 return ${SHUNIT_ERROR} 627 fi 628 if _shunit_shouldSkip; then 629 return ${SHUNIT_TRUE} 630 fi 631 632 shunit_message_=${__shunit_lineno} 633 if ${__SHUNIT_BUILTIN} [ $# -eq 1 ]; then 634 shunit_message_="${shunit_message_}$1" 635 shift 636 fi 637 638 _shunit_assertFail "${shunit_message_}" 639 640 unset shunit_message_ 641 return ${SHUNIT_FALSE} 642} 643# shellcheck disable=SC2016,SC2034 644_FAIL_='eval fail --lineno "${LINENO:-}"' 645 646# Records a test failure, stating two values were not equal. 647# 648# Args: 649# message: string: failure message [optional] 650# expected: string: expected value 651# actual: string: actual value 652# Returns: 653# integer: success (TRUE/FALSE/ERROR constant) 654failNotEquals() { 655 # shellcheck disable=SC2090 656 ${_SHUNIT_LINENO_} 657 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 658 _shunit_error "failNotEquals() requires one or two arguments; $# given" 659 return ${SHUNIT_ERROR} 660 fi 661 if _shunit_shouldSkip; then 662 return ${SHUNIT_TRUE} 663 fi 664 665 shunit_message_=${__shunit_lineno} 666 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 667 shunit_message_="${shunit_message_}$1" 668 shift 669 fi 670 shunit_expected_=$1 671 shunit_actual_=$2 672 673 shunit_message_=${shunit_message_%% } 674 _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" 675 676 unset shunit_message_ shunit_expected_ shunit_actual_ 677 return ${SHUNIT_FALSE} 678} 679# shellcheck disable=SC2016,SC2034 680_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' 681 682# Records a test failure, stating a value was found. 683# 684# Args: 685# message: string: failure message [optional] 686# content: string: found value 687# Returns: 688# integer: success (TRUE/FALSE/ERROR constant) 689failFound() { 690 # shellcheck disable=SC2090 691 ${_SHUNIT_LINENO_} 692 if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then 693 _shunit_error "failFound() requires one or two arguments; $# given" 694 return ${SHUNIT_ERROR} 695 fi 696 if _shunit_shouldSkip; then 697 return ${SHUNIT_TRUE} 698 fi 699 700 shunit_message_=${__shunit_lineno} 701 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 702 shunit_message_="${shunit_message_}$1" 703 shift 704 fi 705 706 shunit_message_=${shunit_message_%% } 707 _shunit_assertFail "${shunit_message_:+${shunit_message_} }found" 708 709 unset shunit_message_ 710 return ${SHUNIT_FALSE} 711} 712# shellcheck disable=SC2016,SC2034 713_FAIL_FOUND_='eval failFound --lineno "${LINENO:-}"' 714 715# Records a test failure, stating a content was not found. 716# 717# Args: 718# message: string: failure message [optional] 719# content: string: content not found 720# Returns: 721# integer: success (TRUE/FALSE/ERROR constant) 722failNotFound() { 723 # shellcheck disable=SC2090 724 ${_SHUNIT_LINENO_} 725 if ${__SHUNIT_BUILTIN} [ $# -lt 1 -o $# -gt 2 ]; then 726 _shunit_error "failNotFound() requires one or two arguments; $# given" 727 return ${SHUNIT_ERROR} 728 fi 729 if _shunit_shouldSkip; then 730 return ${SHUNIT_TRUE} 731 fi 732 733 shunit_message_=${__shunit_lineno} 734 if ${__SHUNIT_BUILTIN} [ $# -eq 2 ]; then 735 shunit_message_="${shunit_message_}$1" 736 shift 737 fi 738 shunit_content_=$1 739 740 shunit_message_=${shunit_message_%% } 741 _shunit_assertFail "${shunit_message_:+${shunit_message_} }not found:<${shunit_content_}>" 742 743 unset shunit_message_ shunit_content_ 744 return ${SHUNIT_FALSE} 745} 746# shellcheck disable=SC2016,SC2034 747_FAIL_NOT_FOUND_='eval failNotFound --lineno "${LINENO:-}"' 748 749# Records a test failure, stating two values should have been the same. 750# 751# Args: 752# message: string: failure message [optional] 753# expected: string: expected value 754# actual: string: actual value 755# Returns: 756# integer: success (TRUE/FALSE/ERROR constant) 757failSame() { 758 # shellcheck disable=SC2090 759 ${_SHUNIT_LINENO_} 760 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 761 _shunit_error "failSame() requires two or three arguments; $# given" 762 return ${SHUNIT_ERROR} 763 fi 764 if _shunit_shouldSkip; then 765 return ${SHUNIT_TRUE} 766 fi 767 768 shunit_message_=${__shunit_lineno} 769 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 770 shunit_message_="${shunit_message_}$1" 771 shift 772 fi 773 774 shunit_message_=${shunit_message_%% } 775 _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" 776 777 unset shunit_message_ 778 return ${SHUNIT_FALSE} 779} 780# shellcheck disable=SC2016,SC2034 781_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' 782 783# Records a test failure, stating two values were not equal. 784# 785# This is functionally equivalent to calling failNotEquals(). 786# 787# Args: 788# message: string: failure message [optional] 789# expected: string: expected value 790# actual: string: actual value 791# Returns: 792# integer: success (TRUE/FALSE/ERROR constant) 793failNotSame() { 794 # shellcheck disable=SC2090 795 ${_SHUNIT_LINENO_} 796 if ${__SHUNIT_BUILTIN} [ $# -lt 2 -o $# -gt 3 ]; then 797 _shunit_error "failNotSame() requires one or two arguments; $# given" 798 return ${SHUNIT_ERROR} 799 fi 800 if _shunit_shouldSkip; then 801 return ${SHUNIT_TRUE} 802 fi 803 804 shunit_message_=${__shunit_lineno} 805 if ${__SHUNIT_BUILTIN} [ $# -eq 3 ]; then 806 shunit_message_="${shunit_message_}$1" 807 shift 808 fi 809 failNotEquals "${shunit_message_}" "$1" "$2" 810 shunit_return=$? 811 812 unset shunit_message_ 813 return ${shunit_return} 814} 815# shellcheck disable=SC2016,SC2034 816_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' 817 818#----------------------------------------------------------------------------- 819# Skipping functions. 820# 821 822# Force remaining assert and fail functions to be "skipped". 823# 824# This function forces the remaining assert and fail functions to be "skipped", 825# i.e. they will have no effect. Each function skipped will be recorded so that 826# the total of asserts and fails will not be altered. 827# 828# Args: 829# None 830startSkipping() { __shunit_skip=${SHUNIT_TRUE}; } 831 832# Resume the normal recording behavior of assert and fail calls. 833# 834# Args: 835# None 836endSkipping() { __shunit_skip=${SHUNIT_FALSE}; } 837 838# Returns the state of assert and fail call skipping. 839# 840# Args: 841# None 842# Returns: 843# boolean: (TRUE/FALSE constant) 844isSkipping() { return ${__shunit_skip}; } 845 846#----------------------------------------------------------------------------- 847# Suite functions. 848# 849 850# Stub. This function should contains all unit test calls to be made. 851# 852# DEPRECATED (as of 2.1.0) 853# 854# This function can be optionally overridden by the user in their test suite. 855# 856# If this function exists, it will be called when shunit2 is sourced. If it 857# does not exist, shunit2 will search the parent script for all functions 858# beginning with the word 'test', and they will be added dynamically to the 859# test suite. 860# 861# This function should be overridden by the user in their unit test suite. 862# Note: see _shunit_mktempFunc() for actual implementation 863# 864# Args: 865# None 866#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION 867 868# Adds a function name to the list of tests schedule for execution. 869# 870# This function should only be called from within the suite() function. 871# 872# Args: 873# function: string: name of a function to add to current unit test suite 874suite_addTest() { 875 shunit_func_=${1:-} 876 877 __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" 878 __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` 879 880 unset shunit_func_ 881} 882 883# Stub. This function will be called once before any tests are run. 884# 885# Common one-time environment preparation tasks shared by all tests can be 886# defined here. 887# 888# This function should be overridden by the user in their unit test suite. 889# Note: see _shunit_mktempFunc() for actual implementation 890# 891# Args: 892# None 893#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION 894 895# Stub. This function will be called once after all tests are finished. 896# 897# Common one-time environment cleanup tasks shared by all tests can be defined 898# here. 899# 900# This function should be overridden by the user in their unit test suite. 901# Note: see _shunit_mktempFunc() for actual implementation 902# 903# Args: 904# None 905#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 906 907# Stub. This function will be called before each test is run. 908# 909# Common environment preparation tasks shared by all tests can be defined here. 910# 911# This function should be overridden by the user in their unit test suite. 912# Note: see _shunit_mktempFunc() for actual implementation 913# 914# Args: 915# None 916#setUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION 917 918# Note: see _shunit_mktempFunc() for actual implementation 919# Stub. This function will be called after each test is run. 920# 921# Common environment cleanup tasks shared by all tests can be defined here. 922# 923# This function should be overridden by the user in their unit test suite. 924# Note: see _shunit_mktempFunc() for actual implementation 925# 926# Args: 927# None 928#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 929 930#------------------------------------------------------------------------------ 931# Internal shUnit2 functions. 932# 933 934# Create a temporary directory to store various run-time files in. 935# 936# This function is a cross-platform temporary directory creation tool. Not all 937# OSes have the `mktemp` function, so one is included here. 938# 939# Args: 940# None 941# Outputs: 942# string: the temporary directory that was created 943_shunit_mktempDir() { 944 # Try the standard `mktemp` function. 945 if ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ); then 946 return 947 fi 948 949 # The standard `mktemp` didn't work. Use our own. 950 # shellcheck disable=SC2039 951 if ${__SHUNIT_BUILTIN} [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then 952 _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 </dev/urandom |command sed 's/^[^0-9a-f]*//'` 953 elif ${__SHUNIT_BUILTIN} [ -n "${RANDOM:-}" ]; then 954 # $RANDOM works 955 _shunit_random_=${RANDOM}${RANDOM}${RANDOM}$$ 956 else 957 # `$RANDOM` doesn't work. 958 _shunit_date_=`date '+%Y%m%d%H%M%S'` 959 _shunit_random_=`expr "${_shunit_date_}" / $$` 960 fi 961 962 _shunit_tmpDir_="${TMPDIR:-/tmp}/shunit.${_shunit_random_}" 963 if ! ( umask 077 && command mkdir "${_shunit_tmpDir_}" ); then 964 _shunit_fatal 'could not create temporary directory! exiting' 965 fi 966 967 echo "${_shunit_tmpDir_}" 968 unset _shunit_date_ _shunit_random_ _shunit_tmpDir_ 969} 970 971# This function is here to work around issues in Cygwin. 972# 973# Args: 974# None 975_shunit_mktempFunc() { 976 for _shunit_func_ in oneTimeSetUp oneTimeTearDown setUp tearDown suite noexec 977 do 978 _shunit_file_="${__shunit_tmpDir}/${_shunit_func_}" 979 command cat <<EOF >"${_shunit_file_}" 980#! /bin/sh 981exit ${SHUNIT_TRUE} 982EOF 983 command chmod +x "${_shunit_file_}" 984 done 985 986 unset _shunit_file_ 987} 988 989# Final cleanup function to leave things as we found them. 990# 991# Besides removing the temporary directory, this function is in charge of the 992# final exit code of the unit test. The exit code is based on how the script 993# was ended (e.g. normal exit, or via Ctrl-C). 994# 995# Args: 996# name: string: name of the trap called (specified when trap defined) 997_shunit_cleanup() { 998 _shunit_name_=$1 999 1000 _shunit_signal_=0 1001 case "${_shunit_name_}" in 1002 EXIT) ;; 1003 INT) _shunit_signal_=130 ;; # 2+128 1004 TERM) _shunit_signal_=143 ;; # 15+128 1005 *) 1006 _shunit_error "unrecognized trap value (${_shunit_name_})" 1007 ;; 1008 esac 1009 if ${__SHUNIT_BUILTIN} [ "${_shunit_name_}" != 'EXIT' ]; then 1010 _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" 1011 fi 1012 1013 # Do our work. 1014 if ${__SHUNIT_BUILTIN} [ ${__shunit_clean} -eq ${SHUNIT_FALSE} ]; then 1015 # Ensure tear downs are only called once. 1016 __shunit_clean=${SHUNIT_TRUE} 1017 1018 tearDown || _shunit_warn 'tearDown() returned non-zero return code.' 1019 oneTimeTearDown || \ 1020 _shunit_warn 'oneTimeTearDown() returned non-zero return code.' 1021 1022 command rm -fr "${__shunit_tmpDir}" 1023 fi 1024 1025 if ${__SHUNIT_BUILTIN} [ "${_shunit_name_}" != 'EXIT' ]; then 1026 # Handle all non-EXIT signals. 1027 trap - 0 # Disable EXIT trap. 1028 exit ${_shunit_signal_} 1029 elif ${__SHUNIT_BUILTIN} [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ]; then 1030 _shunit_assertFail 'unknown failure encountered running a test' 1031 _shunit_generateReport 1032 exit ${SHUNIT_ERROR} 1033 fi 1034 1035 unset _shunit_name_ _shunit_signal_ 1036} 1037 1038# configureColor based on user color preference. 1039# 1040# Args: 1041# color: string: color mode (one of `always`, `auto`, or `none`). 1042_shunit_configureColor() { 1043 _shunit_color_=${SHUNIT_FALSE} # By default, no color. 1044 case $1 in 1045 'always') _shunit_color_=${SHUNIT_TRUE} ;; 1046 'auto') 1047 if ${__SHUNIT_BUILTIN} [ "`_shunit_colors`" -ge 8 ]; then 1048 _shunit_color_=${SHUNIT_TRUE} 1049 fi 1050 ;; 1051 'none') ;; 1052 *) _shunit_fatal "unrecognized color option '$1'" ;; 1053 esac 1054 1055 case ${_shunit_color_} in 1056 ${SHUNIT_TRUE}) 1057 __shunit_ansi_none=${__SHUNIT_ANSI_NONE} 1058 __shunit_ansi_red=${__SHUNIT_ANSI_RED} 1059 __shunit_ansi_green=${__SHUNIT_ANSI_GREEN} 1060 __shunit_ansi_yellow=${__SHUNIT_ANSI_YELLOW} 1061 __shunit_ansi_cyan=${__SHUNIT_ANSI_CYAN} 1062 ;; 1063 ${SHUNIT_FALSE}) 1064 __shunit_ansi_none='' 1065 __shunit_ansi_red='' 1066 __shunit_ansi_green='' 1067 __shunit_ansi_yellow='' 1068 __shunit_ansi_cyan='' 1069 ;; 1070 esac 1071 1072 unset _shunit_color_ _shunit_tput_ 1073} 1074 1075# colors returns the number of supported colors for the TERM. 1076_shunit_colors() { 1077 if _shunit_tput_=`${SHUNIT_CMD_TPUT} colors 2>/dev/null`; then 1078 echo "${_shunit_tput_}" 1079 else 1080 echo 16 1081 fi 1082 unset _shunit_tput_ 1083} 1084 1085# The actual running of the tests happens here. 1086# 1087# Args: 1088# None 1089_shunit_execSuite() { 1090 for _shunit_test_ in ${__shunit_suite}; do 1091 __shunit_testSuccess=${SHUNIT_TRUE} 1092 1093 # Disable skipping. 1094 endSkipping 1095 1096 # Execute the per-test setup function. 1097 if ! setUp; then 1098 _shunit_fatal "setup() returned non-zero return code." 1099 fi 1100 1101 # Execute the test. 1102 echo "${__SHUNIT_TEST_PREFIX}${_shunit_test_}" 1103 # shellcheck disable=SC2086 1104 if ! eval ${_shunit_test_}; then 1105 _shunit_error "${_shunit_test_}() returned non-zero return code." 1106 __shunit_testSuccess=${SHUNIT_ERROR} 1107 _shunit_incFailedCount 1108 fi 1109 1110 # Execute the per-test tear-down function. 1111 if ! tearDown; then 1112 _shunit_fatal "tearDown() returned non-zero return code." 1113 fi 1114 1115 # Update stats. 1116 if ${__SHUNIT_BUILTIN} [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then 1117 __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` 1118 else 1119 __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` 1120 fi 1121 done 1122 1123 unset _shunit_test_ 1124} 1125 1126# Generates the user friendly report with appropriate OK/FAILED message. 1127# 1128# Args: 1129# None 1130# Output: 1131# string: the report of successful and failed tests, as well as totals. 1132_shunit_generateReport() { 1133 if ${__SHUNIT_BUILTIN} [ "${__shunit_reportGenerated}" -eq ${SHUNIT_TRUE} ]; then 1134 return 1135 fi 1136 1137 _shunit_ok_=${SHUNIT_TRUE} 1138 1139 # If no exit code was provided, determine an appropriate one. 1140 if ${__SHUNIT_BUILTIN} [ "${__shunit_testsFailed}" -gt 0 -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ]; then 1141 _shunit_ok_=${SHUNIT_FALSE} 1142 fi 1143 1144 echo 1145 _shunit_msg_="Ran ${__shunit_ansi_cyan}${__shunit_testsTotal}${__shunit_ansi_none}" 1146 if ${__SHUNIT_BUILTIN} [ "${__shunit_testsTotal}" -eq 1 ]; then 1147 ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} test." 1148 else 1149 ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} tests." 1150 fi 1151 1152 if ${__SHUNIT_BUILTIN} [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then 1153 _shunit_msg_="${__shunit_ansi_green}OK${__shunit_ansi_none}" 1154 if ${__SHUNIT_BUILTIN} [ "${__shunit_assertsSkipped}" -gt 0 ]; then 1155 _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none})" 1156 fi 1157 else 1158 _shunit_msg_="${__shunit_ansi_red}FAILED${__shunit_ansi_none}" 1159 _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_red}failures=${__shunit_assertsFailed}${__shunit_ansi_none}" 1160 if ${__SHUNIT_BUILTIN} [ "${__shunit_assertsSkipped}" -gt 0 ]; then 1161 _shunit_msg_="${_shunit_msg_},${__shunit_ansi_yellow}skipped=${__shunit_assertsSkipped}${__shunit_ansi_none}" 1162 fi 1163 _shunit_msg_="${_shunit_msg_})" 1164 fi 1165 1166 echo 1167 ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_}" 1168 __shunit_reportGenerated=${SHUNIT_TRUE} 1169 1170 unset _shunit_msg_ _shunit_ok_ 1171} 1172 1173# Test for whether a function should be skipped. 1174# 1175# Args: 1176# None 1177# Returns: 1178# boolean: whether the test should be skipped (TRUE/FALSE constant) 1179_shunit_shouldSkip() { 1180 if test ${__shunit_skip} -eq ${SHUNIT_FALSE}; then 1181 return ${SHUNIT_FALSE} 1182 fi 1183 _shunit_assertSkip 1184} 1185 1186# Records a successful test. 1187# 1188# Args: 1189# None 1190_shunit_assertPass() { 1191 __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` 1192 __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 1193} 1194 1195# Records a test failure. 1196# 1197# Args: 1198# message: string: failure message to provide user 1199_shunit_assertFail() { 1200 __shunit_testSuccess=${SHUNIT_FALSE} 1201 _shunit_incFailedCount 1202 1203 if ${__SHUNIT_BUILTIN} [ $# -gt 0 ]; then 1204 ${__SHUNIT_CMD_ECHO_ESC} "${__shunit_ansi_red}ASSERT:${__shunit_ansi_none}$*" 1205 fi 1206} 1207 1208# Increment the count of failed asserts. 1209# 1210# Args: 1211# none 1212_shunit_incFailedCount() { 1213 __shunit_assertsFailed=`expr "${__shunit_assertsFailed}" + 1` 1214 __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` 1215} 1216 1217# Records a skipped test. 1218# 1219# Args: 1220# None 1221_shunit_assertSkip() { 1222 __shunit_assertsSkipped=`expr "${__shunit_assertsSkipped}" + 1` 1223 __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` 1224} 1225 1226# Dump the current test metrics. 1227# 1228# Args: 1229# none 1230_shunit_metrics() { 1231 echo "< \ 1232total: ${__shunit_assertsTotal} \ 1233passed: ${__shunit_assertsPassed} \ 1234failed: ${__shunit_assertsFailed} \ 1235skipped: ${__shunit_assertsSkipped} \ 1236>" 1237} 1238 1239# Prepare a script filename for sourcing. 1240# 1241# Args: 1242# script: string: path to a script to source 1243# Returns: 1244# string: filename prefixed with ./ (if necessary) 1245_shunit_prepForSourcing() { 1246 _shunit_script_=$1 1247 case "${_shunit_script_}" in 1248 /*|./*) echo "${_shunit_script_}" ;; 1249 *) echo "./${_shunit_script_}" ;; 1250 esac 1251 unset _shunit_script_ 1252} 1253 1254# Escape a character in a string. 1255# 1256# Args: 1257# c: string: unescaped character 1258# s: string: to escape character in 1259# Returns: 1260# string: with escaped character(s) 1261_shunit_escapeCharInStr() { 1262 if ${__SHUNIT_BUILTIN} [ -z "$2" ]; then 1263 return # No point in doing work on an empty string. 1264 fi 1265 1266 # Note: using shorter variable names to prevent conflicts with 1267 # _shunit_escapeCharactersInString(). 1268 _shunit_c_=$1 1269 _shunit_s_=$2 1270 1271 # Escape the character. 1272 # shellcheck disable=SC1003,SC2086 1273 echo ''${_shunit_s_}'' |command sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' 1274 1275 unset _shunit_c_ _shunit_s_ 1276} 1277 1278# Escape a character in a string. 1279# 1280# Args: 1281# str: string: to escape characters in 1282# Returns: 1283# string: with escaped character(s) 1284_shunit_escapeCharactersInString() { 1285 if ${__SHUNIT_BUILTIN} [ -z "$1" ]; then 1286 return # No point in doing work on an empty string. 1287 fi 1288 1289 _shunit_str_=$1 1290 1291 # Note: using longer variable names to prevent conflicts with 1292 # _shunit_escapeCharInStr(). 1293 for _shunit_char_ in '"' '$' "'" '`'; do 1294 _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` 1295 done 1296 1297 echo "${_shunit_str_}" 1298 unset _shunit_char_ _shunit_str_ 1299} 1300 1301# Extract list of functions to run tests against. 1302# 1303# Args: 1304# script: string: name of script to extract functions from 1305# Returns: 1306# string: of function names 1307_shunit_extractTestFunctions() { 1308 _shunit_script_=$1 1309 1310 # Extract the lines with test function names, strip of anything besides the 1311 # function name, and output everything on a single line. 1312 _shunit_regex_='^\s*((function test[A-Za-z0-9_-]*)|(test[A-Za-z0-9_-]* *\(\)))' 1313 # shellcheck disable=SC2196 1314 egrep "${_shunit_regex_}" "${_shunit_script_}" \ 1315 |command sed 's/^[^A-Za-z0-9_-]*//;s/^function //;s/\([A-Za-z0-9_-]*\).*/\1/g' \ 1316 |xargs 1317 1318 unset _shunit_regex_ _shunit_script_ 1319} 1320 1321#------------------------------------------------------------------------------ 1322# Main. 1323# 1324 1325# Determine the operating mode. 1326if ${__SHUNIT_BUILTIN} [ $# -eq 0 -o "${1:-}" = '--' ]; then 1327 __shunit_script=${__SHUNIT_PARENT} 1328 __shunit_mode=${__SHUNIT_MODE_SOURCED} 1329else 1330 __shunit_script=$1 1331 if ! ${__SHUNIT_BUILTIN} [ -r "${__shunit_script}" ]; then 1332 _shunit_fatal "unable to read from ${__shunit_script}" 1333 fi 1334 __shunit_mode=${__SHUNIT_MODE_STANDALONE} 1335fi 1336 1337# Create a temporary storage location. 1338__shunit_tmpDir=`_shunit_mktempDir` 1339 1340# Provide a public temporary directory for unit test scripts. 1341# TODO(kward): document this. 1342SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" 1343if ! command mkdir "${SHUNIT_TMPDIR}"; then 1344 _shunit_fatal "error creating SHUNIT_TMPDIR '${SHUNIT_TMPDIR}'" 1345fi 1346 1347# Setup traps to clean up after ourselves. 1348trap '_shunit_cleanup EXIT' 0 1349trap '_shunit_cleanup INT' 2 1350trap '_shunit_cleanup TERM' 15 1351 1352# Create phantom functions to work around issues with Cygwin. 1353_shunit_mktempFunc 1354PATH="${__shunit_tmpDir}:${PATH}" 1355 1356# Make sure phantom functions are executable. This will bite if `/tmp` (or the 1357# current `$TMPDIR`) points to a path on a partition that was mounted with the 1358# 'noexec' option. The noexec command was created with `_shunit_mktempFunc()`. 1359noexec 2>/dev/null || _shunit_fatal \ 1360 'Please declare TMPDIR with path on partition with exec permission.' 1361 1362# We must manually source the tests in standalone mode. 1363if ${__SHUNIT_BUILTIN} [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then 1364 # shellcheck disable=SC1090 1365 ${__SHUNIT_BUILTIN} . "`_shunit_prepForSourcing \"${__shunit_script}\"`" 1366fi 1367 1368# Configure default output coloring behavior. 1369_shunit_configureColor "${SHUNIT_COLOR}" 1370 1371# Execute the oneTimeSetUp function (if it exists). 1372if ! oneTimeSetUp; then 1373 _shunit_fatal "oneTimeSetUp() returned non-zero return code." 1374fi 1375 1376# Command line selected tests or suite selected tests 1377if ${__SHUNIT_BUILTIN} [ "$#" -ge 2 ]; then 1378 # Argument $1 is either the filename of tests or '--'; either way, skip it. 1379 shift 1380 # Remaining arguments ($2 .. $#) are assumed to be test function names. 1381 # Interate through all remaining args in "$@" in a POSIX (likely portable) way. 1382 # Helpful tip: https://unix.stackexchange.com/questions/314032/how-to-use-arguments-like-1-2-in-a-for-loop 1383 for _shunit_arg_ do 1384 suite_addTest "${_shunit_arg_}" 1385 done 1386 unset _shunit_arg_ 1387else 1388 # Execute the suite function defined in the parent test script. 1389 # DEPRECATED as of 2.1.0. 1390 suite 1391fi 1392 1393# If no tests or suite specified, dynamically build a list of functions. 1394if ${__SHUNIT_BUILTIN} [ -z "${__shunit_suite}" ]; then 1395 shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` 1396 for shunit_func_ in ${shunit_funcs_}; do 1397 suite_addTest "${shunit_func_}" 1398 done 1399fi 1400unset shunit_func_ shunit_funcs_ 1401 1402# Execute the suite of unit tests. 1403_shunit_execSuite 1404 1405# Execute the oneTimeTearDown function (if it exists). 1406if ! oneTimeTearDown; then 1407 _shunit_fatal "oneTimeTearDown() returned non-zero return code." 1408fi 1409 1410# Generate a report summary. 1411_shunit_generateReport 1412 1413# That's it folks. 1414if ! ${__SHUNIT_BUILTIN} [ "${__shunit_testsFailed}" -eq 0 ]; then 1415 return ${SHUNIT_FALSE} 1416fi 1417