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 #*/