source: trunk/debian/packages/libubox/trunk/examples/shunit2 @ 857

Last change on this file since 857 was 857, checked in by amain, 4 years ago

libubox: initial import / part 4

File size: 28.4 KB
Line 
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
18SHUNIT_VERSION='2.1.7pre'
19
20# return values that scripts can use
21SHUNIT_TRUE=0
22SHUNIT_FALSE=1
23SHUNIT_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`
32case "${__SHUNIT_UNAME_S}" in
33  BSD) __SHUNIT_EXPR_CMD='gexpr' ;;
34  *) __SHUNIT_EXPR_CMD='expr' ;;
35esac
36
37# commands a user can override if needed
38SHUNIT_EXPR_CMD=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}}
39
40# enable strict mode by default
41SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}}
42
43# specific shell checks
44if [ -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
53fi
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`
66echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \
67    __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1`
68for __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
77done
78unset __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)
122assertEquals()
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)
161assertNotEquals()
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)
198assertNull()
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)
227assertNotNull()
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)
259assertSame()
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)
289assertNotSame()
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)
332assertTrue()
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)
397assertFalse()
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)
451fail()
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)
481failNotEquals()
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)
513failSame()
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)
545failNotSame()
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
579startSkipping()
580{
581  __shunit_skip=${SHUNIT_TRUE}
582}
583
584# Resume the normal recording behavior of assert and fail calls.
585#
586# Args:
587#   None
588endSkipping()
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)
599isSkipping()
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
632suite_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
739exit ${SHUNIT_TRUE}
740EOF
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
1002if [ $# -eq 0 ]; then
1003  __shunit_script=${__SHUNIT_PARENT}
1004  __shunit_mode=${__SHUNIT_MODE_SOURCED}
1005else
1006  __shunit_script=$1
1007  [ -r "${__shunit_script}" ] || \
1008      _shunit_fatal "unable to read from ${__shunit_script}"
1009  __shunit_mode=${__SHUNIT_MODE_STANDALONE}
1010fi
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
1017SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp"
1018mkdir "${SHUNIT_TMPDIR}"
1019
1020# setup traps to clean up after ourselves
1021trap '_shunit_cleanup EXIT' 0
1022trap '_shunit_cleanup INT' 2
1023trap '_shunit_cleanup TERM' 15
1024
1025# create phantom functions to work around issues with Cygwin
1026_shunit_mktempFunc
1027PATH="${__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().
1032noexec 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
1036if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then
1037  . "`_shunit_prepForSourcing \"${__shunit_script}\"`"
1038fi
1039
1040# execute the oneTimeSetUp function (if it exists)
1041oneTimeSetUp
1042
1043# execute the suite function defined in the parent test script
1044# deprecated as of 2.1.0
1045suite
1046
1047# if no suite function was defined, dynamically build a list of functions
1048if [ -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
1053fi
1054unset shunit_func_ shunit_funcs_
1055
1056# execute the tests
1057_shunit_execSuite
1058
1059# execute the oneTimeTearDown function (if it exists)
1060oneTimeTearDown
1061
1062# generate the report
1063_shunit_generateReport
1064
1065# that's it folks
1066[ ${__shunit_testsFailed} -eq 0 ]
1067exit $?
Note: See TracBrowser for help on using the repository browser.