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