1 #! /bin/sh 2 # $Id$ 3 # vim:et:ft=sh:sts=2:sw=2 4 # 5 # Copyright 2008 Kate Ward. All Rights Reserved. 6 # Released under the LGPL (GNU Lesser General Public License) 7 # 8 # shUnit2 -- Unit testing framework for Unix shell scripts. 9 # http://code.google.com/p/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 # return if shunit already loaded 17 [ -n "${SHUNIT_VERSION:-}" ] && exit 0 18 SHUNIT_VERSION='2.1.7pre' 19 20 # return values that scripts can use 21 SHUNIT_TRUE=0 22 SHUNIT_FALSE=1 23 SHUNIT_ERROR=2 24 25 # logging functions 26 _shunit_warn() { echo "shunit2:WARN $@" >&2; } 27 _shunit_error() { echo "shunit2:ERROR $@" >&2; } 28 _shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } 29 30 # determine some reasonable command defaults 31 __SHUNIT_UNAME_S=`uname -s` 32 case "${__SHUNIT_UNAME_S}" in 33 BSD) __SHUNIT_EXPR_CMD='gexpr' ;; 34 *) __SHUNIT_EXPR_CMD='expr' ;; 35 esac 36 37 # commands a user can override if needed 38 SHUNIT_EXPR_CMD=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}} 39 40 # enable strict mode by default 41 SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} 42 43 # specific shell checks 44 if [ -n "${ZSH_VERSION:-}" ]; then 45 setopt |grep "^shwordsplit$" >/dev/null 46 if [ $? -ne ${SHUNIT_TRUE} ]; then 47 _shunit_fatal 'zsh shwordsplit option is required for proper operation' 48 fi 49 if [ -z "${SHUNIT_PARENT:-}" ]; then 50 _shunit_fatal "zsh does not pass \$0 through properly. please declare \ 51 \"SHUNIT_PARENT=\$0\" before calling shUnit2" 52 fi 53 fi 54 55 # 56 # constants 57 # 58 59 __SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' 60 __SHUNIT_MODE_SOURCED='sourced' 61 __SHUNIT_MODE_STANDALONE='standalone' 62 __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} 63 64 # set the constants readonly 65 __shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` 66 echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ 67 __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` 68 for __shunit_const in ${__shunit_constants}; do 69 if [ -z "${ZSH_VERSION:-}" ]; then 70 readonly ${__shunit_const} 71 else 72 case ${ZSH_VERSION} in 73 [123].*) readonly ${__shunit_const} ;; 74 *) readonly -g ${__shunit_const} # declare readonly constants globally 75 esac 76 fi 77 done 78 unset __shunit_const __shunit_constants 79 80 # 81 # internal variables 82 # 83 84 # variables 85 __shunit_lineno='' # line number of executed test 86 __shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode 87 __shunit_reportGenerated=${SHUNIT_FALSE} # is report generated 88 __shunit_script='' # filename of unittest script (standalone mode) 89 __shunit_skip=${SHUNIT_FALSE} # is skipping enabled 90 __shunit_suite='' # suite of tests to execute 91 92 # counts of tests 93 __shunit_testSuccess=${SHUNIT_TRUE} 94 __shunit_testsTotal=0 95 __shunit_testsPassed=0 96 __shunit_testsFailed=0 97 98 # counts of asserts 99 __shunit_assertsTotal=0 100 __shunit_assertsPassed=0 101 __shunit_assertsFailed=0 102 __shunit_assertsSkipped=0 103 104 # macros 105 _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' 106 107 #----------------------------------------------------------------------------- 108 # private functions 109 110 #----------------------------------------------------------------------------- 111 # assert functions 112 # 113 114 # Assert that two values are equal to one another. 115 # 116 # Args: 117 # message: string: failure message [optional] 118 # expected: string: expected value 119 # actual: string: actual value 120 # Returns: 121 # integer: success (TRUE/FALSE/ERROR constant) 122 assertEquals() 123 { 124 ${_SHUNIT_LINENO_} 125 if [ $# -lt 2 -o $# -gt 3 ]; then 126 _shunit_error "assertEquals() requires two or three arguments; $# given" 127 _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" 128 return ${SHUNIT_ERROR} 129 fi 130 _shunit_shouldSkip && return ${SHUNIT_TRUE} 131 132 shunit_message_=${__shunit_lineno} 133 if [ $# -eq 3 ]; then 134 shunit_message_="${shunit_message_}$1" 135 shift 136 fi 137 shunit_expected_=$1 138 shunit_actual_=$2 139 140 shunit_return=${SHUNIT_TRUE} 141 if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then 142 _shunit_assertPass 143 else 144 failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" 145 shunit_return=${SHUNIT_FALSE} 146 fi 147 148 unset shunit_message_ shunit_expected_ shunit_actual_ 149 return ${shunit_return} 150 } 151 _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' 152 153 # Assert that two values are not equal to one another. 154 # 155 # Args: 156 # message: string: failure message [optional] 157 # expected: string: expected value 158 # actual: string: actual value 159 # Returns: 160 # integer: success (TRUE/FALSE/ERROR constant) 161 assertNotEquals() 162 { 163 ${_SHUNIT_LINENO_} 164 if [ $# -lt 2 -o $# -gt 3 ]; then 165 _shunit_error "assertNotEquals() requires two or three arguments; $# given" 166 return ${SHUNIT_ERROR} 167 fi 168 _shunit_shouldSkip && return ${SHUNIT_TRUE} 169 170 shunit_message_=${__shunit_lineno} 171 if [ $# -eq 3 ]; then 172 shunit_message_="${shunit_message_}$1" 173 shift 174 fi 175 shunit_expected_=$1 176 shunit_actual_=$2 177 178 shunit_return=${SHUNIT_TRUE} 179 if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then 180 _shunit_assertPass 181 else 182 failSame "${shunit_message_}" "$@" 183 shunit_return=${SHUNIT_FALSE} 184 fi 185 186 unset shunit_message_ shunit_expected_ shunit_actual_ 187 return ${shunit_return} 188 } 189 _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' 190 191 # Assert that a value is null (i.e. an empty string) 192 # 193 # Args: 194 # message: string: failure message [optional] 195 # actual: string: actual value 196 # Returns: 197 # integer: success (TRUE/FALSE/ERROR constant) 198 assertNull() 199 { 200 ${_SHUNIT_LINENO_} 201 if [ $# -lt 1 -o $# -gt 2 ]; then 202 _shunit_error "assertNull() requires one or two arguments; $# given" 203 return ${SHUNIT_ERROR} 204 fi 205 _shunit_shouldSkip && return ${SHUNIT_TRUE} 206 207 shunit_message_=${__shunit_lineno} 208 if [ $# -eq 2 ]; then 209 shunit_message_="${shunit_message_}$1" 210 shift 211 fi 212 assertTrue "${shunit_message_}" "[ -z '$1' ]" 213 shunit_return=$? 214 215 unset shunit_message_ 216 return ${shunit_return} 217 } 218 _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' 219 220 # Assert that a value is not null (i.e. a non-empty string) 221 # 222 # Args: 223 # message: string: failure message [optional] 224 # actual: string: actual value 225 # Returns: 226 # integer: success (TRUE/FALSE/ERROR constant) 227 assertNotNull() 228 { 229 ${_SHUNIT_LINENO_} 230 if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null 231 _shunit_error "assertNotNull() requires one or two arguments; $# given" 232 return ${SHUNIT_ERROR} 233 fi 234 _shunit_shouldSkip && return ${SHUNIT_TRUE} 235 236 shunit_message_=${__shunit_lineno} 237 if [ $# -eq 2 ]; then 238 shunit_message_="${shunit_message_}$1" 239 shift 240 fi 241 shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` 242 test -n "${shunit_actual_}" 243 assertTrue "${shunit_message_}" $? 244 shunit_return=$? 245 246 unset shunit_actual_ shunit_message_ 247 return ${shunit_return} 248 } 249 _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' 250 251 # Assert that two values are the same (i.e. equal to one another). 252 # 253 # Args: 254 # message: string: failure message [optional] 255 # expected: string: expected value 256 # actual: string: actual value 257 # Returns: 258 # integer: success (TRUE/FALSE/ERROR constant) 259 assertSame() 260 { 261 ${_SHUNIT_LINENO_} 262 if [ $# -lt 2 -o $# -gt 3 ]; then 263 _shunit_error "assertSame() requires two or three arguments; $# given" 264 return ${SHUNIT_ERROR} 265 fi 266 _shunit_shouldSkip && return ${SHUNIT_TRUE} 267 268 shunit_message_=${__shunit_lineno} 269 if [ $# -eq 3 ]; then 270 shunit_message_="${shunit_message_}$1" 271 shift 272 fi 273 assertEquals "${shunit_message_}" "$1" "$2" 274 shunit_return=$? 275 276 unset shunit_message_ 277 return ${shunit_return} 278 } 279 _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' 280 281 # Assert that two values are not the same (i.e. not equal to one another). 282 # 283 # Args: 284 # message: string: failure message [optional] 285 # expected: string: expected value 286 # actual: string: actual value 287 # Returns: 288 # integer: success (TRUE/FALSE/ERROR constant) 289 assertNotSame() 290 { 291 ${_SHUNIT_LINENO_} 292 if [ $# -lt 2 -o $# -gt 3 ]; then 293 _shunit_error "assertNotSame() requires two or three arguments; $# given" 294 return ${SHUNIT_ERROR} 295 fi 296 _shunit_shouldSkip && return ${SHUNIT_TRUE} 297 298 shunit_message_=${__shunit_lineno} 299 if [ $# -eq 3 ]; then 300 shunit_message_="${shunit_message_:-}$1" 301 shift 302 fi 303 assertNotEquals "${shunit_message_}" "$1" "$2" 304 shunit_return=$? 305 306 unset shunit_message_ 307 return ${shunit_return} 308 } 309 _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' 310 311 # Assert that a value or shell test condition is true. 312 # 313 # In shell, a value of 0 is true and a non-zero value is false. Any integer 314 # value passed can thereby be tested. 315 # 316 # Shell supports much more complicated tests though, and a means to support 317 # them was needed. As such, this function tests that conditions are true or 318 # false through evaluation rather than just looking for a true or false. 319 # 320 # The following test will succeed: 321 # assertTrue 0 322 # assertTrue "[ 34 -gt 23 ]" 323 # The folloing test will fail with a message: 324 # assertTrue 123 325 # assertTrue "test failed" "[ -r '/non/existant/file' ]" 326 # 327 # Args: 328 # message: string: failure message [optional] 329 # condition: string: integer value or shell conditional statement 330 # Returns: 331 # integer: success (TRUE/FALSE/ERROR constant) 332 assertTrue() 333 { 334 ${_SHUNIT_LINENO_} 335 if [ $# -lt 1 -o $# -gt 2 ]; then 336 _shunit_error "assertTrue() takes one or two arguments; $# given" 337 return ${SHUNIT_ERROR} 338 fi 339 _shunit_shouldSkip && return ${SHUNIT_TRUE} 340 341 shunit_message_=${__shunit_lineno} 342 if [ $# -eq 2 ]; then 343 shunit_message_="${shunit_message_}$1" 344 shift 345 fi 346 shunit_condition_=$1 347 348 # see if condition is an integer, i.e. a return value 349 shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 350 shunit_return=${SHUNIT_TRUE} 351 if [ -z "${shunit_condition_}" ]; then 352 # null condition 353 shunit_return=${SHUNIT_FALSE} 354 elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 355 then 356 # possible return value. treating 0 as true, and non-zero as false. 357 [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} 358 else 359 # (hopefully) a condition 360 ( eval ${shunit_condition_} ) >/dev/null 2>&1 361 [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} 362 fi 363 364 # record the test 365 if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 366 _shunit_assertPass 367 else 368 _shunit_assertFail "${shunit_message_}" 369 fi 370 371 unset shunit_message_ shunit_condition_ shunit_match_ 372 return ${shunit_return} 373 } 374 _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' 375 376 # Assert that a value or shell test condition is false. 377 # 378 # In shell, a value of 0 is true and a non-zero value is false. Any integer 379 # value passed can thereby be tested. 380 # 381 # Shell supports much more complicated tests though, and a means to support 382 # them was needed. As such, this function tests that conditions are true or 383 # false through evaluation rather than just looking for a true or false. 384 # 385 # The following test will succeed: 386 # assertFalse 1 387 # assertFalse "[ 'apples' = 'oranges' ]" 388 # The folloing test will fail with a message: 389 # assertFalse 0 390 # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" 391 # 392 # Args: 393 # message: string: failure message [optional] 394 # condition: string: integer value or shell conditional statement 395 # Returns: 396 # integer: success (TRUE/FALSE/ERROR constant) 397 assertFalse() 398 { 399 ${_SHUNIT_LINENO_} 400 if [ $# -lt 1 -o $# -gt 2 ]; then 401 _shunit_error "assertFalse() quires one or two arguments; $# given" 402 return ${SHUNIT_ERROR} 403 fi 404 _shunit_shouldSkip && return ${SHUNIT_TRUE} 405 406 shunit_message_=${__shunit_lineno} 407 if [ $# -eq 2 ]; then 408 shunit_message_="${shunit_message_}$1" 409 shift 410 fi 411 shunit_condition_=$1 412 413 # see if condition is an integer, i.e. a return value 414 shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 415 shunit_return=${SHUNIT_TRUE} 416 if [ -z "${shunit_condition_}" ]; then 417 # null condition 418 shunit_return=${SHUNIT_FALSE} 419 elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 420 then 421 # possible return value. treating 0 as true, and non-zero as false. 422 [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} 423 else 424 # (hopefully) a condition 425 ( eval ${shunit_condition_} ) >/dev/null 2>&1 426 [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} 427 fi 428 429 # record the test 430 if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 431 _shunit_assertPass 432 else 433 _shunit_assertFail "${shunit_message_}" 434 fi 435 436 unset shunit_message_ shunit_condition_ shunit_match_ 437 return ${shunit_return} 438 } 439 _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' 440 441 #----------------------------------------------------------------------------- 442 # failure functions 443 # 444 445 # Records a test failure. 446 # 447 # Args: 448 # message: string: failure message [optional] 449 # Returns: 450 # integer: success (TRUE/FALSE/ERROR constant) 451 fail() 452 { 453 ${_SHUNIT_LINENO_} 454 if [ $# -gt 1 ]; then 455 _shunit_error "fail() requires zero or one arguments; $# given" 456 return ${SHUNIT_ERROR} 457 fi 458 _shunit_shouldSkip && return ${SHUNIT_TRUE} 459 460 shunit_message_=${__shunit_lineno} 461 if [ $# -eq 1 ]; then 462 shunit_message_="${shunit_message_}$1" 463 shift 464 fi 465 466 _shunit_assertFail "${shunit_message_}" 467 468 unset shunit_message_ 469 return ${SHUNIT_FALSE} 470 } 471 _FAIL_='eval fail --lineno "${LINENO:-}"' 472 473 # Records a test failure, stating two values were not equal. 474 # 475 # Args: 476 # message: string: failure message [optional] 477 # expected: string: expected value 478 # actual: string: actual value 479 # Returns: 480 # integer: success (TRUE/FALSE/ERROR constant) 481 failNotEquals() 482 { 483 ${_SHUNIT_LINENO_} 484 if [ $# -lt 2 -o $# -gt 3 ]; then 485 _shunit_error "failNotEquals() requires one or two arguments; $# given" 486 return ${SHUNIT_ERROR} 487 fi 488 _shunit_shouldSkip && return ${SHUNIT_TRUE} 489 490 shunit_message_=${__shunit_lineno} 491 if [ $# -eq 3 ]; then 492 shunit_message_="${shunit_message_}$1" 493 shift 494 fi 495 shunit_expected_=$1 496 shunit_actual_=$2 497 498 _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" 499 500 unset shunit_message_ shunit_expected_ shunit_actual_ 501 return ${SHUNIT_FALSE} 502 } 503 _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' 504 505 # Records a test failure, stating two values should have been the same. 506 # 507 # Args: 508 # message: string: failure message [optional] 509 # expected: string: expected value 510 # actual: string: actual value 511 # Returns: 512 # integer: success (TRUE/FALSE/ERROR constant) 513 failSame() 514 { 515 ${_SHUNIT_LINENO_} 516 if [ $# -lt 2 -o $# -gt 3 ]; then 517 _shunit_error "failSame() requires two or three arguments; $# given" 518 return ${SHUNIT_ERROR} 519 fi 520 _shunit_shouldSkip && return ${SHUNIT_TRUE} 521 522 shunit_message_=${__shunit_lineno} 523 if [ $# -eq 3 ]; then 524 shunit_message_="${shunit_message_}$1" 525 shift 526 fi 527 528 _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" 529 530 unset shunit_message_ 531 return ${SHUNIT_FALSE} 532 } 533 _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' 534 535 # Records a test failure, stating two values were not equal. 536 # 537 # This is functionally equivalent to calling failNotEquals(). 538 # 539 # Args: 540 # message: string: failure message [optional] 541 # expected: string: expected value 542 # actual: string: actual value 543 # Returns: 544 # integer: success (TRUE/FALSE/ERROR constant) 545 failNotSame() 546 { 547 ${_SHUNIT_LINENO_} 548 if [ $# -lt 2 -o $# -gt 3 ]; then 549 _shunit_error "failNotEquals() requires one or two arguments; $# given" 550 return ${SHUNIT_ERROR} 551 fi 552 _shunit_shouldSkip && return ${SHUNIT_TRUE} 553 554 shunit_message_=${__shunit_lineno} 555 if [ $# -eq 3 ]; then 556 shunit_message_="${shunit_message_}$1" 557 shift 558 fi 559 failNotEquals "${shunit_message_}" "$1" "$2" 560 shunit_return=$? 561 562 unset shunit_message_ 563 return ${shunit_return} 564 } 565 _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' 566 567 #----------------------------------------------------------------------------- 568 # skipping functions 569 # 570 571 # Force remaining assert and fail functions to be "skipped". 572 # 573 # This function forces the remaining assert and fail functions to be "skipped", 574 # i.e. they will have no effect. Each function skipped will be recorded so that 575 # the total of asserts and fails will not be altered. 576 # 577 # Args: 578 # None 579 startSkipping() 580 { 581 __shunit_skip=${SHUNIT_TRUE} 582 } 583 584 # Resume the normal recording behavior of assert and fail calls. 585 # 586 # Args: 587 # None 588 endSkipping() 589 { 590 __shunit_skip=${SHUNIT_FALSE} 591 } 592 593 # Returns the state of assert and fail call skipping. 594 # 595 # Args: 596 # None 597 # Returns: 598 # boolean: (TRUE/FALSE constant) 599 isSkipping() 600 { 601 return ${__shunit_skip} 602 } 603 604 #----------------------------------------------------------------------------- 605 # suite functions 606 # 607 608 # Stub. This function should contains all unit test calls to be made. 609 # 610 # DEPRECATED (as of 2.1.0) 611 # 612 # This function can be optionally overridden by the user in their test suite. 613 # 614 # If this function exists, it will be called when shunit2 is sourced. If it 615 # does not exist, shunit2 will search the parent script for all functions 616 # beginning with the word 'test', and they will be added dynamically to the 617 # test suite. 618 # 619 # This function should be overridden by the user in their unit test suite. 620 # Note: see _shunit_mktempFunc() for actual implementation 621 # 622 # Args: 623 # None 624 #suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION 625 626 # Adds a function name to the list of tests schedule for execution. 627 # 628 # This function should only be called from within the suite() function. 629 # 630 # Args: 631 # function: string: name of a function to add to current unit test suite 632 suite_addTest() 633 { 634 shunit_func_=${1:-} 635 636 __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" 637 __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` 638 639 unset shunit_func_ 640 } 641 642 # Stub. This function will be called once before any tests are run. 643 # 644 # Common one-time environment preparation tasks shared by all tests can be 645 # defined here. 646 # 647 # This function should be overridden by the user in their unit test suite. 648 # Note: see _shunit_mktempFunc() for actual implementation 649 # 650 # Args: 651 # None 652 #oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION 653 654 # Stub. This function will be called once after all tests are finished. 655 # 656 # Common one-time environment cleanup tasks shared by all tests can be defined 657 # here. 658 # 659 # This function should be overridden by the user in their unit test suite. 660 # Note: see _shunit_mktempFunc() for actual implementation 661 # 662 # Args: 663 # None 664 #oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 665 666 # Stub. This function will be called before each test is run. 667 # 668 # Common environment preparation tasks shared by all tests can be defined here. 669 # 670 # This function should be overridden by the user in their unit test suite. 671 # Note: see _shunit_mktempFunc() for actual implementation 672 # 673 # Args: 674 # None 675 #setUp() { :; } 676 677 # Note: see _shunit_mktempFunc() for actual implementation 678 # Stub. This function will be called after each test is run. 679 # 680 # Common environment cleanup tasks shared by all tests can be defined here. 681 # 682 # This function should be overridden by the user in their unit test suite. 683 # Note: see _shunit_mktempFunc() for actual implementation 684 # 685 # Args: 686 # None 687 #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 688 689 #------------------------------------------------------------------------------ 690 # internal shUnit2 functions 691 # 692 693 # Create a temporary directory to store various run-time files in. 694 # 695 # This function is a cross-platform temporary directory creation tool. Not all 696 # OSes have the mktemp function, so one is included here. 697 # 698 # Args: 699 # None 700 # Outputs: 701 # string: the temporary directory that was created 702 _shunit_mktempDir() 703 { 704 # try the standard mktemp function 705 ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return 706 707 # the standard mktemp didn't work. doing our own. 708 if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then 709 _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 </dev/urandom \ 710 |sed 's/^[^0-9a-f]*//'` 711 elif [ -n "${RANDOM:-}" ]; then 712 # $RANDOM works 713 _shunit_random_=${RANDOM}${RANDOM}${RANDOM}$$ 714 else 715 # $RANDOM doesn't work 716 _shunit_date_=`date '+%Y%m%d%H%M%S'` 717 _shunit_random_=`expr ${_shunit_date_} / $$` 718 fi 719 720 _shunit_tmpDir_="${TMPDIR:-/tmp}/shunit.${_shunit_random_}" 721 ( umask 077 && mkdir "${_shunit_tmpDir_}" ) || \ 722 _shunit_fatal 'could not create temporary directory! exiting' 723 724 echo ${_shunit_tmpDir_} 725 unset _shunit_date_ _shunit_random_ _shunit_tmpDir_ 726 } 727 728 # This function is here to work around issues in Cygwin. 729 # 730 # Args: 731 # None 732 _shunit_mktempFunc() 733 { 734 for _shunit_func_ in oneTimeSetUp oneTimeTearDown setUp tearDown suite noexec 735 do 736 _shunit_file_="${__shunit_tmpDir}/${_shunit_func_}" 737 cat <<EOF >"${_shunit_file_}" 738 #! /bin/sh 739 exit ${SHUNIT_TRUE} 740 EOF 741 chmod +x "${_shunit_file_}" 742 done 743 744 unset _shunit_file_ 745 } 746 747 # Final cleanup function to leave things as we found them. 748 # 749 # Besides removing the temporary directory, this function is in charge of the 750 # final exit code of the unit test. The exit code is based on how the script 751 # was ended (e.g. normal exit, or via Ctrl-C). 752 # 753 # Args: 754 # name: string: name of the trap called (specified when trap defined) 755 _shunit_cleanup() 756 { 757 _shunit_name_=$1 758 759 case ${_shunit_name_} in 760 EXIT) _shunit_signal_=0 ;; 761 INT) _shunit_signal_=2 ;; 762 TERM) _shunit_signal_=15 ;; 763 *) 764 _shunit_warn "unrecognized trap value (${_shunit_name_})" 765 _shunit_signal_=0 766 ;; 767 esac 768 769 # do our work 770 rm -fr "${__shunit_tmpDir}" 771 772 # exit for all non-EXIT signals 773 if [ ${_shunit_name_} != 'EXIT' ]; then 774 _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" 775 # disable EXIT trap 776 trap 0 777 # add 128 to signal and exit 778 exit `expr ${_shunit_signal_} + 128` 779 elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then 780 _shunit_assertFail 'Unknown failure encountered running a test' 781 _shunit_generateReport 782 exit ${SHUNIT_ERROR} 783 fi 784 785 unset _shunit_name_ _shunit_signal_ 786 } 787 788 # The actual running of the tests happens here. 789 # 790 # Args: 791 # None 792 _shunit_execSuite() 793 { 794 for _shunit_test_ in ${__shunit_suite}; do 795 __shunit_testSuccess=${SHUNIT_TRUE} 796 797 # disable skipping 798 endSkipping 799 800 # execute the per-test setup function 801 setUp 802 803 # execute the test 804 echo "${_shunit_test_}" 805 eval ${_shunit_test_} 806 807 # execute the per-test tear-down function 808 tearDown 809 810 # update stats 811 if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then 812 __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` 813 else 814 __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` 815 fi 816 done 817 818 unset _shunit_test_ 819 } 820 821 # Generates the user friendly report with appropriate OK/FAILED message. 822 # 823 # Args: 824 # None 825 # Output: 826 # string: the report of successful and failed tests, as well as totals. 827 _shunit_generateReport() 828 { 829 _shunit_ok_=${SHUNIT_TRUE} 830 831 # if no exit code was provided one, determine an appropriate one 832 [ ${__shunit_testsFailed} -gt 0 \ 833 -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ 834 && _shunit_ok_=${SHUNIT_FALSE} 835 836 echo 837 if [ ${__shunit_testsTotal} -eq 1 ]; then 838 echo "Ran ${__shunit_testsTotal} test." 839 else 840 echo "Ran ${__shunit_testsTotal} tests." 841 fi 842 843 _shunit_failures_='' 844 _shunit_skipped_='' 845 [ ${__shunit_assertsFailed} -gt 0 ] \ 846 && _shunit_failures_="failures=${__shunit_assertsFailed}" 847 [ ${__shunit_assertsSkipped} -gt 0 ] \ 848 && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" 849 850 if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then 851 _shunit_msg_='OK' 852 [ -n "${_shunit_skipped_}" ] \ 853 && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" 854 else 855 _shunit_msg_="FAILED (${_shunit_failures_}" 856 [ -n "${_shunit_skipped_}" ] \ 857 && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" 858 _shunit_msg_="${_shunit_msg_})" 859 fi 860 861 echo 862 echo ${_shunit_msg_} 863 __shunit_reportGenerated=${SHUNIT_TRUE} 864 865 unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ 866 } 867 868 # Test for whether a function should be skipped. 869 # 870 # Args: 871 # None 872 # Returns: 873 # boolean: whether the test should be skipped (TRUE/FALSE constant) 874 _shunit_shouldSkip() 875 { 876 [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} 877 _shunit_assertSkip 878 } 879 880 # Records a successful test. 881 # 882 # Args: 883 # None 884 _shunit_assertPass() 885 { 886 __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` 887 __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 888 } 889 890 # Records a test failure. 891 # 892 # Args: 893 # message: string: failure message to provide user 894 _shunit_assertFail() 895 { 896 _shunit_msg_=$1 897 898 __shunit_testSuccess=${SHUNIT_FALSE} 899 __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` 900 __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 901 echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" 902 903 unset _shunit_msg_ 904 } 905 906 # Records a skipped test. 907 # 908 # Args: 909 # None 910 _shunit_assertSkip() 911 { 912 __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` 913 __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 914 } 915 916 # Prepare a script filename for sourcing. 917 # 918 # Args: 919 # script: string: path to a script to source 920 # Returns: 921 # string: filename prefixed with ./ (if necessary) 922 _shunit_prepForSourcing() 923 { 924 _shunit_script_=$1 925 case "${_shunit_script_}" in 926 /*|./*) echo "${_shunit_script_}" ;; 927 *) echo "./${_shunit_script_}" ;; 928 esac 929 unset _shunit_script_ 930 } 931 932 # Escape a character in a string. 933 # 934 # Args: 935 # c: string: unescaped character 936 # s: string: to escape character in 937 # Returns: 938 # string: with escaped character(s) 939 _shunit_escapeCharInStr() 940 { 941 [ -n "$2" ] || return # no point in doing work on an empty string 942 943 # Note: using shorter variable names to prevent conflicts with 944 # _shunit_escapeCharactersInString(). 945 _shunit_c_=$1 946 _shunit_s_=$2 947 948 949 # escape the character 950 echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' 951 952 unset _shunit_c_ _shunit_s_ 953 } 954 955 # Escape a character in a string. 956 # 957 # Args: 958 # str: string: to escape characters in 959 # Returns: 960 # string: with escaped character(s) 961 _shunit_escapeCharactersInString() 962 { 963 [ -n "$1" ] || return # no point in doing work on an empty string 964 965 _shunit_str_=$1 966 967 # Note: using longer variable names to prevent conflicts with 968 # _shunit_escapeCharInStr(). 969 for _shunit_char_ in '"' '$' "'" '`'; do 970 _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` 971 done 972 973 echo "${_shunit_str_}" 974 unset _shunit_char_ _shunit_str_ 975 } 976 977 # Extract list of functions to run tests against. 978 # 979 # Args: 980 # script: string: name of script to extract functions from 981 # Returns: 982 # string: of function names 983 _shunit_extractTestFunctions() 984 { 985 _shunit_script_=$1 986 987 # extract the lines with test function names, strip of anything besides the 988 # function name, and output everything on a single line. 989 _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' 990 egrep "${_shunit_regex_}" "${_shunit_script_}" \ 991 |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ 992 |xargs 993 994 unset _shunit_regex_ _shunit_script_ 995 } 996 997 #------------------------------------------------------------------------------ 998 # main 999 # 1000 1001 # determine the operating mode 1002 if [ $# -eq 0 ]; then 1003 __shunit_script=${__SHUNIT_PARENT} 1004 __shunit_mode=${__SHUNIT_MODE_SOURCED} 1005 else 1006 __shunit_script=$1 1007 [ -r "${__shunit_script}" ] || \ 1008 _shunit_fatal "unable to read from ${__shunit_script}" 1009 __shunit_mode=${__SHUNIT_MODE_STANDALONE} 1010 fi 1011 1012 # create a temporary storage location 1013 __shunit_tmpDir=`_shunit_mktempDir` 1014 1015 # provide a public temporary directory for unit test scripts 1016 # TODO(kward): document this 1017 SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" 1018 mkdir "${SHUNIT_TMPDIR}" 1019 1020 # setup traps to clean up after ourselves 1021 trap '_shunit_cleanup EXIT' 0 1022 trap '_shunit_cleanup INT' 2 1023 trap '_shunit_cleanup TERM' 15 1024 1025 # create phantom functions to work around issues with Cygwin 1026 _shunit_mktempFunc 1027 PATH="${__shunit_tmpDir}:${PATH}" 1028 1029 # make sure phantom functions are executable. this will bite if /tmp (or the 1030 # current $TMPDIR) points to a path on a partition that was mounted with the 1031 # 'noexec' option. the noexec command was created with _shunit_mktempFunc(). 1032 noexec 2>/dev/null || _shunit_fatal \ 1033 'please declare TMPDIR with path on partition with exec permission' 1034 1035 # we must manually source the tests in standalone mode 1036 if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then 1037 . "`_shunit_prepForSourcing \"${__shunit_script}\"`" 1038 fi 1039 1040 # execute the oneTimeSetUp function (if it exists) 1041 oneTimeSetUp 1042 1043 # execute the suite function defined in the parent test script 1044 # deprecated as of 2.1.0 1045 suite 1046 1047 # if no suite function was defined, dynamically build a list of functions 1048 if [ -z "${__shunit_suite}" ]; then 1049 shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` 1050 for shunit_func_ in ${shunit_funcs_}; do 1051 suite_addTest ${shunit_func_} 1052 done 1053 fi 1054 unset shunit_func_ shunit_funcs_ 1055 1056 # execute the tests 1057 _shunit_execSuite 1058 1059 # execute the oneTimeTearDown function (if it exists) 1060 oneTimeTearDown 1061 1062 # generate the report 1063 _shunit_generateReport 1064 1065 # that's it folks 1066 [ ${__shunit_testsFailed} -eq 0 ] 1067 exit $?
This page was automatically generated by LXR 0.3.1. • OpenWrt