1240116Smarcel# Copyright (c) 2007 The NetBSD Foundation, Inc.
2240116Smarcel# All rights reserved.
3240116Smarcel#
4240116Smarcel# Redistribution and use in source and binary forms, with or without
5240116Smarcel# modification, are permitted provided that the following conditions
6240116Smarcel# are met:
7240116Smarcel# 1. Redistributions of source code must retain the above copyright
8240116Smarcel#    notice, this list of conditions and the following disclaimer.
9240116Smarcel# 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel#    notice, this list of conditions and the following disclaimer in the
11240116Smarcel#    documentation and/or other materials provided with the distribution.
12240116Smarcel#
13240116Smarcel# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24240116Smarcel# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25240116Smarcel
26240116Smarcel# ------------------------------------------------------------------------
27240116Smarcel# GLOBAL VARIABLES
28240116Smarcel# ------------------------------------------------------------------------
29240116Smarcel
30240116Smarcel# Values for the expect property.
31240116SmarcelExpect=pass
32240116SmarcelExpect_Reason=
33240116Smarcel
34240116Smarcel# A boolean variable that indicates whether we are parsing a test case's
35240116Smarcel# head or not.
36240116SmarcelParsing_Head=false
37240116Smarcel
38240116Smarcel# The program name.
39240116SmarcelProg_Name=${0##*/}
40240116Smarcel
41240116Smarcel# The file to which the test case will print its result.
42240116SmarcelResults_File=
43240116Smarcel
44240116Smarcel# The test program's source directory: i.e. where its auxiliary data files
45240116Smarcel# and helper utilities can be found.  Can be overriden through the '-s' flag.
46240116SmarcelSource_Dir="$(dirname ${0})"
47240116Smarcel
48240116Smarcel# Indicates the test case we are currently processing.
49240116SmarcelTest_Case=
50240116Smarcel
51240116Smarcel# List of meta-data variables for the current test case.
52240116SmarcelTest_Case_Vars=
53240116Smarcel
54240116Smarcel# The list of all test cases provided by the test program.
55240116SmarcelTest_Cases=
56240116Smarcel
57240116Smarcel# ------------------------------------------------------------------------
58240116Smarcel# PUBLIC INTERFACE
59240116Smarcel# ------------------------------------------------------------------------
60240116Smarcel
61240116Smarcel#
62240116Smarcel# atf_add_test_case tc-name
63240116Smarcel#
64240116Smarcel#   Adds the given test case to the list of test cases that form the test
65240116Smarcel#   program.  The name provided here must be accompanied by two functions
66240116Smarcel#   named after it: <tc-name>_head and <tc-name>_body, and optionally by
67240116Smarcel#   a <tc-name>_cleanup function.
68240116Smarcel#
69240116Smarcelatf_add_test_case()
70240116Smarcel{
71240116Smarcel    Test_Cases="${Test_Cases} ${1}"
72240116Smarcel}
73240116Smarcel
74240116Smarcel#
75240116Smarcel# atf_check cmd expcode expout experr
76240116Smarcel#
77240116Smarcel#   Executes atf-check with given arguments and automatically calls
78240116Smarcel#   atf_fail in case of failure.
79240116Smarcel#
80240116Smarcelatf_check()
81240116Smarcel{
82240116Smarcel    ${Atf_Check} "${@}" || \
83240116Smarcel        atf_fail "atf-check failed; see the output of the test for details"
84240116Smarcel}
85240116Smarcel
86240116Smarcel#
87275988Sngie# atf_check_equal expected_expression actual_expression
88240116Smarcel#
89275988Sngie#   Checks that expected_expression's value matches actual_expression's
90275988Sngie#   and, if not, raises an error.  Ideally expected_expression and
91275988Sngie#   actual_expression should be provided quoted (not expanded) so that
92275988Sngie#   the error message is helpful; otherwise it will only show the values,
93275988Sngie#   not the expressions themselves.
94240116Smarcel#
95240116Smarcelatf_check_equal()
96240116Smarcel{
97240116Smarcel    eval _val1=\"${1}\"
98240116Smarcel    eval _val2=\"${2}\"
99240116Smarcel    test "${_val1}" = "${_val2}" || \
100240116Smarcel        atf_fail "${1} != ${2} (${_val1} != ${_val2})"
101240116Smarcel}
102240116Smarcel
103240116Smarcel#
104240116Smarcel# atf_config_get varname [defvalue]
105240116Smarcel#
106240116Smarcel#   Prints the value of a configuration variable.  If it is not
107240116Smarcel#   defined, prints the given default value.
108240116Smarcel#
109240116Smarcelatf_config_get()
110240116Smarcel{
111240116Smarcel    _varname="__tc_config_var_$(_atf_normalize ${1})"
112240116Smarcel    if [ ${#} -eq 1 ]; then
113240116Smarcel        eval _value=\"\${${_varname}-__unset__}\"
114240116Smarcel        [ "${_value}" = __unset__ ] && \
115240116Smarcel            _atf_error 1 "Could not find configuration variable \`${1}'"
116240116Smarcel        echo ${_value}
117240116Smarcel    elif [ ${#} -eq 2 ]; then
118240116Smarcel        eval echo \${${_varname}-${2}}
119240116Smarcel    else
120240116Smarcel        _atf_error 1 "Incorrect number of parameters for atf_config_get"
121240116Smarcel    fi
122240116Smarcel}
123240116Smarcel
124240116Smarcel#
125240116Smarcel# atf_config_has varname
126240116Smarcel#
127240116Smarcel#   Returns a boolean indicating if the given configuration variable is
128240116Smarcel#   defined or not.
129240116Smarcel#
130240116Smarcelatf_config_has()
131240116Smarcel{
132240116Smarcel    _varname="__tc_config_var_$(_atf_normalize ${1})"
133240116Smarcel    eval _value=\"\${${_varname}-__unset__}\"
134240116Smarcel    [ "${_value}" != __unset__ ]
135240116Smarcel}
136240116Smarcel
137240116Smarcel#
138240116Smarcel# atf_expect_death reason
139240116Smarcel#
140240116Smarcel#   Sets the expectations to 'death'.
141240116Smarcel#
142240116Smarcelatf_expect_death()
143240116Smarcel{
144240116Smarcel    _atf_validate_expect
145240116Smarcel
146240116Smarcel    Expect=death
147240116Smarcel    _atf_create_resfile "expected_death: ${*}"
148240116Smarcel}
149240116Smarcel
150240116Smarcel#
151240116Smarcel# atf_expect_timeout reason
152240116Smarcel#
153240116Smarcel#   Sets the expectations to 'timeout'.
154240116Smarcel#
155240116Smarcelatf_expect_timeout()
156240116Smarcel{
157240116Smarcel    _atf_validate_expect
158240116Smarcel
159240116Smarcel    Expect=timeout
160240116Smarcel    _atf_create_resfile "expected_timeout: ${*}"
161240116Smarcel}
162240116Smarcel
163240116Smarcel#
164240116Smarcel# atf_expect_exit exitcode reason
165240116Smarcel#
166240116Smarcel#   Sets the expectations to 'exit'.
167240116Smarcel#
168240116Smarcelatf_expect_exit()
169240116Smarcel{
170240116Smarcel    _exitcode="${1}"; shift
171240116Smarcel
172240116Smarcel    _atf_validate_expect
173240116Smarcel
174240116Smarcel    Expect=exit
175240116Smarcel    if [ "${_exitcode}" = "-1" ]; then
176240116Smarcel        _atf_create_resfile "expected_exit: ${*}"
177240116Smarcel    else
178240116Smarcel        _atf_create_resfile "expected_exit(${_exitcode}): ${*}"
179240116Smarcel    fi
180240116Smarcel}
181240116Smarcel
182240116Smarcel#
183240116Smarcel# atf_expect_fail reason
184240116Smarcel#
185240116Smarcel#   Sets the expectations to 'fail'.
186240116Smarcel#
187240116Smarcelatf_expect_fail()
188240116Smarcel{
189240116Smarcel    _atf_validate_expect
190240116Smarcel
191240116Smarcel    Expect=fail
192240116Smarcel    Expect_Reason="${*}"
193240116Smarcel}
194240116Smarcel
195240116Smarcel#
196240116Smarcel# atf_expect_pass
197240116Smarcel#
198240116Smarcel#   Sets the expectations to 'pass'.
199240116Smarcel#
200240116Smarcelatf_expect_pass()
201240116Smarcel{
202240116Smarcel    _atf_validate_expect
203240116Smarcel
204240116Smarcel    Expect=pass
205240116Smarcel    Expect_Reason=
206240116Smarcel}
207240116Smarcel
208240116Smarcel#
209240116Smarcel# atf_expect_signal signo reason
210240116Smarcel#
211240116Smarcel#   Sets the expectations to 'signal'.
212240116Smarcel#
213240116Smarcelatf_expect_signal()
214240116Smarcel{
215240116Smarcel    _signo="${1}"; shift
216240116Smarcel
217240116Smarcel    _atf_validate_expect
218240116Smarcel
219240116Smarcel    Expect=signal
220240116Smarcel    if [ "${_signo}" = "-1" ]; then
221240116Smarcel        _atf_create_resfile "expected_signal: ${*}"
222240116Smarcel    else
223240116Smarcel        _atf_create_resfile "expected_signal(${_signo}): ${*}"
224240116Smarcel    fi
225240116Smarcel}
226240116Smarcel
227240116Smarcel#
228240116Smarcel# atf_expected_failure msg1 [.. msgN]
229240116Smarcel#
230240116Smarcel#   Makes the test case report an expected failure with the given error
231240116Smarcel#   message.  Multiple words can be provided, which are concatenated with
232240116Smarcel#   a single blank space.
233240116Smarcel#
234240116Smarcelatf_expected_failure()
235240116Smarcel{
236240116Smarcel    _atf_create_resfile "expected_failure: ${Expect_Reason}: ${*}"
237240116Smarcel    exit 0
238240116Smarcel}
239240116Smarcel
240240116Smarcel#
241240116Smarcel# atf_fail msg1 [.. msgN]
242240116Smarcel#
243240116Smarcel#   Makes the test case fail with the given error message.  Multiple
244240116Smarcel#   words can be provided, in which case they are joined by a single
245240116Smarcel#   blank space.
246240116Smarcel#
247240116Smarcelatf_fail()
248240116Smarcel{
249240116Smarcel    case "${Expect}" in
250240116Smarcel        fail)
251240116Smarcel            atf_expected_failure "${@}"
252240116Smarcel            ;;
253240116Smarcel        pass)
254240116Smarcel            _atf_create_resfile "failed: ${*}"
255240116Smarcel            exit 1
256240116Smarcel            ;;
257240116Smarcel        *)
258240116Smarcel            _atf_error 128 "Unreachable"
259240116Smarcel            ;;
260240116Smarcel    esac
261240116Smarcel}
262240116Smarcel
263240116Smarcel#
264240116Smarcel# atf_get varname
265240116Smarcel#
266240116Smarcel#   Prints the value of a test case-specific variable.  Given that one
267240116Smarcel#   should not get the value of non-existent variables, it is fine to
268240116Smarcel#   always use this function as 'val=$(atf_get var)'.
269240116Smarcel#
270240116Smarcelatf_get()
271240116Smarcel{
272240116Smarcel    eval echo \${__tc_var_${Test_Case}_$(_atf_normalize ${1})}
273240116Smarcel}
274240116Smarcel
275240116Smarcel#
276240116Smarcel# atf_get_srcdir
277240116Smarcel#
278240116Smarcel#   Prints the value of the test case's source directory.
279240116Smarcel#
280240116Smarcelatf_get_srcdir()
281240116Smarcel{
282240116Smarcel    echo ${Source_Dir}
283240116Smarcel}
284240116Smarcel
285240116Smarcel#
286240116Smarcel# atf_pass
287240116Smarcel#
288240116Smarcel#   Makes the test case pass.  Shouldn't be used in general, as a test
289240116Smarcel#   case that does not explicitly fail is assumed to pass.
290240116Smarcel#
291240116Smarcelatf_pass()
292240116Smarcel{
293240116Smarcel    case "${Expect}" in
294240116Smarcel        fail)
295240116Smarcel            Expect=pass
296240116Smarcel            atf_fail "Test case was expecting a failure but got a pass instead"
297240116Smarcel            ;;
298240116Smarcel        pass)
299240116Smarcel            _atf_create_resfile passed
300240116Smarcel            exit 0
301240116Smarcel            ;;
302240116Smarcel        *)
303240116Smarcel            _atf_error 128 "Unreachable"
304240116Smarcel            ;;
305240116Smarcel    esac
306240116Smarcel}
307240116Smarcel
308240116Smarcel#
309240116Smarcel# atf_require_prog prog
310240116Smarcel#
311240116Smarcel#   Checks that the given program name (either provided as an absolute
312240116Smarcel#   path or as a plain file name) can be found.  If it is not available,
313240116Smarcel#   automatically skips the test case with an appropriate message.
314240116Smarcel#
315240116Smarcel#   Relative paths are not allowed because the test case cannot predict
316240116Smarcel#   where it will be executed from.
317240116Smarcel#
318240116Smarcelatf_require_prog()
319240116Smarcel{
320240116Smarcel    _prog=
321240116Smarcel    case ${1} in
322240116Smarcel    /*)
323240116Smarcel        _prog="${1}"
324240116Smarcel        [ -x ${_prog} ] || \
325240116Smarcel            atf_skip "The required program ${1} could not be found"
326240116Smarcel        ;;
327240116Smarcel    */*)
328240116Smarcel        atf_fail "atf_require_prog does not accept relative path names \`${1}'"
329240116Smarcel        ;;
330240116Smarcel    *)
331240116Smarcel        _prog=$(_atf_find_in_path "${1}")
332240116Smarcel        [ -n "${_prog}" ] || \
333240116Smarcel            atf_skip "The required program ${1} could not be found" \
334240116Smarcel                     "in the PATH"
335240116Smarcel        ;;
336240116Smarcel    esac
337240116Smarcel}
338240116Smarcel
339240116Smarcel#
340240116Smarcel# atf_set varname val1 [.. valN]
341240116Smarcel#
342240116Smarcel#   Sets the test case's variable 'varname' to the specified values
343240116Smarcel#   which are concatenated using a single blank space.  This function
344240116Smarcel#   is supposed to be called form the test case's head only.
345240116Smarcel#
346240116Smarcelatf_set()
347240116Smarcel{
348240116Smarcel    ${Parsing_Head} || \
349240116Smarcel        _atf_error 128 "atf_set called from the test case's body"
350240116Smarcel
351240116Smarcel    Test_Case_Vars="${Test_Case_Vars} ${1}"
352240116Smarcel    _var=$(_atf_normalize ${1}); shift
353240116Smarcel    eval __tc_var_${Test_Case}_${_var}=\"\${*}\"
354240116Smarcel}
355240116Smarcel
356240116Smarcel#
357240116Smarcel# atf_skip msg1 [.. msgN]
358240116Smarcel#
359240116Smarcel#   Skips the test case because of the reason provided.  Multiple words
360240116Smarcel#   can be given, in which case they are joined by a single blank space.
361240116Smarcel#
362240116Smarcelatf_skip()
363240116Smarcel{
364240116Smarcel    _atf_create_resfile "skipped: ${*}"
365240116Smarcel    exit 0
366240116Smarcel}
367240116Smarcel
368240116Smarcel#
369240116Smarcel# atf_test_case tc-name cleanup
370240116Smarcel#
371240116Smarcel#   Defines a new test case named tc-name.  The name provided here must be
372240116Smarcel#   accompanied by two functions named after it: <tc-name>_head and
373240116Smarcel#   <tc-name>_body.  If cleanup is set to 'cleanup', then this also expects
374240116Smarcel#   a <tc-name>_cleanup function to be defined.
375240116Smarcel#
376240116Smarcelatf_test_case()
377240116Smarcel{
378240116Smarcel    eval "${1}_head() { :; }"
379240116Smarcel    eval "${1}_body() { atf_fail 'Test case not implemented'; }"
380240116Smarcel    if [ "${2}" = cleanup ]; then
381240116Smarcel        eval __has_cleanup_${1}=true
382240116Smarcel        eval "${1}_cleanup() { :; }"
383240116Smarcel    else
384240116Smarcel        eval "${1}_cleanup() {
385240116Smarcel            _atf_error 1 'Test case ${1} declared without a cleanup routine'; }"
386240116Smarcel    fi
387240116Smarcel}
388240116Smarcel
389240116Smarcel# ------------------------------------------------------------------------
390240116Smarcel# PRIVATE INTERFACE
391240116Smarcel# ------------------------------------------------------------------------
392240116Smarcel
393240116Smarcel#
394240116Smarcel# _atf_config_set varname val1 [.. valN]
395240116Smarcel#
396240116Smarcel#   Sets the test case's private variable 'varname' to the specified
397240116Smarcel#   values which are concatenated using a single blank space.
398240116Smarcel#
399240116Smarcel_atf_config_set()
400240116Smarcel{
401240116Smarcel    _var=$(_atf_normalize ${1}); shift
402240116Smarcel    eval __tc_config_var_${_var}=\"\${*}\"
403240116Smarcel    Config_Vars="${Config_Vars} __tc_config_var_${_var}"
404240116Smarcel}
405240116Smarcel
406240116Smarcel#
407240116Smarcel# _atf_config_set_str varname=val
408240116Smarcel#
409240116Smarcel#   Sets the test case's private variable 'varname' to the specified
410240116Smarcel#   value.  The parameter is of the form 'varname=val'.
411240116Smarcel#
412240116Smarcel_atf_config_set_from_str()
413240116Smarcel{
414240116Smarcel    _oldifs=${IFS}
415240116Smarcel    IFS='='
416240116Smarcel    set -- ${*}
417240116Smarcel    _var=${1}
418240116Smarcel    shift
419240116Smarcel    _val="${@}"
420240116Smarcel    IFS=${_oldifs}
421240116Smarcel    _atf_config_set "${_var}" "${_val}"
422240116Smarcel}
423240116Smarcel
424240116Smarcel#
425240116Smarcel# _atf_create_resfile contents
426240116Smarcel#
427240116Smarcel#   Creates the results file.
428240116Smarcel#
429240116Smarcel_atf_create_resfile()
430240116Smarcel{
431240116Smarcel    if [ -n "${Results_File}" ]; then
432240116Smarcel        echo "${*}" >"${Results_File}" || \
433240116Smarcel            _atf_error 128 "Cannot create results file '${Results_File}'"
434240116Smarcel    else
435240116Smarcel        echo "${*}"
436240116Smarcel    fi
437240116Smarcel}
438240116Smarcel
439240116Smarcel#
440240116Smarcel# _atf_error error_code [msg1 [.. msgN]]
441240116Smarcel#
442240116Smarcel#   Prints the given error message (which can be composed of multiple
443240116Smarcel#   arguments, in which case are joined by a single space) and exits
444240116Smarcel#   with the specified error code.
445240116Smarcel#
446240116Smarcel#   This must not be used by test programs themselves (hence making
447240116Smarcel#   the function private) to indicate a test case's failure.  They
448240116Smarcel#   have to use the atf_fail function.
449240116Smarcel#
450240116Smarcel_atf_error()
451240116Smarcel{
452240116Smarcel    _error_code="${1}"; shift
453240116Smarcel
454240116Smarcel    echo "${Prog_Name}: ERROR:" "$@" 1>&2
455240116Smarcel    exit ${_error_code}
456240116Smarcel}
457240116Smarcel
458240116Smarcel#
459240116Smarcel# _atf_warning msg1 [.. msgN]
460240116Smarcel#
461240116Smarcel#   Prints the given warning message (which can be composed of multiple
462240116Smarcel#   arguments, in which case are joined by a single space).
463240116Smarcel#
464240116Smarcel_atf_warning()
465240116Smarcel{
466240116Smarcel    echo "${Prog_Name}: WARNING:" "$@" 1>&2
467240116Smarcel}
468240116Smarcel
469240116Smarcel#
470240116Smarcel# _atf_find_in_path program
471240116Smarcel#
472240116Smarcel#   Looks for a program in the path and prints the full path to it or
473240116Smarcel#   nothing if it could not be found.  It also returns true in case of
474240116Smarcel#   success.
475240116Smarcel#
476240116Smarcel_atf_find_in_path()
477240116Smarcel{
478240116Smarcel    _prog="${1}"
479240116Smarcel
480240116Smarcel    _oldifs=${IFS}
481240116Smarcel    IFS=:
482240116Smarcel    for _dir in ${PATH}
483240116Smarcel    do
484240116Smarcel        if [ -x ${_dir}/${_prog} ]; then
485240116Smarcel            IFS=${_oldifs}
486240116Smarcel            echo ${_dir}/${_prog}
487240116Smarcel            return 0
488240116Smarcel        fi
489240116Smarcel    done
490240116Smarcel    IFS=${_oldifs}
491240116Smarcel
492240116Smarcel    return 1
493240116Smarcel}
494240116Smarcel
495240116Smarcel#
496240116Smarcel# _atf_has_tc name
497240116Smarcel#
498240116Smarcel#   Returns true if the given test case exists.
499240116Smarcel#
500240116Smarcel_atf_has_tc()
501240116Smarcel{
502240116Smarcel    for _tc in ${Test_Cases}; do
503240116Smarcel        [ "${_tc}" != "${1}" ] || return 0
504240116Smarcel    done
505240116Smarcel    return 1
506240116Smarcel}
507240116Smarcel
508240116Smarcel#
509240116Smarcel# _atf_list_tcs
510240116Smarcel#
511240116Smarcel#   Describes all test cases and prints the list to the standard output.
512240116Smarcel#
513240116Smarcel_atf_list_tcs()
514240116Smarcel{
515240116Smarcel    echo 'Content-Type: application/X-atf-tp; version="1"'
516240116Smarcel    echo
517240116Smarcel
518240116Smarcel    set -- ${Test_Cases}
519240116Smarcel    while [ ${#} -gt 0 ]; do
520240116Smarcel        _atf_parse_head ${1}
521240116Smarcel
522240116Smarcel        echo "ident: $(atf_get ident)"
523240116Smarcel        for _var in ${Test_Case_Vars}; do
524240116Smarcel            [ "${_var}" != "ident" ] && echo "${_var}: $(atf_get ${_var})"
525240116Smarcel        done
526240116Smarcel
527240116Smarcel        [ ${#} -gt 1 ] && echo
528240116Smarcel        shift
529240116Smarcel    done
530240116Smarcel}
531240116Smarcel
532240116Smarcel#
533240116Smarcel# _atf_normalize str
534240116Smarcel#
535240116Smarcel#   Normalizes a string so that it is a valid shell variable name.
536240116Smarcel#
537240116Smarcel_atf_normalize()
538240116Smarcel{
539240116Smarcel    echo ${1} | tr .- __
540240116Smarcel}
541240116Smarcel
542240116Smarcel#
543240116Smarcel# _atf_parse_head tcname
544240116Smarcel#
545240116Smarcel#   Evaluates a test case's head to gather its variables and prepares the
546240116Smarcel#   test program to run it.
547240116Smarcel#
548240116Smarcel_atf_parse_head()
549240116Smarcel{
550240116Smarcel    Parsing_Head=true
551240116Smarcel
552240116Smarcel    Test_Case="${1}"
553240116Smarcel    Test_Case_Vars=
554240116Smarcel
555240116Smarcel    if _atf_has_cleanup "${1}"; then
556240116Smarcel        atf_set has.cleanup "true"
557240116Smarcel    fi
558240116Smarcel
559240116Smarcel    ${1}_head
560240116Smarcel    atf_set ident "${1}"
561240116Smarcel
562240116Smarcel    Parsing_Head=false
563240116Smarcel}
564240116Smarcel
565240116Smarcel#
566240116Smarcel# _atf_run_tc tc
567240116Smarcel#
568240116Smarcel#   Runs the specified test case.  Prints its exit status to the
569240116Smarcel#   standard output and returns a boolean indicating if the test was
570240116Smarcel#   successful or not.
571240116Smarcel#
572240116Smarcel_atf_run_tc()
573240116Smarcel{
574240116Smarcel    case ${1} in
575240116Smarcel    *:*)
576240116Smarcel        _tcname=${1%%:*}
577240116Smarcel        _tcpart=${1#*:}
578240116Smarcel
579240116Smarcel        if [ "${_tcpart}" != body -a "${_tcpart}" != cleanup ]; then
580240116Smarcel            _atf_syntax_error "Unknown test case part \`${_tcpart}'"
581240116Smarcel        fi
582240116Smarcel        ;;
583240116Smarcel
584240116Smarcel    *)
585240116Smarcel        _tcname=${1}
586240116Smarcel        _tcpart=body
587240116Smarcel        ;;
588240116Smarcel    esac
589240116Smarcel
590240116Smarcel    _atf_has_tc "${_tcname}" || _atf_syntax_error "Unknown test case \`${1}'"
591240116Smarcel
592240116Smarcel    if [ "${__RUNNING_INSIDE_ATF_RUN}" != "internal-yes-value" ]; then
593275988Sngie        _atf_warning "Running test cases outside of kyua(1) is unsupported"
594240116Smarcel        _atf_warning "No isolation nor timeout control is being applied;" \
595240116Smarcel            "you may get unexpected failures; see atf-test-case(4)"
596240116Smarcel    fi
597240116Smarcel
598240116Smarcel    _atf_parse_head ${_tcname}
599240116Smarcel
600240116Smarcel    case ${_tcpart} in
601240116Smarcel    body)
602240116Smarcel        if ${_tcname}_body; then
603240116Smarcel            _atf_validate_expect
604240116Smarcel            _atf_create_resfile passed
605240116Smarcel        else
606240116Smarcel            Expect=pass
607240116Smarcel            atf_fail "Test case body returned a non-ok exit code, but" \
608240116Smarcel                "this is not allowed"
609240116Smarcel        fi
610240116Smarcel        ;;
611240116Smarcel    cleanup)
612240116Smarcel        if _atf_has_cleanup "${_tcname}"; then
613240116Smarcel            ${_tcname}_cleanup || _atf_error 128 "The test case cleanup" \
614240116Smarcel                "returned a non-ok exit code, but this is not allowed"
615240116Smarcel        fi
616240116Smarcel        ;;
617240116Smarcel    *)
618240116Smarcel        _atf_error 128 "Unknown test case part"
619240116Smarcel        ;;
620240116Smarcel    esac
621240116Smarcel}
622240116Smarcel
623240116Smarcel#
624240116Smarcel# _atf_syntax_error msg1 [.. msgN]
625240116Smarcel#
626240116Smarcel#   Formats and prints a syntax error message and terminates the
627240116Smarcel#   program prematurely.
628240116Smarcel#
629240116Smarcel_atf_syntax_error()
630240116Smarcel{
631240116Smarcel    echo "${Prog_Name}: ERROR: ${@}" 1>&2
632240116Smarcel    echo "${Prog_Name}: See atf-test-program(1) for usage details." 1>&2
633240116Smarcel    exit 1
634240116Smarcel}
635240116Smarcel
636240116Smarcel#
637240116Smarcel# _atf_has_cleanup tc-name
638240116Smarcel#
639240116Smarcel#   Returns a boolean indicating if the given test case has a cleanup
640240116Smarcel#   routine or not.
641240116Smarcel#
642240116Smarcel_atf_has_cleanup()
643240116Smarcel{
644240116Smarcel    _found=true
645240116Smarcel    eval "[ x\"\${__has_cleanup_${1}}\" = xtrue ] || _found=false"
646240116Smarcel    [ "${_found}" = true ]
647240116Smarcel}
648240116Smarcel
649240116Smarcel#
650240116Smarcel# _atf_validate_expect
651240116Smarcel#
652240116Smarcel#   Ensures that the current test case state is correct regarding the expect
653240116Smarcel#   status.
654240116Smarcel#
655240116Smarcel_atf_validate_expect()
656240116Smarcel{
657240116Smarcel    case "${Expect}" in
658240116Smarcel        death)
659240116Smarcel            Expect=pass
660240116Smarcel            atf_fail "Test case was expected to terminate abruptly but it" \
661240116Smarcel                "continued execution"
662240116Smarcel            ;;
663240116Smarcel        exit)
664240116Smarcel            Expect=pass
665240116Smarcel            atf_fail "Test case was expected to exit cleanly but it continued" \
666240116Smarcel                "execution"
667240116Smarcel            ;;
668240116Smarcel        fail)
669240116Smarcel            Expect=pass
670240116Smarcel            atf_fail "Test case was expecting a failure but none were raised"
671240116Smarcel            ;;
672240116Smarcel        pass)
673240116Smarcel            ;;
674240116Smarcel        signal)
675240116Smarcel            Expect=pass
676240116Smarcel            atf_fail "Test case was expected to receive a termination signal" \
677240116Smarcel                "but it continued execution"
678240116Smarcel            ;;
679240116Smarcel        timeout)
680240116Smarcel            Expect=pass
681240116Smarcel            atf_fail "Test case was expected to hang but it continued execution"
682240116Smarcel            ;;
683240116Smarcel        *)
684240116Smarcel            _atf_error 128 "Unreachable"
685240116Smarcel            ;;
686240116Smarcel    esac
687240116Smarcel}
688240116Smarcel
689240116Smarcel#
690240116Smarcel# _atf_warning [msg1 [.. msgN]]
691240116Smarcel#
692240116Smarcel#   Prints the given warning message (which can be composed of multiple
693240116Smarcel#   arguments, in which case are joined by a single space).
694240116Smarcel#
695240116Smarcel#   This must not be used by test programs themselves (hence making
696240116Smarcel#   the function private).
697240116Smarcel#
698240116Smarcel_atf_warning()
699240116Smarcel{
700240116Smarcel    echo "${Prog_Name}: WARNING:" "$@" 1>&2
701240116Smarcel}
702240116Smarcel
703240116Smarcel#
704240116Smarcel# main [options] test_case
705240116Smarcel#
706240116Smarcel#   Test program's entry point.
707240116Smarcel#
708240116Smarcelmain()
709240116Smarcel{
710240116Smarcel    # Process command-line options first.
711240116Smarcel    _numargs=${#}
712240116Smarcel    _lflag=false
713240116Smarcel    while getopts :lr:s:v: arg; do
714240116Smarcel        case ${arg} in
715240116Smarcel        l)
716240116Smarcel            _lflag=true
717240116Smarcel            ;;
718240116Smarcel
719240116Smarcel        r)
720240116Smarcel            Results_File=${OPTARG}
721240116Smarcel            ;;
722240116Smarcel
723240116Smarcel        s)
724240116Smarcel            Source_Dir=${OPTARG}
725240116Smarcel            ;;
726240116Smarcel
727240116Smarcel        v)
728240116Smarcel            _atf_config_set_from_str "${OPTARG}"
729240116Smarcel            ;;
730240116Smarcel
731240116Smarcel        \?)
732240116Smarcel            _atf_syntax_error "Unknown option -${OPTARG}."
733240116Smarcel            # NOTREACHED
734240116Smarcel            ;;
735240116Smarcel        esac
736240116Smarcel    done
737240116Smarcel    shift `expr ${OPTIND} - 1`
738240116Smarcel
739240116Smarcel    case ${Source_Dir} in
740240116Smarcel        /*)
741240116Smarcel            ;;
742240116Smarcel        *)
743240116Smarcel            Source_Dir=$(pwd)/${Source_Dir}
744240116Smarcel            ;;
745240116Smarcel    esac
746240116Smarcel    [ -f ${Source_Dir}/${Prog_Name} ] || \
747240116Smarcel        _atf_error 1 "Cannot find the test program in the source" \
748240116Smarcel                     "directory \`${Source_Dir}'"
749240116Smarcel
750240116Smarcel    # Call the test program's hook to register all available test cases.
751240116Smarcel    atf_init_test_cases
752240116Smarcel
753240116Smarcel    # Run or list test cases.
754240116Smarcel    if `${_lflag}`; then
755240116Smarcel        if [ ${#} -gt 0 ]; then
756240116Smarcel            _atf_syntax_error "Cannot provide test case names with -l"
757240116Smarcel        fi
758240116Smarcel        _atf_list_tcs
759240116Smarcel    else
760240116Smarcel        if [ ${#} -eq 0 ]; then
761240116Smarcel            _atf_syntax_error "Must provide a test case name"
762240116Smarcel        elif [ ${#} -gt 1 ]; then
763240116Smarcel            _atf_syntax_error "Cannot provide more than one test case name"
764240116Smarcel        else
765240116Smarcel            _atf_run_tc "${1}"
766240116Smarcel        fi
767240116Smarcel    fi
768240116Smarcel}
769240116Smarcel
770240116Smarcel# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
771