libatf-sh.subr revision 1.1.1.4
1#
2# Automated Testing Framework (atf)
3#
4# Copyright (c) 2007, 2008, 2009, 2010, 2011 The NetBSD Foundation, Inc.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29
30set -e
31
32# ------------------------------------------------------------------------
33# GLOBAL VARIABLES
34# ------------------------------------------------------------------------
35
36# The list of all test cases defined by the test program.
37Defined_Test_Cases=
38
39# Values for the expect property.
40Expect=pass
41Expect_Reason=
42
43# A boolean variable that indicates whether we are parsing a test case's
44# head or not.
45Parsing_Head=false
46
47# The program name.
48Prog_Name=${0##*/}
49
50# The file to which the test case will print its result.
51Results_File=
52
53# The test program's source directory: i.e. where its auxiliary data files
54# and helper utilities can be found.  Can be overriden through the '-s' flag.
55Source_Dir="$(dirname ${0})"
56
57# Indicates the test case we are currently processing.
58Test_Case=
59
60# List of meta-data variables for the current test case.
61Test_Case_Vars=
62
63# The list of all test cases provided by the test program.
64# Subset of ${Defined_Test_Cases}.
65Test_Cases=
66Test_Cases_With_Cleanup=
67
68# ------------------------------------------------------------------------
69# PUBLIC INTERFACE
70# ------------------------------------------------------------------------
71
72#
73# atf_add_test_case tc-name
74#
75#   Adds the given test case to the list of test cases that form the test
76#   program.  The name provided here must be accompanied by two functions
77#   named after it: <tc-name>_head and <tc-name>_body, and optionally by
78#   a <tc-name>_cleanup function.
79#
80atf_add_test_case()
81{
82    _atf_is_tc_defined "${1}" || \
83        _atf_error 128 "Test case ${1} was not correctly defined by" \
84                       "this test program"
85    Test_Cases="${Test_Cases} ${1}"
86}
87
88#
89# atf_check cmd expcode expout experr
90#
91#   Executes atf-check with given arguments and automatically calls
92#   atf_fail in case of failure.
93#
94atf_check()
95{
96    ${Atf_Check} "${@}" || \
97        atf_fail "atf-check failed; see the output of the test for details"
98}
99
100#
101# atf_check_equal expr1 expr2
102#
103#   Checks that expr1's value matches expr2's and, if not, raises an
104#   error.  Ideally expr1 and expr2 should be provided quoted (not
105#   expanded) so that the error message is helpful; otherwise it will
106#   only show the values, not the expressions themselves.
107#
108atf_check_equal()
109{
110    eval _val1=\"${1}\"
111    eval _val2=\"${2}\"
112    test "${_val1}" = "${_val2}" || \
113        atf_fail "${1} != ${2} (${_val1} != ${_val2})"
114}
115
116#
117# atf_config_get varname [defvalue]
118#
119#   Prints the value of a configuration variable.  If it is not
120#   defined, prints the given default value.
121#
122atf_config_get()
123{
124    _varname="__tc_config_var_$(_atf_normalize ${1})"
125    if [ ${#} -eq 1 ]; then
126        eval _value=\"\${${_varname}-__unset__}\"
127        [ "${_value}" = __unset__ ] && \
128            _atf_error 1 "Could not find configuration variable \`${1}'"
129        echo ${_value}
130    elif [ ${#} -eq 2 ]; then
131        eval echo \${${_varname}-${2}}
132    else
133        _atf_error 1 "Incorrect number of parameters for atf_config_get"
134    fi
135}
136
137#
138# atf_config_has varname
139#
140#   Returns a boolean indicating if the given configuration variable is
141#   defined or not.
142#
143atf_config_has()
144{
145    _varname="__tc_config_var_$(_atf_normalize ${1})"
146    eval _value=\"\${${_varname}-__unset__}\"
147    [ "${_value}" != __unset__ ]
148}
149
150#
151# atf_expect_death reason
152#
153#   Sets the expectations to 'death'.
154#
155atf_expect_death()
156{
157    _atf_validate_expect
158
159    Expect=death
160    _atf_create_resfile expected_death -1 "${@}"
161}
162
163#
164# atf_expect_timeout reason
165#
166#   Sets the expectations to 'timeout'.
167#
168atf_expect_timeout()
169{
170    _atf_validate_expect
171
172    Expect=timeout
173    _atf_create_resfile expected_timeout -1 "${@}"
174}
175
176#
177# atf_expect_exit exitcode reason
178#
179#   Sets the expectations to 'exit'.
180#
181atf_expect_exit()
182{
183    _exitcode="${1}"; shift
184
185    _atf_validate_expect
186
187    Expect=exit
188    _atf_create_resfile expected_exit "${_exitcode}" "${@}"
189}
190
191#
192# atf_expect_fail reason
193#
194#   Sets the expectations to 'fail'.
195#
196atf_expect_fail()
197{
198    _atf_validate_expect
199
200    Expect=fail
201    Expect_Reason="${*}"
202}
203
204#
205# atf_expect_pass
206#
207#   Sets the expectations to 'pass'.
208#
209atf_expect_pass()
210{
211    _atf_validate_expect
212
213    Expect=pass
214    Expect_Reason=
215}
216
217#
218# atf_expect_signal signo reason
219#
220#   Sets the expectations to 'signal'.
221#
222atf_expect_signal()
223{
224    _signo="${1}"; shift
225
226    _atf_validate_expect
227
228    Expect=signal
229    _atf_create_resfile expected_signal "${_signo}" "${@}"
230}
231
232#
233# atf_expected_failure msg1 [.. msgN]
234#
235#   Makes the test case report an expected failure with the given error
236#   message.  Multiple words can be provided, which are concatenated with
237#   a single blank space.
238#
239atf_expected_failure()
240{
241    _atf_create_resfile expected_failure -1 "${Expect_Reason}:" "${@}"
242    exit 0
243}
244
245#
246# atf_fail msg1 [.. msgN]
247#
248#   Makes the test case fail with the given error message.  Multiple
249#   words can be provided, in which case they are joined by a single
250#   blank space.
251#
252atf_fail()
253{
254    case "${Expect}" in
255        fail)
256            atf_expected_failure "${@}"
257            ;;
258        pass)
259            _atf_create_resfile failed -1 "${@}"
260            exit 1
261            ;;
262        *)
263            _atf_error 128 "Unreachable"
264            ;;
265    esac
266}
267
268#
269# atf_get varname
270#
271#   Prints the value of a test case-specific variable.  Given that one
272#   should not get the value of non-existent variables, it is fine to
273#   always use this function as 'val=$(atf_get var)'.
274#
275atf_get()
276{
277    eval echo \${__tc_var_${Test_Case}_$(_atf_normalize ${1})}
278}
279
280#
281# atf_get_srcdir
282#
283#   Prints the value of the test case's source directory.
284#
285atf_get_srcdir()
286{
287    _atf_internal_get srcdir
288}
289
290#
291# atf_init_test_cases
292#
293#   The function in charge of registering the test cases that have to
294#   be made available to the user.  Must be redefined.
295#
296atf_init_test_cases()
297{
298    _atf_error 128 "No test cases defined"
299}
300
301#
302# atf_pass
303#
304#   Makes the test case pass.  Shouldn't be used in general, as a test
305#   case that does not explicitly fail is assumed to pass.
306#
307atf_pass()
308{
309    case "${Expect}" in
310        fail)
311            Expect=pass
312            atf_fail "Test case was expecting a failure but got a pass instead"
313            ;;
314        pass)
315            _atf_create_resfile passed -1
316            exit 0
317            ;;
318        *)
319            _atf_error 128 "Unreachable"
320            ;;
321    esac
322}
323
324#
325# atf_require_prog prog
326#
327#   Checks that the given program name (either provided as an absolute
328#   path or as a plain file name) can be found.  If it is not available,
329#   automatically skips the test case with an appropriate message.
330#
331#   Relative paths are not allowed because the test case cannot predict
332#   where it will be executed from.
333#
334atf_require_prog()
335{
336    _prog=
337    case ${1} in
338    /*)
339        _prog="${1}"
340        [ -x ${_prog} ] || \
341            atf_skip "The required program ${1} could not be found"
342        ;;
343    */*)
344        atf_fail "atf_require_prog does not accept relative path names \`${1}'"
345        ;;
346    *)
347        _prog=$(_atf_find_in_path "${1}")
348        [ -n "${_prog}" ] || \
349            atf_skip "The required program ${1} could not be found" \
350                     "in the PATH"
351        ;;
352    esac
353}
354
355#
356# atf_set varname val1 [.. valN]
357#
358#   Sets the test case's variable 'varname' to the specified values
359#   which are concatenated using a single blank space.  This function
360#   is supposed to be called form the test case's head only.
361#
362atf_set()
363{
364    ${Parsing_Head} || \
365        _atf_error 128 "atf_set called from the test case's body"
366
367    Test_Case_Vars="${Test_Case_Vars} ${1}"
368    _var=$(_atf_normalize ${1}); shift
369    eval __tc_var_${Test_Case}_${_var}=\"\${*}\"
370}
371
372#
373# atf_skip msg1 [.. msgN]
374#
375#   Skips the test case because of the reason provided.  Multiple words
376#   can be given, in which case they are joined by a single blank space.
377#
378atf_skip()
379{
380    _atf_create_resfile skipped -1 "${@}"
381    exit 0
382}
383
384#
385# atf_test_case tc-name cleanup
386#
387#   Defines a new test case named tc-name.  The name provided here must be
388#   accompanied by two functions named after it: <tc-name>_head and
389#   <tc-name>_body.  If cleanup is set to 'cleanup', then this also expects
390#   a <tc-name>_cleanup function to be defined.
391#
392atf_test_case()
393{
394    Defined_Test_Cases="${Defined_Test_Cases} ${1}"
395
396    eval "${1}_head() { :; }"
397    eval "${1}_body() { atf_fail 'Test case not implemented'; }"
398    if [ "${2}" = cleanup ]; then
399        Test_Cases_With_Cleanup="${Test_Cases_With_Cleanup} ${1}"
400        eval "${1}_cleanup() { :; }"
401    else
402        eval "${1}_cleanup() {
403            _atf_error 1 'Test case ${1} declared without a cleanup routine'; }"
404    fi
405}
406
407# ------------------------------------------------------------------------
408# PRIVATE INTERFACE
409# ------------------------------------------------------------------------
410
411#
412# _atf_config_set varname val1 [.. valN]
413#
414#   Sets the test case's private variable 'varname' to the specified
415#   values which are concatenated using a single blank space.
416#
417_atf_config_set()
418{
419    _var=$(_atf_normalize ${1}); shift
420    eval __tc_config_var_${_var}=\"\${*}\"
421    Config_Vars="${Config_Vars} __tc_config_var_${_var}"
422}
423
424#
425# _atf_config_set_str varname=val
426#
427#   Sets the test case's private variable 'varname' to the specified
428#   value.  The parameter is of the form 'varname=val'.
429#
430_atf_config_set_from_str()
431{
432    _oldifs=${IFS}
433    IFS='='
434    set -- ${*}
435    _var=${1}
436    shift
437    _val="${@}"
438    IFS=${_oldifs}
439    _atf_config_set "${_var}" "${_val}"
440}
441
442#
443# _atf_create_resfile result arg [reason ...]
444#
445#   Creates the results file.
446#
447_atf_create_resfile()
448{
449    _result="${1}"; shift
450    if [ "${1}" -eq -1 ]; then
451        _arg=""
452        shift
453    else
454        _arg="(${1})"
455        shift
456    fi
457    if [ ${#} -gt 0 ]; then
458        _reason=": ${*}"
459    else
460        _reason=""
461    fi
462
463    if [ -n "${Results_File}" ]; then
464        echo "${_result}${_arg}${_reason}" >"${Results_File}" || \
465            _atf_error 128 "Cannot create results file '${Results_File}'"
466    else
467        echo "${_result}${_arg}${_reason}"
468    fi
469}
470
471#
472# _atf_ensure_boolean var
473#
474#   Ensures that the test case defined the variable 'var' to a boolean
475#   value.
476#
477_atf_ensure_boolean()
478{
479    _atf_ensure_not_empty ${1}
480
481    case $(atf_get ${1}) in
482    [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee])
483        atf_set ${1} true
484        ;;
485    [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee])
486        atf_set ${1} false
487        ;;
488    *)
489        _atf_error 128 "Invalid value for boolean variable \`${1}'"
490        ;;
491    esac
492}
493
494#
495# _atf_ensure_not_empty var
496#
497#   Ensures that the test case defined the variable 'var' to a non-empty
498#   value.
499#
500_atf_ensure_not_empty()
501{
502    [ -n "$(atf_get ${1})" ] || \
503        _atf_error 128 "Undefined or empty variable \`${1}'"
504}
505
506#
507# _atf_error error_code [msg1 [.. msgN]]
508#
509#   Prints the given error message (which can be composed of multiple
510#   arguments, in which case are joined by a single space) and exits
511#   with the specified error code.
512#
513#   This must not be used by test programs themselves (hence making
514#   the function private) to indicate a test case's failure.  They
515#   have to use the atf_fail function.
516#
517_atf_error()
518{
519    _error_code="${1}"; shift
520
521    echo "${Prog_Name}: ERROR:" "$@" 1>&2
522    exit ${_error_code}
523}
524
525#
526# _atf_warning msg1 [.. msgN]
527#
528#   Prints the given warning message (which can be composed of multiple
529#   arguments, in which case are joined by a single space).
530#
531_atf_warning()
532{
533    echo "${Prog_Name}: WARNING:" "$@" 1>&2
534}
535
536#
537# _atf_find_in_path program
538#
539#   Looks for a program in the path and prints the full path to it or
540#   nothing if it could not be found.  It also returns true in case of
541#   success.
542#
543_atf_find_in_path()
544{
545    _prog="${1}"
546
547    _oldifs=${IFS}
548    IFS=:
549    for _dir in ${PATH}
550    do
551        if [ -x ${_dir}/${_prog} ]; then
552            IFS=${_oldifs}
553            echo ${_dir}/${_prog}
554            return 0
555        fi
556    done
557    IFS=${_oldifs}
558
559    return 1
560}
561
562#
563# _atf_has_tc name
564#
565#   Returns true if the given test case exists.
566#
567_atf_has_tc()
568{
569    for _tc in ${Test_Cases}; do
570        if [ ${_tc} = ${1} ]; then
571            return 0
572        fi
573    done
574    return 1
575}
576
577#
578# _atf_get_bool varname
579#
580#   Evaluates a test case-specific variable as a boolean and returns its
581#   value.
582#
583_atf_get_bool()
584{
585    eval $(atf_get ${1})
586}
587
588#
589# _atf_internal_get varname
590#
591#   Prints the value of a test case-specific internal variable.  Given
592#   that one should not get the value of non-existent variables, it is
593#   fine to always use this function as 'val=$(_atf_internal_get var)'.
594#
595_atf_internal_get()
596{
597    eval echo \${__tc_internal_var_${Test_Case}_${1}}
598}
599
600#
601# _atf_internal_set varname val1 [.. valN]
602#
603#   Sets the test case's private variable 'varname' to the specified
604#   values which are concatenated using a single blank space.
605#
606_atf_internal_set()
607{
608    _var=${1}; shift
609    eval __tc_internal_var_${Test_Case}_${_var}=\"\${*}\"
610}
611
612#
613# _atf_list_tcs
614#
615#   Describes all test cases and prints the list to the standard output.
616#
617_atf_list_tcs()
618{
619    echo 'Content-Type: application/X-atf-tp; version="1"'
620    echo
621
622    set -- ${Test_Cases}
623    while [ ${#} -gt 0 ]; do
624        _atf_parse_head ${1}
625
626        echo "ident: $(atf_get ident)"
627        for _var in ${Test_Case_Vars}; do
628            [ "${_var}" != "ident" ] && echo "${_var}: $(atf_get ${_var})"
629        done
630
631        [ ${#} -gt 1 ] && echo
632        shift
633    done
634}
635
636#
637# _atf_normalize str
638#
639#   Normalizes a string so that it is a valid shell variable name.
640#
641_atf_normalize()
642{
643    echo ${1} | tr .- __
644}
645
646#
647# _atf_parse_head tcname
648#
649#   Evaluates a test case's head to gather its variables and prepares the
650#   test program to run it.
651#
652_atf_parse_head()
653{
654    ${Parsing_Head} && _atf_error 128 "_atf_parse_head called recursively"
655    Parsing_Head=true
656
657    Test_Case="${1}"
658    Test_Case_Vars=
659
660    if _atf_has_cleanup "${1}"; then
661        atf_set has.cleanup "true"
662    fi
663
664    atf_set ident "${1}"
665    ${1}_head
666    _atf_ensure_not_empty ident
667    test $(atf_get ident) = "${1}" || \
668        _atf_error 128 "Test case redefined ident"
669
670    Parsing_Head=false
671}
672
673#
674# _atf_run_tc tc
675#
676#   Runs the specified test case.  Prints its exit status to the
677#   standard output and returns a boolean indicating if the test was
678#   successful or not.
679#
680_atf_run_tc()
681{
682    case ${1} in
683    *:*)
684        _tcname=${1%%:*}
685        _tcpart=${1#*:}
686
687        if [ "${_tcpart}" != body -a "${_tcpart}" != cleanup ]; then
688            _atf_syntax_error "Unknown test case part \`${_tcpart}'"
689        fi
690        ;;
691
692    *)
693        _tcname=${1}
694        _tcpart=body
695        ;;
696    esac
697
698    if _atf_has_tc ${_tcname}; then
699        if [ "${__RUNNING_INSIDE_ATF_RUN}" != "internal-yes-value" ]; then
700            _atf_warning "Running test cases without atf-run(1) is unsupported"
701            _atf_warning "No isolation nor timeout control is being applied;" \
702                "you may get unexpected failures; see atf-test-case(4)"
703        fi
704
705        _atf_parse_head ${_tcname}
706
707        _atf_internal_set srcdir "${Source_Dir}"
708
709        case ${_tcpart} in
710        body)
711            if ${_tcname}_body; then
712                _atf_validate_expect
713                _atf_create_resfile passed -1
714            else
715                Expect=pass
716                atf_fail "Test case body returned a non-ok exit code, but" \
717                    "this is not allowed"
718            fi
719            ;;
720        cleanup)
721            if _atf_has_cleanup "${_tcname}"; then
722                if ${_tcname}_cleanup; then
723                    :
724                else
725                    _atf_error 128 "The test case cleanup returned a non-ok" \
726                        "exit code, but this is not allowed"
727                fi
728            fi
729            ;;
730        *)
731            _atf_error 128 "Unknown test case part"
732            ;;
733        esac
734    else
735        _atf_syntax_error "Unknown test case \`${1}'"
736    fi
737}
738
739#
740# _atf_sighup_handler
741#
742#   Handler for the SIGHUP signal that registers its occurrence so that
743#   it can be processed at a later stage.
744#
745_atf_sighup_handler()
746{
747    Held_Signals="${Held_Signals} SIGHUP"
748}
749
750#
751# _atf_sigint_handler
752#
753#   Handler for the SIGINT signal that registers its occurrence so that
754#   it can be processed at a later stage.
755#
756_atf_sigint_handler()
757{
758    Held_Signals="${Held_Signals} SIGINT"
759}
760
761#
762# _atf_sigterm_handler
763#
764#   Handler for the SIGTERM signal that registers its occurrence so that
765#   it can be processed at a later stage.
766#
767_atf_sigterm_handler()
768{
769    Held_Signals="${Held_Signals} SIGTERM"
770}
771
772#
773# _atf_syntax_error msg1 [.. msgN]
774#
775#   Formats and prints a syntax error message and terminates the
776#   program prematurely.
777#
778_atf_syntax_error()
779{
780    echo "${Prog_Name}: ERROR: ${@}" 1>&2
781    echo "${Prog_Name}: See atf-test-program(1) for usage details." 1>&2
782    exit 1
783}
784
785#
786# _atf_is_tc_defined tc-name
787#
788#   Returns a boolean indicating if the given test case was defined by the
789#   test program or not.
790#
791_atf_is_tc_defined()
792{
793    for _tc in ${Defined_Test_Cases}; do
794        [ ${_tc} = ${1} ] && return 0
795    done
796    return 1
797}
798
799#
800# _atf_has_cleanup tc-name
801#
802#   Returns a boolean indicating if the given test case has a cleanup
803#   routine or not.
804#
805_atf_has_cleanup()
806{
807    for _tc in ${Test_Cases_With_Cleanup}; do
808        [ ${_tc} = ${1} ] && return 0
809    done
810    return 1
811}
812
813#
814# _atf_validate_expect
815#
816#   Ensures that the current test case state is correct regarding the expect
817#   status.
818#
819_atf_validate_expect()
820{
821    case "${Expect}" in
822        death)
823            Expect=pass
824            atf_fail "Test case was expected to terminate abruptly but it" \
825                "continued execution"
826            ;;
827        exit)
828            Expect=pass
829            atf_fail "Test case was expected to exit cleanly but it continued" \
830                "execution"
831            ;;
832        fail)
833            Expect=pass
834            atf_fail "Test case was expecting a failure but none were raised"
835            ;;
836        pass)
837            ;;
838        signal)
839            Expect=pass
840            atf_fail "Test case was expected to receive a termination signal" \
841                "but it continued execution"
842            ;;
843        timeout)
844            Expect=pass
845            atf_fail "Test case was expected to hang but it continued execution"
846            ;;
847        *)
848            _atf_error 128 "Unreachable"
849            ;;
850    esac
851}
852
853#
854# _atf_warning [msg1 [.. msgN]]
855#
856#   Prints the given warning message (which can be composed of multiple
857#   arguments, in which case are joined by a single space).
858#
859#   This must not be used by test programs themselves (hence making
860#   the function private).
861#
862_atf_warning()
863{
864    echo "${Prog_Name}: WARNING:" "$@" 1>&2
865}
866
867#
868# main [options] test_case
869#
870#   Test program's entry point.
871#
872main()
873{
874    # Process command-line options first.
875    _numargs=${#}
876    _lflag=false
877    while getopts :lr:s:v: arg; do
878        case ${arg} in
879        l)
880            _lflag=true
881            ;;
882
883        r)
884            Results_File=${OPTARG}
885            ;;
886
887        s)
888            Source_Dir=${OPTARG}
889            ;;
890
891        v)
892            _atf_config_set_from_str "${OPTARG}"
893            ;;
894
895        \?)
896            _atf_syntax_error "Unknown option -${OPTARG}."
897            # NOTREACHED
898            ;;
899        esac
900    done
901    shift `expr ${OPTIND} - 1`
902
903    # First of all, make sure that the source directory is correct.  It
904    # doesn't matter if the user did not change it, because the default
905    # value may not work.  (TODO: It possibly should, even though it is
906    # not a big deal because atf-run deals with this.)
907    case ${Source_Dir} in
908        /*)
909            ;;
910        *)
911            Source_Dir=$(pwd)/${Source_Dir}
912            ;;
913    esac
914    [ -f ${Source_Dir}/${Prog_Name} ] || \
915        _atf_error 1 "Cannot find the test program in the source" \
916                     "directory \`${Source_Dir}'"
917
918    # Set some global variables useful to the user.  Not specific to the
919    # test case because they may be needed during initialization too.
920    # XXX I'm not too fond on this though.  Sure, it is very useful in some
921    # situations -- such as in NetBSD's fs/tmpfs/* tests where each test
922    # program includes a helper subroutines file -- but there are also
923    # other, maybe better ways to achieve the same.  Because, for example,
924    # at the moment it is not possible to detect failures in the inclusion
925    # and report them nicely.  Plus this change is difficult to implement
926    # in the current C++ API.
927    _atf_internal_set srcdir "${Source_Dir}"
928
929    # Call the test program's hook to register all available test cases.
930    atf_init_test_cases
931
932    # Run or list test cases.
933    if `${_lflag}`; then
934        if [ ${#} -gt 0 ]; then
935            _atf_syntax_error "Cannot provide test case names with -l"
936        fi
937        _atf_list_tcs
938    else
939        if [ ${#} -eq 0 ]; then
940            _atf_syntax_error "Must provide a test case name"
941        elif [ ${#} -gt 1 ]; then
942            _atf_syntax_error "Cannot provide more than one test case name"
943        else
944            _atf_run_tc "${1}"
945        fi
946    fi
947}
948
949# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
950