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