Adds a unit test framework based on shunit2
[project/uci.git] / test / shunit2 / shunit2
1 # $Id: shunit2 189 2008-07-11 11:46:54Z kate.ward@forestent.com $
2 # vim:et:ft=sh:sts=2:sw=2
3 # vim:foldmethod=marker:foldmarker=/**,*/
4 #
5 #/**
6 # <?xml version="1.0" encoding="UTF-8"?>
7 # <s:shelldoc xmlns:s="http://www.forestent.com/projects/shelldoc/xsl/2005.0">
8 # <s:header>
9 # shUnit 2.1.4
10 # Shell Unit Test Framework
11 #
12 # http://shunit2.sourceforge.net/
13 #
14 # written by Kate Ward &lt;kate.ward@forestent.com&gt;
15 # released under the LGPL
16 #
17 # this module implements a xUnit based unit test framework similar to JUnit
18 # </s:header>
19 #*/
20
21 SHUNIT_VERSION='2.1.4'
22
23 _shunit_warn() { echo "shunit2:WARN $@" >&2; }
24 _shunit_error() { echo "shunit2:ERROR $@" >&2; }
25 _shunit_fatal() { echo "shunit2:FATAL $@" >&2; }
26
27 SHUNIT_TRUE=0
28 SHUNIT_FALSE=1
29 SHUNIT_ERROR=2
30
31 # specific shell checks
32 if [ -n "${ZSH_VERSION:-}" ]; then
33   setopt |grep "^shwordsplit$" >/dev/null
34   if [ $? -ne ${SHUNIT_TRUE} ]; then
35     _shunit_fatal 'zsh shwordsplit option is required for proper operation'
36     exit ${SHUNIT_ERROR}
37   fi
38   if [ -z "${SHUNIT_PARENT:-}" ]; then
39     _shunit_fatal "zsh does not pass \$0 through properly. please declare \
40 \"SHUNIT_PARENT=\$0\" before calling shUnit2"
41     exit ${SHUNIT_ERROR}
42   fi
43 fi
44
45 # shell flags for shunit2:
46 # u - treat unset variables as an error when performing parameter expansion
47 __SHUNIT_SHELL_FLAGS='u'
48
49 # save the current set of shell flags, and then set some for ourself
50 shunit_shellFlags_="$-"
51 for shunit_shellFlag_ in `echo "${__SHUNIT_SHELL_FLAGS}" |sed 's/\(.\)/\1 /g'`
52 do
53   set -${shunit_shellFlag_}
54 done
55
56 #
57 # constants
58 #
59
60 __SHUNIT_ASSERT_MSG_PREFIX='ASSERT:'
61 __SHUNIT_PARENT=${SHUNIT_PARENT:-$0}
62
63 # set the constants readonly
64 shunit_constants_=`set |grep "^__SHUNIT_" |cut -d= -f1`
65 echo "${shunit_constants_}" |grep "^Binary file" >/dev/null
66 if [ $? -eq 0 ]; then
67   # deal with binary junk in 'set' output
68   shunit_constants_=`set |grep -a "^__SHUNIT_" |cut -d= -f1`
69 fi
70 for shunit_const_ in ${shunit_constants_}; do
71   shunit_ro_opts_=''
72   if [ -n "${ZSH_VERSION:-}" ]; then
73     case ${ZSH_VERSION} in
74       [123].*) ;;
75       *) shunit_ro_opts_='-g' ;;  # declare readonly constants globally
76     esac
77   fi
78   readonly ${shunit_ro_opts_} ${shunit_const_}
79 done
80 unset shunit_const_ shunit_constants_ shunit_ro_opts_
81
82 # variables
83 __shunit_skip=${SHUNIT_FALSE}
84 __shunit_suite=''
85
86 __shunit_testsPassed=0
87 __shunit_testsFailed=0
88 __shunit_testsSkipped=0
89 __shunit_testsTotal=0
90
91 # macros
92 _SHUNIT_LINENO_='eval if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && shunit_message_="[$2]"; shift 2; fi'
93
94 #-----------------------------------------------------------------------------
95 # assert functions
96 #
97
98 #/**
99 # <s:function group="asserts">
100 # <entry align="right">
101 #   <emphasis>void</emphasis>
102 # </entry>
103 # <entry>
104 #   <funcsynopsis>
105 #     <funcprototype>
106 #       <funcdef><function>assertEquals</function></funcdef>
107 #       <paramdef>string <parameter>[message]</parameter></paramdef>
108 #       <paramdef>string <parameter>expected</parameter></paramdef>
109 #       <paramdef>string <parameter>actual</parameter></paramdef>
110 #     </funcprototype>
111 #   </funcsynopsis>
112 #   <para>Asserts that <emphasis>expected</emphasis> and
113 #   <emphasis>actual</emphasis> are equal to one another. The message is
114 #   optional.</para>
115 # </entry>
116 # </s:function>
117 #*/
118 assertEquals()
119 {
120   ${_SHUNIT_LINENO_}
121   if [ $# -lt 2 -o $# -gt 3 ]; then
122     _shunit_error 'assertEquals() requires one or two arguments'
123     return ${SHUNIT_ERROR}
124   fi
125   _shunit_shouldSkip && return ${SHUNIT_TRUE}
126
127   [ -z "${shunit_message_:-}" ] && shunit_message_=''
128   if [ $# -eq 3 ]; then
129     shunit_message_="${shunit_message_}$1"
130     shift
131   fi
132   shunit_expected_=$1
133   shunit_actual_=$2
134
135   shunit_return=${SHUNIT_TRUE}
136   if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then
137     _shunit_testPassed
138   else
139     failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}"
140     shunit_return=${SHUNIT_FALSE}
141   fi
142
143   unset shunit_message_ shunit_expected_ shunit_actual_ __shunit_lineno
144   return ${shunit_return}
145 }
146 _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"'
147
148 #/**
149 # <s:function group="asserts">
150 # <entry align="right">
151 #   <emphasis>void</emphasis>
152 # </entry>
153 # <entry>
154 #   <funcsynopsis>
155 #     <funcprototype>
156 #       <funcdef><function>assertNull</function></funcdef>
157 #       <paramdef>string <parameter>[message]</parameter></paramdef>
158 #       <paramdef>string <parameter>value</parameter></paramdef>
159 #     </funcprototype>
160 #   </funcsynopsis>
161 #   <para>Asserts that <emphasis>value</emphasis> is <literal>null</literal>,
162 #   or in shell terms a zero-length string. The message is optional.</para>
163 # </entry>
164 # </s:function>
165 #*/
166 assertNull()
167 {
168   ${_SHUNIT_LINENO_}
169   if [ $# -lt 1 -o $# -gt 2 ]; then
170     _shunit_error 'assertNull() requires one or two arguments'
171     return ${SHUNIT_ERROR}
172   fi
173   _shunit_shouldSkip && return ${SHUNIT_TRUE}
174
175   [ -z "${shunit_message_:-}" ] && shunit_message_=''
176   if [ $# -eq 2 ]; then
177     shunit_message_="${shunit_message_}$1"
178     shift
179   fi
180   if [ $# -eq 2 ]; then
181     assertTrue "${shunit_message_}$1" "[ -z '$2' ]"
182   else
183     assertTrue "[ -z '$1' ]"
184   fi
185 }
186 _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"'
187
188 #/**
189 # <s:function group="asserts">
190 # <entry align="right">
191 #   <emphasis>void</emphasis>
192 # </entry>
193 # <entry>
194 #   <funcsynopsis>
195 #     <funcprototype>
196 #       <funcdef><function>assertNotNull</function></funcdef>
197 #       <paramdef>string <parameter>[message]</parameter></paramdef>
198 #       <paramdef>string <parameter>value</parameter></paramdef>
199 #     </funcprototype>
200 #   </funcsynopsis>
201 #   <para>Asserts that <emphasis>value</emphasis> is <emphasis
202 #   role="strong">not</emphasis> <literal>null</literal>, or in shell terms not
203 #   a zero-length string. The message is optional.</para>
204 # </entry>
205 # </s:function>
206 #*/
207 assertNotNull()
208 {
209   ${_SHUNIT_LINENO_}
210   if [ $# -gt 2 ]; then  # allowing 0 arguments as $1 might actually be null
211     _shunit_error 'assertNotNull() requires one or two arguments'
212     return ${SHUNIT_ERROR}
213   fi
214   _shunit_shouldSkip && return ${SHUNIT_TRUE}
215
216   if [ $# -eq 2 ]; then
217     assertTrue "$1" "[ -n '$2' ]"
218   else
219     assertTrue "[ -n '${1:-}' ]"
220   fi
221 }
222 _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"'
223
224 #/**
225 # <s:function group="asserts">
226 # <entry align="right">
227 #   <emphasis>void</emphasis>
228 # </entry>
229 # <entry>
230 #   <funcsynopsis>
231 #     <funcprototype>
232 #       <funcdef><function>assertSame</function></funcdef>
233 #       <paramdef>string <parameter>[message]</parameter></paramdef>
234 #       <paramdef>string <parameter>expected</parameter></paramdef>
235 #       <paramdef>string <parameter>actual</parameter></paramdef>
236 #     </funcprototype>
237 #   </funcsynopsis>
238 #   <para>This function is functionally equivalent to
239 #   <function>assertEquals</function>.</para>
240 # </entry>
241 # </s:function>
242 #*/
243 assertSame()
244 {
245   ${_SHUNIT_LINENO_}
246   if [ $# -lt 2 -o $# -gt 3 ]; then
247     _shunit_error 'assertSame() requires one or two arguments'
248     return ${SHUNIT_ERROR}
249   fi
250   _shunit_shouldSkip && return ${SHUNIT_TRUE}
251
252   if [ $# -eq 2 ]; then
253     assertEquals "$1" "$2"
254   else
255     assertEquals "$1" "$2" "$3"
256   fi
257 }
258 _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"'
259
260 #/**
261 # <s:function group="asserts">
262 # <entry align="right">
263 #   <emphasis>void</emphasis>
264 # </entry>
265 # <entry>
266 #   <funcsynopsis>
267 #     <funcprototype>
268 #       <funcdef><function>assertNotSame</function></funcdef>
269 #       <paramdef>string <parameter>[message]</parameter></paramdef>
270 #       <paramdef>string <parameter>unexpected</parameter></paramdef>
271 #       <paramdef>string <parameter>actual</parameter></paramdef>
272 #     </funcprototype>
273 #   </funcsynopsis>
274 #   <para>Asserts that <emphasis>unexpected</emphasis> and
275 #   <emphasis>actual</emphasis> are <emphasis role="strong">not</emphasis>
276 #   equal to one another. The message is optional.</para>
277 # </entry>
278 # </s:function>
279 #*/
280 assertNotSame()
281 {
282   ${_SHUNIT_LINENO_}
283   if [ $# -lt 2 -o $# -gt 3 ]; then
284     _shunit_error 'assertNotSame() requires two or three arguments'
285     return ${SHUNIT_ERROR}
286   fi
287   _shunit_shouldSkip && return ${SHUNIT_TRUE}
288
289   [ -z "${shunit_message_:-}" ] && shunit_message_=''
290   if [ $# -eq 3 ]; then
291     shunit_message_="${shunit_message_}$1"
292     shift
293   fi
294   shunit_unexpected_=$1
295   shunit_actual_=$2
296
297   shunit_return=${SHUNIT_TRUE}
298   if [ "${shunit_unexpected_}" != "${shunit_actual_}" ]; then
299     _shunit_testPassed
300   else
301     failSame "${shunit_message_}" "$@"
302     shunit_return=${SHUNIT_FALSE}
303   fi
304
305   unset shunit_message_ shunit_unexpected_ shunit_actual_
306   return ${shunit_return}
307 }
308 _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"'
309
310 #/**
311 # <s:function group="asserts">
312 # <entry align="right">
313 #   <emphasis>void</emphasis>
314 # </entry>
315 # <entry>
316 #   <funcsynopsis>
317 #     <funcprototype>
318 #       <funcdef><function>assertTrue</function></funcdef>
319 #       <paramdef>string <parameter>[message]</parameter></paramdef>
320 #       <paramdef>string <parameter>condition</parameter></paramdef>
321 #     </funcprototype>
322 #   </funcsynopsis>
323 #   <para>Asserts that a given shell test condition is true. The message is
324 #   optional.</para>
325 #   <para>Testing whether something is true or false is easy enough by using
326 #   the assertEquals/assertNotSame functions. Shell supports much more
327 #   complicated tests though, and a means to support them was needed. As such,
328 #   this function tests that conditions are true or false through evaluation
329 #   rather than just looking for a true or false.</para>
330 #   <funcsynopsis>
331 #     The following test will succeed: <funcsynopsisinfo>assertTrue "[ 34 -gt 23 ]"</funcsynopsisinfo>
332 #     The folloing test will fail with a message: <funcsynopsisinfo>assertTrue "test failed" "[ -r '/non/existant/file' ]"</funcsynopsisinfo>
333 #   </funcsynopsis>
334 # </entry>
335 # </s:function>
336 #*/
337 assertTrue()
338 {
339   ${_SHUNIT_LINENO_}
340   if [ $# -gt 2 ]; then
341     _shunit_error 'assertTrue() takes one two arguments'
342     return ${SHUNIT_ERROR}
343   fi
344   _shunit_shouldSkip && return ${SHUNIT_TRUE}
345
346   [ -z "${shunit_message_:-}" ] && shunit_message_=''
347   if [ $# -eq 2 ]; then
348     shunit_message_="${shunit_message_}$1"
349     shift
350   fi
351   shunit_condition_=$1
352
353   # see if condition is an integer, i.e. a return value
354   shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'`
355   shunit_return=${SHUNIT_TRUE}
356   if [ -z "${shunit_condition_}" ]; then
357     # null condition
358     shunit_return=${SHUNIT_FALSE}
359   elif [ "${shunit_condition_}" = "${shunit_match_}" ]; then
360     # possible return value. treating 0 as true, and non-zero as false.
361     [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE}
362   else
363     # (hopefully) a condition
364     ( eval ${shunit_condition_} ) >/dev/null 2>&1
365     [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE}
366   fi
367
368   # record the test
369   if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then
370     _shunit_testPassed
371   else
372     _shunit_testFailed "${shunit_message_}"
373   fi
374
375   unset shunit_message_ shunit_condition_ shunit_match_
376   return ${shunit_return}
377 }
378 _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"'
379
380 #/**
381 # <s:function group="asserts">
382 # <entry align="right">
383 #   <emphasis>void</emphasis>
384 # </entry>
385 # <entry>
386 #   <funcsynopsis>
387 #     <funcprototype>
388 #       <funcdef><function>assertFalse</function></funcdef>
389 #       <paramdef>string <parameter>[message]</parameter></paramdef>
390 #       <paramdef>string <parameter>condition</parameter></paramdef>
391 #     </funcprototype>
392 #   </funcsynopsis>
393 #   <para>Asserts that a given shell test condition is false. The message is
394 #   optional.</para>
395 #   <para>Testing whether something is true or false is easy enough by using
396 #   the assertEquals/assertNotSame functions. Shell supports much more
397 #   complicated tests though, and a means to support them was needed. As such,
398 #   this function tests that conditions are true or false through evaluation
399 #   rather than just looking for a true or false.</para>
400 #   <funcsynopsis>
401 #     The following test will succeed: <funcsynopsisinfo>assertFalse "[ 'apples' = 'oranges' ]"</funcsynopsisinfo>
402 #     The folloing test will fail with a message: <funcsynopsisinfo>assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]"</funcsynopsisinfo>
403 #   </funcsynopsis>
404 # </entry>
405 # </s:function>
406 #*/
407 assertFalse()
408 {
409   ${_SHUNIT_LINENO_}
410   if [ $# -lt 1 -o $# -gt 2 ]; then
411     _shunit_error 'assertFalse() quires one or two arguments'
412     return ${SHUNIT_ERROR}
413   fi
414   _shunit_shouldSkip && return ${SHUNIT_TRUE}
415
416   [ -z "${shunit_message_:-}" ] && shunit_message_=''
417   if [ $# -eq 2 ]; then
418     shunit_message_="${shunit_message_}$1"
419     shift
420   fi
421   shunit_condition_=$1
422
423   # see if condition is an integer, i.e. a return value
424   shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'`
425   shunit_return=${SHUNIT_TRUE}
426   if [ -z "${shunit_condition_}" ]; then
427     # null condition
428     shunit_return=${SHUNIT_FALSE}
429   elif [ "${shunit_condition_}" = "${shunit_match_}" ]; then
430     # possible return value. treating 0 as true, and non-zero as false.
431     [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE}
432   else
433     # (hopefully) a condition
434     ( eval ${shunit_condition_} ) >/dev/null 2>&1
435     [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE}
436   fi
437
438   # record the test
439   if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then
440     _shunit_testPassed
441   else
442     _shunit_testFailed "${shunit_message_}"
443   fi
444
445   unset shunit_message_ shunit_condition_ shunit_match_
446   return ${shunit_return}
447 }
448 _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"'
449
450 #-----------------------------------------------------------------------------
451 # failure functions
452 #
453
454 #/**
455 # <s:function group="failures">
456 # <entry align="right">
457 #   <emphasis>void</emphasis>
458 # </entry>
459 # <entry>
460 #   <funcsynopsis>
461 #     <funcprototype>
462 #       <funcdef><function>fail</function></funcdef>
463 #       <paramdef>string <parameter>[message]</parameter></paramdef>
464 #     </funcprototype>
465 #   </funcsynopsis>
466 #   <para>Fails the test immediately, with the optional message.</para>
467 # </entry>
468 # </s:function>
469 #*/
470 fail()
471 {
472   ${_SHUNIT_LINENO_}
473   if [ $# -gt 1 ]; then
474     _shunit_error 'fail() requires one or two arguments'
475     return ${SHUNIT_ERROR}
476   fi
477   _shunit_shouldSkip && return ${SHUNIT_TRUE}
478
479   [ -z "${shunit_message_:-}" ] && shunit_message_=''
480   if [ $# -eq 1 ]; then
481     shunit_message_="${shunit_message_}$1"
482     shift
483   fi
484
485   _shunit_testFailed "${shunit_message_}"
486
487   unset shunit_message_
488   return ${SHUNIT_FALSE}
489 }
490 _FAIL_='eval fail --lineno "${LINENO:-}"'
491
492 #/**
493 # <s:function group="failures">
494 # <entry align="right">
495 #   <emphasis>void</emphasis>
496 # </entry>
497 # <entry>
498 #   <funcsynopsis>
499 #     <funcprototype>
500 #       <funcdef><function>failNotEquals</function></funcdef>
501 #       <paramdef>string <parameter>[message]</parameter></paramdef>
502 #       <paramdef>string <parameter>unexpected</parameter></paramdef>
503 #       <paramdef>string <parameter>actual</parameter></paramdef>
504 #     </funcprototype>
505 #   </funcsynopsis>
506 #   <para>Fails the test if <emphasis>unexpected</emphasis> and
507 #   <emphasis>actual</emphasis> are <emphasis role="strong">not</emphasis>
508 #   equal to one another. The message is optional.</para>
509 # </entry>
510 # </s:function>
511 #*/
512 failNotEquals()
513 {
514   ${_SHUNIT_LINENO_}
515   if [ $# -lt 2 -o $# -gt 3 ]; then
516     _shunit_error 'failNotEquals() requires one or two arguments'
517     return ${SHUNIT_ERROR}
518   fi
519   _shunit_shouldSkip && return ${SHUNIT_TRUE}
520
521   [ -z "${shunit_message_:-}" ] && shunit_message_=''
522   if [ $# -eq 3 ]; then
523     shunit_message_="${shunit_message_}$1"
524     shift
525   fi
526   shunit_unexpected_=$1
527   shunit_actual_=$2
528
529   _shunit_testFailed "${shunit_message_:+${shunit_message_} }expected:<${shunit_unexpected_}> but was:<${shunit_actual_}>"
530
531   unset shunit_message_ shunit_unexpected_ shunit_actual_
532   return ${SHUNIT_FALSE}
533 }
534 _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"'
535
536 #/**
537 # <s:function group="failures">
538 # <entry align="right">
539 #   <emphasis>void</emphasis>
540 # </entry>
541 # <entry>
542 #   <funcsynopsis>
543 #     <funcprototype>
544 #       <funcdef><function>failSame</function></funcdef>
545 #       <paramdef>string <parameter>[message]</parameter></paramdef>
546 #     </funcprototype>
547 #   </funcsynopsis>
548 #   <para>Indicate test failure because arguments were not the same. The
549 #   message is optional.</para>
550 # </entry>
551 # </s:function>
552 #*/
553 failSame()
554 {
555   ${_SHUNIT_LINENO_}
556   if [ $# -lt 2 -o $# -gt 3 ]; then
557     _shunit_error 'failSame() requires two or three arguments'
558     return ${SHUNIT_ERROR}
559   fi
560   _shunit_shouldSkip && return ${SHUNIT_TRUE}
561
562   [ -z "${shunit_message_:-}" ] && shunit_message_=''
563   if [ $# -eq 3 ]; then
564     shunit_message_="${shunit_message_}$1"
565     shift
566   fi
567
568   _shunit_testFailed "${shunit_message_:+${shunit_message_} }expected not same"
569
570   unset shunit_message_
571   return ${SHUNIT_FALSE}
572 }
573 _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"'
574
575 #/**
576 # <s:function group="failures">
577 # <entry align="right">
578 #   <emphasis>void</emphasis>
579 # </entry>
580 # <entry>
581 #   <funcsynopsis>
582 #     <funcprototype>
583 #       <funcdef><function>failNotSame</function></funcdef>
584 #       <paramdef>string <parameter>[message]</parameter></paramdef>
585 #       <paramdef>string <parameter>expected</parameter></paramdef>
586 #       <paramdef>string <parameter>actual</parameter></paramdef>
587 #     </funcprototype>
588 #   </funcsynopsis>
589 #   <para>Fails the test if <emphasis>expected</emphasis> and
590 #   <emphasis>actual</emphasis> are equal to one another. The message is
591 #   optional.</para>
592 # </entry>
593 # </s:function>
594 #*/
595 failNotSame()
596 {
597   ${_SHUNIT_LINENO_}
598   if [ $# -lt 2 -o $# -gt 3 ]; then
599     _shunit_error 'failNotEquals() requires one or two arguments'
600     return ${SHUNIT_ERROR}
601   fi
602   _shunit_shouldSkip && return ${SHUNIT_TRUE}
603
604   if [ $# -eq 2 ]; then
605     failNotEquals "$1" "$2"
606   else
607     failNotEquals "$1" "$2" "$3"
608   fi
609 }
610 _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"'
611
612 #-----------------------------------------------------------------------------
613 # skipping functions
614 #
615
616 #/**
617 # <s:function group="skipping">
618 # <entry align="right">
619 #   <emphasis>void</emphasis>
620 # </entry>
621 # <entry>
622 #   <funcsynopsis>
623 #     <funcprototype>
624 #       <funcdef><function>startSkipping</function></funcdef>
625 #       <paramdef />
626 #     </funcprototype>
627 #   </funcsynopsis>
628 #   <para>This function forces the remaining assert and fail functions to be
629 #   "skipped", i.e. they will have no effect. Each function skipped will be
630 #   recorded so that the total of asserts and fails will not be altered.</para>
631 # </entry>
632 # </s:function>
633 #*/
634 startSkipping()
635 {
636   __shunit_skip=${SHUNIT_TRUE}
637 }
638
639 #/**
640 # <s:function group="skipping">
641 # <entry align="right">
642 #   <emphasis>void</emphasis>
643 # </entry>
644 # <entry>
645 #   <funcsynopsis>
646 #     <funcprototype>
647 #       <funcdef><function>endSkipping</function></funcdef>
648 #       <paramdef />
649 #     </funcprototype>
650 #   </funcsynopsis>
651 #   <para>This function returns calls to the assert and fail functions to their
652 #   default behavior, i.e. they will be called.</para>
653 # </entry>
654 # </s:function>
655 #*/
656 endSkipping()
657 {
658   __shunit_skip=${SHUNIT_FALSE}
659 }
660
661 #/**
662 # <s:function group="skipping">
663 # <entry align="right">
664 #   <emphasis>boolean</emphasis>
665 # </entry>
666 # <entry>
667 #   <funcsynopsis>
668 #     <funcprototype>
669 #       <funcdef><function>isSkipping</function></funcdef>
670 #       <paramdef />
671 #     </funcprototype>
672 #   </funcsynopsis>
673 #   <para>This function returns the state of skipping.</para>
674 # </entry>
675 # </s:function>
676 #*/
677 isSkipping()
678 {
679   return ${__shunit_skip}
680 }
681
682 #-----------------------------------------------------------------------------
683 # suite functions
684 #
685
686 #/**
687 # <s:function group="suites">
688 # <entry align="right">
689 #   <emphasis>void</emphasis>
690 # </entry>
691 # <entry>
692 #   <funcsynopsis>
693 #     <funcprototype>
694 #       <funcdef><function>suite</function></funcdef>
695 #       <paramdef />
696 #     </funcprototype>
697 #   </funcsynopsis>
698 #   <para>This function can be optionally overridden by the user in their test
699 #   suite.</para>
700 #   <para>If this function exists, it will be called when
701 #   <command>shunit2</command> is sourced. If it does not exist, shUnit2 will
702 #   search the parent script for all functions beginning with the word
703 #   <literal>test</literal>, and they will be added dynamically to the test
704 #   suite.</para>
705 # </entry>
706 # </s:function>
707 #*/
708 # Note: see _shunit_mktempFunc() for actual implementation
709 # suite() { :; }
710
711 #/**
712 # <s:function group="suites">
713 # <entry align="right">
714 #   <emphasis>void</emphasis>
715 # </entry>
716 # <entry>
717 #   <funcsynopsis>
718 #     <funcprototype>
719 #       <funcdef><function>suite_addTest</function></funcdef>
720 #       <paramdef>string <parameter>function</parameter></paramdef>
721 #     </funcprototype>
722 #   </funcsynopsis>
723 #   <para>This function adds a function name to the list of tests scheduled for
724 #   execution as part of this test suite. This function should only be called
725 #   from within the <function>suite()</function> function.</para>
726 # </entry>
727 # </s:function>
728 #*/
729 suite_addTest()
730 {
731   _su_func=${1:-}
732
733   __shunit_suite="${__shunit_suite:+${__shunit_suite} }${_su_func}"
734
735   unset _su_func
736 }
737
738 #/**
739 # <s:function group="suites">
740 # <entry align="right">
741 #   <emphasis>void</emphasis>
742 # </entry>
743 # <entry>
744 #   <funcsynopsis>
745 #     <funcprototype>
746 #       <funcdef><function>oneTimeSetUp</function></funcdef>
747 #       <paramdef />
748 #     </funcprototype>
749 #   </funcsynopsis>
750 #   <para>This function can be be optionally overridden by the user in their
751 #   test suite.</para>
752 #   <para>If this function exists, it will be called once before any tests are
753 #   run. It is useful to prepare a common environment for all tests.</para>
754 # </entry>
755 # </s:function>
756 #*/
757 # Note: see _shunit_mktempFunc() for actual implementation
758 # oneTimeSetUp() { :; }
759
760 #/**
761 # <s:function group="suites">
762 # <entry align="right">
763 #   <emphasis>void</emphasis>
764 # </entry>
765 # <entry>
766 #   <funcsynopsis>
767 #     <funcprototype>
768 #       <funcdef><function>oneTimeTearDown</function></funcdef>
769 #       <paramdef />
770 #     </funcprototype>
771 #   </funcsynopsis>
772 #   <para>This function can be be optionally overridden by the user in their
773 #   test suite.</para>
774 #   <para>If this function exists, it will be called once after all tests are
775 #   completed. It is useful to clean up the environment after all tests.</para>
776 # </entry>
777 # </s:function>
778 #*/
779 # Note: see _shunit_mktempFunc() for actual implementation
780 # oneTimeTearDown() { :; }
781
782 #/**
783 # <s:function group="suites">
784 # <entry align="right">
785 #   <emphasis>void</emphasis>
786 # </entry>
787 # <entry>
788 #   <funcsynopsis>
789 #     <funcprototype>
790 #       <funcdef><function>setUp</function></funcdef>
791 #       <paramdef />
792 #     </funcprototype>
793 #   </funcsynopsis>
794 #   <para>This function can be be optionally overridden by the user in their
795 #   test suite.</para>
796 #   <para>If this function exists, it will be called before each test is run.
797 #   It is useful to reset the environment before each test.</para>
798 # </entry>
799 # </s:function>
800 #*/
801 # Note: see _shunit_mktempFunc() for actual implementation
802 # setUp() { :; }
803
804 #/**
805 # <s:function group="suites">
806 # <entry align="right">
807 #   <emphasis>void</emphasis>
808 # </entry>
809 # <entry>
810 #   <funcsynopsis>
811 #     <funcprototype>
812 #       <funcdef><function>tearDown</function></funcdef>
813 #       <paramdef />
814 #     </funcprototype>
815 #   </funcsynopsis>
816 #   <para>This function can be be optionally overridden by the user in their
817 #   test suite.</para>
818 #   <para>If this function exists, it will be called after each test completes.
819 #   It is useful to clean up the environment after each test.</para>
820 # </entry>
821 # </s:function>
822 #*/
823 # Note: see _shunit_mktempFunc() for actual implementation
824 # tearDown() { :; }
825
826 #------------------------------------------------------------------------------
827 # internal shUnit2 functions
828 #
829
830 _shunit_cleanup()
831 {
832   name=$1
833
834   case ${name} in
835     EXIT) signal=0 ;;
836     INT) signal=2 ;;
837     TERM) signal=15 ;;
838     *)
839       _shunit_warn "unrecognized trap value (${name})"
840       signal=0
841       ;;
842   esac
843
844   # do our work
845   rm -fr "${__shunit_tmpDir}"
846
847   # exit for all non-EXIT signals
848   if [ ${name} != 'EXIT' ]; then
849     _shunit_warn "trapped and now handling the (${name}) signal"
850     _shunit_generateReport
851     # disable EXIT trap
852     trap 0
853     # add 128 to signal and exit
854     exit `expr ${signal} + 128`
855   fi
856 }
857
858 _shunit_execSuite()
859 {
860   echo '#'
861   echo '# Performing tests'
862   echo '#'
863   for _su_func in ${__shunit_suite}; do
864     # disable skipping
865     endSkipping
866
867     # execute the per-test setup function
868     setUp
869
870     # execute the test
871     echo "${_su_func}"
872     eval ${_su_func}
873
874     # execute the per-test tear-down function
875     tearDown
876   done
877
878   unset _su_func
879 }
880
881 _shunit_generateReport()
882 {
883   _su__awkPercent='{printf("%4d %3.0f%%", $1, $1*100/$2)}'
884   if [ ${__shunit_testsTotal:-0} -gt 0 ]; then
885     _su__passed=`echo ${__shunit_testsPassed} ${__shunit_testsTotal} |\
886         awk "${_su__awkPercent}"`
887     _su__failed=`echo ${__shunit_testsFailed} ${__shunit_testsTotal} |\
888         awk "${_su__awkPercent}"`
889     _su__skipped=`echo ${__shunit_testsSkipped} ${__shunit_testsTotal} |\
890         awk "${_su__awkPercent}"`
891     _su__total=`echo ${__shunit_testsTotal} 100 |\
892         awk '{printf("%4d %3d%%", $1, $2)}'`
893   else
894     _su__passed=`echo 0 0 |awk '{printf("%4d %3d%%", $1, $2)}'`
895     _su__failed=${_su__passed}
896     _su__skipped=${_su__passed}
897     _su__total=${_su__passed}
898   fi
899
900   cat <<EOF
901
902 #
903 # Test report
904 #
905 tests passed:  ${_su__passed}
906 tests failed:  ${_su__failed}
907 tests skipped: ${_su__skipped}
908 tests total:   ${_su__total}
909 EOF
910
911   unset _su__awkPercent _su__passed _su__failed _su__skipped _su__total
912 }
913
914 # this function is a cross-platform temporary directory creation tool. not all
915 # OSes have the mktemp function, so one is included here.
916 _shunit_mktempDir()
917 {
918   # try the standard mktemp function
919   ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return
920
921   # the standard mktemp didn't work.  doing our own.
922   if [ -r '/dev/urandom' ]; then
923     _su__random=`od -vAn -N4 -tx4 </dev/urandom |sed 's/^[^0-9a-f]*//'`
924   elif [ -n "${RANDOM:-}" ]; then
925     # $RANDOM works
926     _su__random=${RANDOM}${RANDOM}${RANDOM}$$
927   else
928     # $RANDOM doesn't work
929     _su__date=`date '+%Y%m%d%H%M%S'`
930     _su__random=`expr ${_su__date} / $$`
931   fi
932
933   _su__tmpDir="${TMPDIR:-/tmp}/shunit.${_su__random}"
934   ( umask 077 && mkdir "${_su__tmpDir}" ) || {
935     echo 'shUnit:FATAL could not create temporary directory! exiting' >&2
936     exit 1
937   }
938
939   echo ${_su__tmpDir}
940   unset _su__date _su__random _su__tmpDir
941 }
942
943 # this function is here to work around issues in Cygwin
944 _shunit_mktempFunc()
945 {
946   for _su__func in oneTimeSetUp oneTimeTearDown setUp tearDown suite; do
947     _su__file="${__shunit_tmpDir}/${_su__func}"
948     cat <<EOF >"${_su__file}"
949 #! /bin/sh
950 exit 0
951 EOF
952     chmod +x "${_su__file}"
953   done
954
955   unset _su__file
956 }
957
958 _shunit_shouldSkip()
959 {
960   [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE}
961   _shunit_testSkipped
962 }
963
964 _shunit_testPassed()
965 {
966   __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1`
967   __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1`
968 }
969
970 _shunit_testFailed()
971 {
972   _su__msg=$1
973
974   __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1`
975   __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1`
976   echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_su__msg}" >&2
977
978   unset _su__msg
979 }
980
981 _shunit_testSkipped()
982 {
983   __shunit_testsSkipped=`expr ${__shunit_testsSkipped} + 1`
984   __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1`
985 }
986
987 #------------------------------------------------------------------------------
988 # main
989 #
990
991 # create a temporary storage location
992 __shunit_tmpDir=`_shunit_mktempDir`
993
994 # setup traps to clean up after ourselves
995 trap '_shunit_cleanup EXIT' 0
996 trap '_shunit_cleanup INT' 2
997 trap '_shunit_cleanup TERM' 15
998
999 # create phantom functions to work around issues with Cygwin
1000 _shunit_mktempFunc
1001 PATH="${__shunit_tmpDir}:${PATH}"
1002
1003 # execute the oneTimeSetUp function (if it exists)
1004 oneTimeSetUp
1005
1006 # execute the suite function defined in the parent test script
1007 # deprecated as of 2.1.0
1008 suite
1009
1010 # if no suite function was defined, dynamically build a list of functions
1011 if [ -z "${__shunit_suite}" ]; then
1012   shunit_funcs_=`grep "^[ \t]*test[A-Za-z0-9_]* *()" ${__SHUNIT_PARENT} \
1013       |sed 's/[^A-Za-z0-9_]//g'`
1014   for shunit_func_ in ${shunit_funcs_}; do
1015     suite_addTest ${shunit_func_}
1016   done
1017 fi
1018 unset shunit_func_ shunit_funcs_
1019
1020 # execute the tests
1021 _shunit_execSuite
1022
1023 # execute the oneTimeTearDown function (if it exists)
1024 oneTimeTearDown
1025
1026 # generate report
1027 _shunit_generateReport
1028
1029 # restore the previous set of shell flags
1030 for shunit_shellFlag_ in ${__SHUNIT_SHELL_FLAGS}; do
1031   echo ${shunit_shellFlags_} |grep ${shunit_shellFlag_} >/dev/null \
1032     || set +${shunit_shellFlag_}
1033 done
1034 unset shunit_shellFlag_ shunit_shellFlags_
1035
1036 [ ${__shunit_testsFailed} -eq 0 ] || exit 1
1037
1038 #/**
1039 # </s:shelldoc>
1040 #*/