xref: /netbsd-src/external/bsd/atf/dist/atf-c/atf-c-api.3 (revision d5ef91429e7b3235d66a7c82bd9a1103be3c4016)
1e2207522Sjmmv.\"
2e2207522Sjmmv.\" Automated Testing Framework (atf)
3e2207522Sjmmv.\"
4a551a20fSjmmv.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
5e2207522Sjmmv.\" All rights reserved.
6e2207522Sjmmv.\"
7e2207522Sjmmv.\" Redistribution and use in source and binary forms, with or without
8e2207522Sjmmv.\" modification, are permitted provided that the following conditions
9e2207522Sjmmv.\" are met:
10e2207522Sjmmv.\" 1. Redistributions of source code must retain the above copyright
11e2207522Sjmmv.\"    notice, this list of conditions and the following disclaimer.
12e2207522Sjmmv.\" 2. Redistributions in binary form must reproduce the above copyright
13e2207522Sjmmv.\"    notice, this list of conditions and the following disclaimer in the
14e2207522Sjmmv.\"    documentation and/or other materials provided with the distribution.
15e2207522Sjmmv.\"
16e2207522Sjmmv.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17e2207522Sjmmv.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18e2207522Sjmmv.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19e2207522Sjmmv.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20e2207522Sjmmv.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21e2207522Sjmmv.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22e2207522Sjmmv.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23e2207522Sjmmv.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24e2207522Sjmmv.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25e2207522Sjmmv.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26e2207522Sjmmv.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27e2207522Sjmmv.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28e2207522Sjmmv.\"
29*d5ef9142Sgutteridge.Dd March 14, 2023
30e2207522Sjmmv.Dt ATF-C-API 3
31e2207522Sjmmv.Os
32e2207522Sjmmv.Sh NAME
336f587c98Sjmmv.Nm atf-c-api ,
34e2207522Sjmmv.Nm ATF_CHECK ,
3512aa0b5aSjmmv.Nm ATF_CHECK_MSG ,
3612aa0b5aSjmmv.Nm ATF_CHECK_EQ ,
3712aa0b5aSjmmv.Nm ATF_CHECK_EQ_MSG ,
386f587c98Sjmmv.Nm ATF_CHECK_MATCH ,
396f587c98Sjmmv.Nm ATF_CHECK_MATCH_MSG ,
4012aa0b5aSjmmv.Nm ATF_CHECK_STREQ ,
4112aa0b5aSjmmv.Nm ATF_CHECK_STREQ_MSG ,
42edebbb8eSjmmv.Nm ATF_CHECK_ERRNO ,
4312aa0b5aSjmmv.Nm ATF_REQUIRE ,
4412aa0b5aSjmmv.Nm ATF_REQUIRE_MSG ,
4512aa0b5aSjmmv.Nm ATF_REQUIRE_EQ ,
4612aa0b5aSjmmv.Nm ATF_REQUIRE_EQ_MSG ,
476f587c98Sjmmv.Nm ATF_REQUIRE_MATCH ,
486f587c98Sjmmv.Nm ATF_REQUIRE_MATCH_MSG ,
4912aa0b5aSjmmv.Nm ATF_REQUIRE_STREQ ,
5012aa0b5aSjmmv.Nm ATF_REQUIRE_STREQ_MSG ,
51edebbb8eSjmmv.Nm ATF_REQUIRE_ERRNO ,
52e2207522Sjmmv.Nm ATF_TC ,
53e2207522Sjmmv.Nm ATF_TC_BODY ,
54e2207522Sjmmv.Nm ATF_TC_BODY_NAME ,
55e2207522Sjmmv.Nm ATF_TC_CLEANUP ,
56e2207522Sjmmv.Nm ATF_TC_CLEANUP_NAME ,
57e2207522Sjmmv.Nm ATF_TC_HEAD ,
58e2207522Sjmmv.Nm ATF_TC_HEAD_NAME ,
59e2207522Sjmmv.Nm ATF_TC_NAME ,
60e2207522Sjmmv.Nm ATF_TC_WITH_CLEANUP ,
619b3149ccSjmmv.Nm ATF_TC_WITHOUT_HEAD ,
62e2207522Sjmmv.Nm ATF_TP_ADD_TC ,
63e2207522Sjmmv.Nm ATF_TP_ADD_TCS ,
64eb215e31Sjmmv.Nm atf_tc_get_config_var ,
65eb215e31Sjmmv.Nm atf_tc_get_config_var_wd ,
66eb215e31Sjmmv.Nm atf_tc_get_config_var_as_bool ,
67eb215e31Sjmmv.Nm atf_tc_get_config_var_as_bool_wd ,
68eb215e31Sjmmv.Nm atf_tc_get_config_var_as_long ,
69eb215e31Sjmmv.Nm atf_tc_get_config_var_as_long_wd ,
70e2207522Sjmmv.Nm atf_no_error ,
71edebbb8eSjmmv.Nm atf_tc_expect_death ,
72edebbb8eSjmmv.Nm atf_tc_expect_exit ,
73edebbb8eSjmmv.Nm atf_tc_expect_fail ,
74edebbb8eSjmmv.Nm atf_tc_expect_pass ,
75edebbb8eSjmmv.Nm atf_tc_expect_signal ,
76edebbb8eSjmmv.Nm atf_tc_expect_timeout ,
77e2207522Sjmmv.Nm atf_tc_fail ,
78e2207522Sjmmv.Nm atf_tc_fail_nonfatal ,
79e2207522Sjmmv.Nm atf_tc_pass ,
806f587c98Sjmmv.Nm atf_tc_skip ,
816f587c98Sjmmv.Nm atf_utils_cat_file ,
826f587c98Sjmmv.Nm atf_utils_compare_file ,
836f587c98Sjmmv.Nm atf_utils_copy_file ,
846f587c98Sjmmv.Nm atf_utils_create_file ,
856f587c98Sjmmv.Nm atf_utils_file_exists ,
866f587c98Sjmmv.Nm atf_utils_fork ,
876f587c98Sjmmv.Nm atf_utils_free_charpp ,
886f587c98Sjmmv.Nm atf_utils_grep_file ,
896f587c98Sjmmv.Nm atf_utils_grep_string ,
906f587c98Sjmmv.Nm atf_utils_readline ,
916f587c98Sjmmv.Nm atf_utils_redirect ,
926f587c98Sjmmv.Nm atf_utils_wait
93e2207522Sjmmv.Nd C API to write ATF-based test programs
94e2207522Sjmmv.Sh SYNOPSIS
95e2207522Sjmmv.In atf-c.h
96e2207522Sjmmv.Fn ATF_CHECK "expression"
9712aa0b5aSjmmv.Fn ATF_CHECK_MSG "expression" "fail_msg_fmt" ...
9812aa0b5aSjmmv.Fn ATF_CHECK_EQ "expression_1" "expression_2"
9912aa0b5aSjmmv.Fn ATF_CHECK_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ...
1006f587c98Sjmmv.Fn ATF_CHECK_MATCH "regexp" "string"
1016f587c98Sjmmv.Fn ATF_CHECK_MATCH_MSG "regexp" "string" "fail_msg_fmt" ...
10212aa0b5aSjmmv.Fn ATF_CHECK_STREQ "string_1" "string_2"
10312aa0b5aSjmmv.Fn ATF_CHECK_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ...
104edebbb8eSjmmv.Fn ATF_CHECK_ERRNO "exp_errno" "bool_expression"
10512aa0b5aSjmmv.Fn ATF_REQUIRE "expression"
10612aa0b5aSjmmv.Fn ATF_REQUIRE_MSG "expression" "fail_msg_fmt" ...
10712aa0b5aSjmmv.Fn ATF_REQUIRE_EQ "expression_1" "expression_2"
10812aa0b5aSjmmv.Fn ATF_REQUIRE_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ...
1096f587c98Sjmmv.Fn ATF_REQUIRE_MATCH "regexp" "string"
1106f587c98Sjmmv.Fn ATF_REQUIRE_MATCH_MSG "regexp" "string" "fail_msg_fmt" ...
11112aa0b5aSjmmv.Fn ATF_REQUIRE_STREQ "string_1" "string_2"
11212aa0b5aSjmmv.Fn ATF_REQUIRE_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ...
113edebbb8eSjmmv.Fn ATF_REQUIRE_ERRNO "exp_errno" "bool_expression"
114e2207522Sjmmv.Fn ATF_TC "name"
115e2207522Sjmmv.Fn ATF_TC_BODY "name" "tc"
116e2207522Sjmmv.Fn ATF_TC_BODY_NAME "name"
117e2207522Sjmmv.Fn ATF_TC_CLEANUP "name" "tc"
118e2207522Sjmmv.Fn ATF_TC_CLEANUP_NAME "name"
119e2207522Sjmmv.Fn ATF_TC_HEAD "name" "tc"
120e2207522Sjmmv.Fn ATF_TC_HEAD_NAME "name"
121e2207522Sjmmv.Fn ATF_TC_NAME "name"
122e2207522Sjmmv.Fn ATF_TC_WITH_CLEANUP "name"
1239b3149ccSjmmv.Fn ATF_TC_WITHOUT_HEAD "name"
124edebbb8eSjmmv.Fn ATF_TP_ADD_TC "tp_name" "tc_name"
125edebbb8eSjmmv.Fn ATF_TP_ADD_TCS "tp_name"
126eb215e31Sjmmv.Fn atf_tc_get_config_var "tc" "varname"
127eb215e31Sjmmv.Fn atf_tc_get_config_var_wd "tc" "variable_name" "default_value"
128eb215e31Sjmmv.Fn atf_tc_get_config_var_as_bool "tc" "variable_name"
129eb215e31Sjmmv.Fn atf_tc_get_config_var_as_bool_wd "tc" "variable_name" "default_value"
130eb215e31Sjmmv.Fn atf_tc_get_config_var_as_long "tc" "variable_name"
131eb215e31Sjmmv.Fn atf_tc_get_config_var_as_long_wd "tc" "variable_name" "default_value"
132e2207522Sjmmv.Fn atf_no_error
133edebbb8eSjmmv.Fn atf_tc_expect_death "reason" "..."
134edebbb8eSjmmv.Fn atf_tc_expect_exit "exitcode" "reason" "..."
135edebbb8eSjmmv.Fn atf_tc_expect_fail "reason" "..."
136edebbb8eSjmmv.Fn atf_tc_expect_pass
137edebbb8eSjmmv.Fn atf_tc_expect_signal "signo" "reason" "..."
138edebbb8eSjmmv.Fn atf_tc_expect_timeout "reason" "..."
139e2207522Sjmmv.Fn atf_tc_fail "reason"
140e2207522Sjmmv.Fn atf_tc_fail_nonfatal "reason"
141e2207522Sjmmv.Fn atf_tc_pass
142e2207522Sjmmv.Fn atf_tc_skip "reason"
1436f587c98Sjmmv.Ft void
1446f587c98Sjmmv.Fo atf_utils_cat_file
1456f587c98Sjmmv.Fa "const char *file"
1466f587c98Sjmmv.Fa "const char *prefix"
1476f587c98Sjmmv.Fc
1486f587c98Sjmmv.Ft bool
1496f587c98Sjmmv.Fo atf_utils_compare_file
1506f587c98Sjmmv.Fa "const char *file"
1516f587c98Sjmmv.Fa "const char *contents"
1526f587c98Sjmmv.Fc
1536f587c98Sjmmv.Ft void
1546f587c98Sjmmv.Fo atf_utils_copy_file
1556f587c98Sjmmv.Fa "const char *source"
1566f587c98Sjmmv.Fa "const char *destination"
1576f587c98Sjmmv.Fc
1586f587c98Sjmmv.Ft void
1596f587c98Sjmmv.Fo atf_utils_create_file
1606f587c98Sjmmv.Fa "const char *file"
1616f587c98Sjmmv.Fa "const char *contents"
1626f587c98Sjmmv.Fa "..."
1636f587c98Sjmmv.Fc
1646f587c98Sjmmv.Ft void
1656f587c98Sjmmv.Fo atf_utils_file_exists
1666f587c98Sjmmv.Fa "const char *file"
1676f587c98Sjmmv.Fc
1686f587c98Sjmmv.Ft pid_t
1696f587c98Sjmmv.Fo atf_utils_fork
1706f587c98Sjmmv.Fa "void"
1716f587c98Sjmmv.Fc
1726f587c98Sjmmv.Ft void
1736f587c98Sjmmv.Fo atf_utils_free_charpp
1746f587c98Sjmmv.Fa "char **argv"
1756f587c98Sjmmv.Fc
1766f587c98Sjmmv.Ft bool
1776f587c98Sjmmv.Fo atf_utils_grep_file
1786f587c98Sjmmv.Fa "const char *regexp"
1796f587c98Sjmmv.Fa "const char *file"
1806f587c98Sjmmv.Fa "..."
1816f587c98Sjmmv.Fc
1826f587c98Sjmmv.Ft bool
1836f587c98Sjmmv.Fo atf_utils_grep_string
1846f587c98Sjmmv.Fa "const char *regexp"
1856f587c98Sjmmv.Fa "const char *str"
1866f587c98Sjmmv.Fa "..."
1876f587c98Sjmmv.Fc
1886f587c98Sjmmv.Ft char *
1896f587c98Sjmmv.Fo atf_utils_readline
1906f587c98Sjmmv.Fa "int fd"
1916f587c98Sjmmv.Fc
1926f587c98Sjmmv.Ft void
1936f587c98Sjmmv.Fo atf_utils_redirect
1946f587c98Sjmmv.Fa "const int fd"
1956f587c98Sjmmv.Fa "const char *file"
1966f587c98Sjmmv.Fc
1976f587c98Sjmmv.Ft void
1986f587c98Sjmmv.Fo atf_utils_wait
1996f587c98Sjmmv.Fa "const pid_t pid"
2006f587c98Sjmmv.Fa "const int expected_exit_status"
2016f587c98Sjmmv.Fa "const char *expected_stdout"
2026f587c98Sjmmv.Fa "const char *expected_stderr"
2036f587c98Sjmmv.Fc
204e2207522Sjmmv.Sh DESCRIPTION
20597bff204SjmmvATF provides a C programming interface to implement test programs.
20697bff204SjmmvC-based test programs follow this template:
207e2207522Sjmmv.Bd -literal -offset indent
208e2207522Sjmmv.Ns ... C-specific includes go here ...
209e2207522Sjmmv
210e2207522Sjmmv#include <atf-c.h>
211e2207522Sjmmv
212e2207522SjmmvATF_TC(tc1);
213e2207522SjmmvATF_TC_HEAD(tc1, tc)
214e2207522Sjmmv{
215e2207522Sjmmv    ... first test case's header ...
216e2207522Sjmmv}
217e2207522SjmmvATF_TC_BODY(tc1, tc)
218e2207522Sjmmv{
219e2207522Sjmmv    ... first test case's body ...
220e2207522Sjmmv}
221e2207522Sjmmv
222e2207522SjmmvATF_TC_WITH_CLEANUP(tc2);
223e2207522SjmmvATF_TC_HEAD(tc2, tc)
224e2207522Sjmmv{
225e2207522Sjmmv    ... second test case's header ...
226e2207522Sjmmv}
227e2207522SjmmvATF_TC_BODY(tc2, tc)
228e2207522Sjmmv{
229e2207522Sjmmv    ... second test case's body ...
230e2207522Sjmmv}
231e2207522SjmmvATF_TC_CLEANUP(tc2, tc)
232e2207522Sjmmv{
233e2207522Sjmmv    ... second test case's cleanup ...
234e2207522Sjmmv}
235e2207522Sjmmv
2369b3149ccSjmmvATF_TC_WITHOUT_HEAD(tc3);
2379b3149ccSjmmvATF_TC_BODY(tc3, tc)
2389b3149ccSjmmv{
2399b3149ccSjmmv    ... third test case's body ...
2409b3149ccSjmmv}
2419b3149ccSjmmv
242e2207522Sjmmv.Ns ... additional test cases ...
243e2207522Sjmmv
244edebbb8eSjmmvATF_TP_ADD_TCS(tp)
245e2207522Sjmmv{
246*d5ef9142Sgutteridge    ATF_TP_ADD_TC(tp, tc1);
247*d5ef9142Sgutteridge    ATF_TP_ADD_TC(tp, tc2);
248*d5ef9142Sgutteridge    ATF_TP_ADD_TC(tp, tc3);
249e2207522Sjmmv    ... add additional test cases ...
250e2207522Sjmmv
251e2207522Sjmmv    return atf_no_error();
252e2207522Sjmmv}
253e2207522Sjmmv.Ed
254e2207522Sjmmv.Ss Definition of test cases
255e2207522SjmmvTest cases have an identifier and are composed of three different parts:
256e2207522Sjmmvthe header, the body and an optional cleanup routine, all of which are
257e2207522Sjmmvdescribed in
258edebbb8eSjmmv.Xr atf-test-case 4 .
259e2207522SjmmvTo define test cases, one can use the
2609b3149ccSjmmv.Fn ATF_TC ,
261e2207522Sjmmv.Fn ATF_TC_WITH_CLEANUP
2629b3149ccSjmmvor the
2639b3149ccSjmmv.Fn ATF_TC_WITHOUT_HEAD
264e2207522Sjmmvmacros, which take a single parameter specifiying the test case's name.
2659b3149ccSjmmv.Fn ATF_TC ,
2669b3149ccSjmmvrequires to define a head and a body for the test case,
2679b3149ccSjmmv.Fn ATF_TC_WITH_CLEANUP
2689b3149ccSjmmvrequires to define a head, a body and a cleanup for the test case and
2699b3149ccSjmmv.Fn ATF_TC_WITHOUT_HEAD
2709b3149ccSjmmvrequires only a body for the test case.
271e2207522SjmmvIt is important to note that these
272e2207522Sjmmv.Em do not
273e2207522Sjmmvset the test case up for execution when the program is run.
274e2207522SjmmvIn order to do so, a later registration is needed with the
275e2207522Sjmmv.Fn ATF_TP_ADD_TC
276e2207522Sjmmvmacro detailed in
277e2207522Sjmmv.Sx Program initialization .
278e2207522Sjmmv.Pp
2791aba6344SpgoyetteLater on, one must define the three parts of the test by means of three
280e2207522Sjmmvfunctions.
281e2207522SjmmvTheir headers are given by the
282e2207522Sjmmv.Fn ATF_TC_HEAD ,
2831aba6344Spgoyette.Fn ATF_TC_BODY ,
284e2207522Sjmmvand
285e2207522Sjmmv.Fn ATF_TC_CLEANUP
286e2207522Sjmmvmacros, all of which take the test case name provided to the
2871aba6344Spgoyette.Fn ATF_TC ,
2889b3149ccSjmmv.Fn ATF_TC_WITH_CLEANUP ,
289e2207522Sjmmvor
2909b3149ccSjmmv.Fn ATF_TC_WITHOUT_HEAD
291e2207522Sjmmvmacros and the name of the variable that will hold a pointer to the
292e2207522Sjmmvtest case data.
293e2207522SjmmvFollowing each of these, a block of code is expected, surrounded by the
294e2207522Sjmmvopening and closing brackets.
295e2207522Sjmmv.Ss Program initialization
296e2207522SjmmvThe library provides a way to easily define the test program's
297e2207522Sjmmv.Fn main
298e2207522Sjmmvfunction.
299e2207522SjmmvYou should never define one on your own, but rely on the
300e2207522Sjmmvlibrary to do it for you.
301e2207522SjmmvThis is done by using the
302e2207522Sjmmv.Fn ATF_TP_ADD_TCS
303e2207522Sjmmvmacro, which is passed the name of the object that will hold the test
304e2207522Sjmmvcases; i.e. the test program instance.
305e2207522SjmmvThis name can be whatever you want as long as it is a valid variable
306e2207522Sjmmvidentifier.
307e2207522Sjmmv.Pp
308e2207522SjmmvAfter the macro, you are supposed to provide the body of a function, which
309e2207522Sjmmvshould only use the
310e2207522Sjmmv.Fn ATF_TP_ADD_TC
311e2207522Sjmmvmacro to register the test cases the test program will execute and return
312e2207522Sjmmva success error code.
313e2207522SjmmvThe first parameter of this macro matches the name you provided in the
314e2207522Sjmmvformer call.
315e2207522SjmmvThe success status can be returned using the
316e2207522Sjmmv.Fn atf_no_error
317e2207522Sjmmvfunction.
318e2207522Sjmmv.Ss Header definitions
319e2207522SjmmvThe test case's header can define the meta-data by using the
320e2207522Sjmmv.Fn atf_tc_set_md_var
321e2207522Sjmmvmethod, which takes three parameters: the first one points to the test
322e2207522Sjmmvcase data, the second one specifies the meta-data variable to be set
323e2207522Sjmmvand the third one specifies its value.
324e2207522SjmmvBoth of them are strings.
325e2207522Sjmmv.Ss Configuration variables
326e2207522SjmmvThe test case has read-only access to the current configuration variables
327e2207522Sjmmvby means of the
328e2207522Sjmmv.Ft bool
3290ebb519dSjmmv.Fn atf_tc_has_config_var ,
330e2207522Sjmmv.Ft const char *
3310ebb519dSjmmv.Fn atf_tc_get_config_var ,
3320ebb519dSjmmv.Ft const char *
3330ebb519dSjmmv.Fn atf_tc_get_config_var_wd ,
3340ebb519dSjmmv.Ft bool
3350ebb519dSjmmv.Fn atf_tc_get_config_var_as_bool ,
3360ebb519dSjmmv.Ft bool
3370ebb519dSjmmv.Fn atf_tc_get_config_var_as_bool_wd ,
3380ebb519dSjmmv.Ft long
3390ebb519dSjmmv.Fn atf_tc_get_config_var_as_long ,
3400ebb519dSjmmvand the
3410ebb519dSjmmv.Ft long
3420ebb519dSjmmv.Fn atf_tc_get_config_var_as_long_wd
3430ebb519dSjmmvfunctions, which can be called in any of the three parts of a test case.
344eb215e31Sjmmv.Pp
345eb215e31SjmmvThe
346eb215e31Sjmmv.Sq _wd
347eb215e31Sjmmvvariants take a default value for the variable which is returned if the
348eb215e31Sjmmvvariable is not defined.
349eb215e31SjmmvThe other functions without the
350eb215e31Sjmmv.Sq _wd
351eb215e31Sjmmvsuffix
352eb215e31Sjmmv.Em require
353eb215e31Sjmmvthe variable to be defined.
354e2207522Sjmmv.Ss Access to the source directory
355e2207522SjmmvIt is possible to get the path to the test case's source directory from any
356e2207522Sjmmvof its three components by querying the
357e2207522Sjmmv.Sq srcdir
358e2207522Sjmmvconfiguration variable.
359e2207522Sjmmv.Ss Requiring programs
360e2207522SjmmvAside from the
361e2207522Sjmmv.Va require.progs
362e2207522Sjmmvmeta-data variable available in the header only, one can also check for
363e2207522Sjmmvadditional programs in the test case's body by using the
364e2207522Sjmmv.Fn atf_tc_require_prog
365e2207522Sjmmvfunction, which takes the base name or full path of a single binary.
366e2207522SjmmvRelative paths are forbidden.
367e2207522SjmmvIf it is not found, the test case will be automatically skipped.
368e2207522Sjmmv.Ss Test case finalization
369e2207522SjmmvThe test case finalizes either when the body reaches its end, at which
370e2207522Sjmmvpoint the test is assumed to have
371e2207522Sjmmv.Em passed ,
372e2207522Sjmmvunless any non-fatal errors were raised using
373e2207522Sjmmv.Fn atf_tc_fail_nonfatal ,
374e2207522Sjmmvor at any explicit call to
375e2207522Sjmmv.Fn atf_tc_pass ,
376e2207522Sjmmv.Fn atf_tc_fail
377e2207522Sjmmvor
378e2207522Sjmmv.Fn atf_tc_skip .
379e2207522SjmmvThese three functions terminate the execution of the test case immediately.
380e2207522SjmmvThe cleanup routine will be processed afterwards in a completely automated
381e2207522Sjmmvway, regardless of the test case's termination reason.
382e2207522Sjmmv.Pp
383e2207522Sjmmv.Fn atf_tc_pass
384e2207522Sjmmvdoes not take any parameters.
385e2207522Sjmmv.Fn atf_tc_fail ,
386e2207522Sjmmv.Fn atf_tc_fail_nonfatal
387e2207522Sjmmvand
388e2207522Sjmmv.Fn atf_tc_skip
389e2207522Sjmmvtake a format string and a variable list of parameters, which describe, in
390e2207522Sjmmva user-friendly manner, why the test case failed or was skipped,
391e2207522Sjmmvrespectively.
392e2207522SjmmvIt is very important to provide a clear error message in both cases so that
393e2207522Sjmmvthe user can quickly know why the test did not pass.
394edebbb8eSjmmv.Ss Expectations
395edebbb8eSjmmvEverything explained in the previous section changes when the test case
396edebbb8eSjmmvexpectations are redefined by the programmer.
397edebbb8eSjmmv.Pp
398edebbb8eSjmmvEach test case has an internal state called
399edebbb8eSjmmv.Sq expect
400edebbb8eSjmmvthat describes what the test case expectations are at any point in time.
401edebbb8eSjmmvThe value of this property can change during execution by any of:
402edebbb8eSjmmv.Bl -tag -width indent
403edebbb8eSjmmv.It Fn atf_tc_expect_death "reason" "..."
404edebbb8eSjmmvExpects the test case to exit prematurely regardless of the nature of the
405edebbb8eSjmmvexit.
406edebbb8eSjmmv.It Fn atf_tc_expect_exit "exitcode" "reason" "..."
407edebbb8eSjmmvExpects the test case to exit cleanly.
408edebbb8eSjmmvIf
409edebbb8eSjmmv.Va exitcode
410edebbb8eSjmmvis not
411edebbb8eSjmmv.Sq -1 ,
412edebbb8eSjmmv.Xr atf-run 1
413edebbb8eSjmmvwill validate that the exit code of the test case matches the one provided
414edebbb8eSjmmvin this call.
415edebbb8eSjmmvOtherwise, the exact value will be ignored.
416edebbb8eSjmmv.It Fn atf_tc_expect_fail "reason" "..."
417edebbb8eSjmmvAny failure (be it fatal or non-fatal) raised in this mode is recorded.
418edebbb8eSjmmvHowever, such failures do not report the test case as failed; instead, the
419edebbb8eSjmmvtest case finalizes cleanly and is reported as
420edebbb8eSjmmv.Sq expected failure ;
421edebbb8eSjmmvthis report includes the provided
422edebbb8eSjmmv.Fa reason
423edebbb8eSjmmvas part of it.
424edebbb8eSjmmvIf no error is raised while running in this mode, then the test case is
425edebbb8eSjmmvreported as
426edebbb8eSjmmv.Sq failed .
427edebbb8eSjmmv.Pp
428edebbb8eSjmmvThis mode is useful to reproduce actual known bugs in tests.
429edebbb8eSjmmvWhenever the developer fixes the bug later on, the test case will start
430edebbb8eSjmmvreporting a failure, signaling the developer that the test case must be
431edebbb8eSjmmvadjusted to the new conditions.
432edebbb8eSjmmvIn this situation, it is useful, for example, to set
433edebbb8eSjmmv.Fa reason
434edebbb8eSjmmvas the bug number for tracking purposes.
435edebbb8eSjmmv.It Fn atf_tc_expect_pass
436edebbb8eSjmmvThis is the normal mode of execution.
437edebbb8eSjmmvIn this mode, any failure is reported as such to the user and the test case
438edebbb8eSjmmvis marked as
439edebbb8eSjmmv.Sq failed .
440edebbb8eSjmmv.It Fn atf_tc_expect_signal "signo" "reason" "..."
441edebbb8eSjmmvExpects the test case to terminate due to the reception of a signal.
442edebbb8eSjmmvIf
443edebbb8eSjmmv.Va signo
444edebbb8eSjmmvis not
445edebbb8eSjmmv.Sq -1 ,
446edebbb8eSjmmv.Xr atf-run 1
447edebbb8eSjmmvwill validate that the signal that terminated the test case matches the one
448edebbb8eSjmmvprovided in this call.
449edebbb8eSjmmvOtherwise, the exact value will be ignored.
450edebbb8eSjmmv.It Fn atf_tc_expect_timeout "reason" "..."
451edebbb8eSjmmvExpects the test case to execute for longer than its timeout.
452edebbb8eSjmmv.El
453e2207522Sjmmv.Ss Helper macros for common checks
454e2207522SjmmvThe library provides several macros that are very handy in multiple
455e2207522Sjmmvsituations.
456e2207522SjmmvThese basically check some condition after executing a given statement or
457e2207522Sjmmvprocessing a given expression and, if the condition is not met, they
45812aa0b5aSjmmvreport the test case as failed.
45912aa0b5aSjmmv.Pp
46012aa0b5aSjmmvThe
46112aa0b5aSjmmv.Sq REQUIRE
46212aa0b5aSjmmvvariant of the macros immediately abort the test case as soon as an error
46312aa0b5aSjmmvcondition is detected by calling the
464e2207522Sjmmv.Fn atf_tc_fail
46512aa0b5aSjmmvfunction.
466fa51ffa6SjoergUse this variant whenever it makes no sense to continue the execution of a
46712aa0b5aSjmmvtest case when the checked condition is not met.
46812aa0b5aSjmmvThe
46912aa0b5aSjmmv.Sq CHECK
47012aa0b5aSjmmvvariant, on the other hand, reports a failure as soon as it is encountered
47112aa0b5aSjmmvusing the
472e2207522Sjmmv.Fn atf_tc_fail_nonfatal
47312aa0b5aSjmmvfunction, but the execution of the test case continues as if nothing had
47412aa0b5aSjmmvhappened.
47512aa0b5aSjmmvUse this variant whenever the checked condition is important as a result of
47612aa0b5aSjmmvthe test case, but there are other conditions that can be subsequently
47712aa0b5aSjmmvchecked on the same run without aborting.
478e2207522Sjmmv.Pp
47912aa0b5aSjmmvAdditionally, the
48012aa0b5aSjmmv.Sq MSG
48112aa0b5aSjmmvvariants take an extra set of parameters to explicitly specify the failure
48212aa0b5aSjmmvmessage.
48312aa0b5aSjmmvThis failure message is formatted according to the
48412aa0b5aSjmmv.Xr printf 3
48512aa0b5aSjmmvformatters.
486e2207522Sjmmv.Pp
48712aa0b5aSjmmv.Fn ATF_CHECK ,
48812aa0b5aSjmmv.Fn ATF_CHECK_MSG ,
48912aa0b5aSjmmv.Fn ATF_REQUIRE
49012aa0b5aSjmmvand
49112aa0b5aSjmmv.Fn ATF_REQUIRE_MSG
49212aa0b5aSjmmvtake an expression and fail if the expression evaluates to false.
49312aa0b5aSjmmv.Pp
49412aa0b5aSjmmv.Fn ATF_CHECK_EQ ,
49512aa0b5aSjmmv.Fn ATF_CHECK_EQ_MSG ,
49612aa0b5aSjmmv.Fn ATF_REQUIRE_EQ
49712aa0b5aSjmmvand
49812aa0b5aSjmmv.Fn ATF_REQUIRE_EQ_MSG
49912aa0b5aSjmmvtake two expressions and fail if the two evaluated values are not equal.
50012aa0b5aSjmmv.Pp
5016f587c98Sjmmv.Fn ATF_CHECK_MATCH ,
5026f587c98Sjmmv.Fn ATF_CHECK_MATCH_MSG ,
5036f587c98Sjmmv.Fn ATF_REQUIRE_MATCH
5046f587c98Sjmmvand
5056f587c98Sjmmv.Fn ATF_REQUIRE_MATCH_MSG
5066f587c98Sjmmvtake a regular expression and a string and fail if the regular expression does
5076f587c98Sjmmvnot match the given string.
5086f587c98SjmmvNote that the regular expression is not anchored, so it will match anywhere in
5096f587c98Sjmmvthe string.
5106f587c98Sjmmv.Pp
51112aa0b5aSjmmv.Fn ATF_CHECK_STREQ ,
51212aa0b5aSjmmv.Fn ATF_CHECK_STREQ_MSG ,
51312aa0b5aSjmmv.Fn ATF_REQUIRE_STREQ
51412aa0b5aSjmmvand
51512aa0b5aSjmmv.Fn ATF_REQUIRE_STREQ_MSG
51612aa0b5aSjmmvtake two strings and fail if the two are not equal character by character.
517edebbb8eSjmmv.Pp
518edebbb8eSjmmv.Fn ATF_CHECK_ERRNO
519edebbb8eSjmmvand
520edebbb8eSjmmv.Fn ATF_REQUIRE_ERRNO
521edebbb8eSjmmvtake, first, the error code that the check is expecting to find in the
522edebbb8eSjmmv.Va errno
523edebbb8eSjmmvvariable and, second, a boolean expression that, if evaluates to true,
524edebbb8eSjmmvmeans that a call failed and
525edebbb8eSjmmv.Va errno
526edebbb8eSjmmvhas to be checked against the first value.
5276f587c98Sjmmv.Ss Utility functions
5286f587c98SjmmvThe following functions are provided as part of the
5296f587c98Sjmmv.Nm
5306f587c98SjmmvAPI to simplify the creation of a variety of tests.
5316f587c98SjmmvIn particular, these are useful to write tests for command-line interfaces.
5326f587c98Sjmmv.Pp
5336f587c98Sjmmv.Ft void
5346f587c98Sjmmv.Fo atf_utils_cat_file
5356f587c98Sjmmv.Fa "const char *file"
5366f587c98Sjmmv.Fa "const char *prefix"
5376f587c98Sjmmv.Fc
53897bff204Sjmmv.Bd -ragged -offset indent
5396f587c98SjmmvPrints the contents of
5406f587c98Sjmmv.Fa file
5416f587c98Sjmmvto the standard output, prefixing every line with the string in
5426f587c98Sjmmv.Fa prefix .
5436f587c98Sjmmv.Ed
5446f587c98Sjmmv.Pp
5456f587c98Sjmmv.Ft bool
5466f587c98Sjmmv.Fo atf_utils_compare_file
5476f587c98Sjmmv.Fa "const char *file"
5486f587c98Sjmmv.Fa "const char *contents"
5496f587c98Sjmmv.Fc
55097bff204Sjmmv.Bd -ragged -offset indent
5516f587c98SjmmvReturns true if the given
5526f587c98Sjmmv.Fa file
5536f587c98Sjmmvmatches exactly the expected inlined
5546f587c98Sjmmv.Fa contents .
5556f587c98Sjmmv.Ed
5566f587c98Sjmmv.Pp
5576f587c98Sjmmv.Ft void
5586f587c98Sjmmv.Fo atf_utils_copy_file
5596f587c98Sjmmv.Fa "const char *source"
5606f587c98Sjmmv.Fa "const char *destination"
5616f587c98Sjmmv.Fc
56297bff204Sjmmv.Bd -ragged -offset indent
5636f587c98SjmmvCopies the file
5646f587c98Sjmmv.Fa source
5656f587c98Sjmmvto
5666f587c98Sjmmv.Fa destination .
5676f587c98SjmmvThe permissions of the file are preserved during the code.
5686f587c98Sjmmv.Ed
5696f587c98Sjmmv.Pp
5706f587c98Sjmmv.Ft void
5716f587c98Sjmmv.Fo atf_utils_create_file
5726f587c98Sjmmv.Fa "const char *file"
5736f587c98Sjmmv.Fa "const char *contents"
5746f587c98Sjmmv.Fa "..."
5756f587c98Sjmmv.Fc
57697bff204Sjmmv.Bd -ragged -offset indent
5776f587c98SjmmvCreates
5786f587c98Sjmmv.Fa file
5796f587c98Sjmmvwith the text given in
5806f587c98Sjmmv.Fa contents ,
5816f587c98Sjmmvwhich is a formatting string that uses the rest of the variable arguments.
5826f587c98Sjmmv.Ed
5836f587c98Sjmmv.Pp
5846f587c98Sjmmv.Ft void
5856f587c98Sjmmv.Fo atf_utils_file_exists
5866f587c98Sjmmv.Fa "const char *file"
5876f587c98Sjmmv.Fc
58897bff204Sjmmv.Bd -ragged -offset indent
5896f587c98SjmmvChecks if
5906f587c98Sjmmv.Fa file
5916f587c98Sjmmvexists.
5926f587c98Sjmmv.Ed
5936f587c98Sjmmv.Pp
5946f587c98Sjmmv.Ft pid_t
5956f587c98Sjmmv.Fo atf_utils_fork
5966f587c98Sjmmv.Fa "void"
5976f587c98Sjmmv.Fc
59897bff204Sjmmv.Bd -ragged -offset indent
5996f587c98SjmmvForks a process and redirects the standard output and standard error of the
6006f587c98Sjmmvchild to files for later validation with
6016f587c98Sjmmv.Fn atf_utils_wait .
6026f587c98SjmmvFails the test case if the fork fails, so this does not return an error.
6036f587c98Sjmmv.Ed
6046f587c98Sjmmv.Pp
6056f587c98Sjmmv.Ft void
6066f587c98Sjmmv.Fo atf_utils_free_charpp
6076f587c98Sjmmv.Fa "char **argv"
6086f587c98Sjmmv.Fc
60997bff204Sjmmv.Bd -ragged -offset indent
6106f587c98SjmmvFrees a dynamically-allocated array of dynamically-allocated strings.
6116f587c98Sjmmv.Ed
6126f587c98Sjmmv.Pp
6136f587c98Sjmmv.Ft bool
6146f587c98Sjmmv.Fo atf_utils_grep_file
6156f587c98Sjmmv.Fa "const char *regexp"
6166f587c98Sjmmv.Fa "const char *file"
6176f587c98Sjmmv.Fa "..."
6186f587c98Sjmmv.Fc
61997bff204Sjmmv.Bd -ragged -offset indent
6206f587c98SjmmvSearches for the
6216f587c98Sjmmv.Fa regexp ,
6226f587c98Sjmmvwhich is a formatting string representing the regular expression,
6236f587c98Sjmmvin the
6246f587c98Sjmmv.Fa file .
6256f587c98SjmmvThe variable arguments are used to construct the regular expression.
6266f587c98Sjmmv.Ed
6276f587c98Sjmmv.Pp
6286f587c98Sjmmv.Ft bool
6296f587c98Sjmmv.Fo atf_utils_grep_string
6306f587c98Sjmmv.Fa "const char *regexp"
6316f587c98Sjmmv.Fa "const char *str"
6326f587c98Sjmmv.Fa "..."
6336f587c98Sjmmv.Fc
63497bff204Sjmmv.Bd -ragged -offset indent
6356f587c98SjmmvSearches for the
6366f587c98Sjmmv.Fa regexp ,
6376f587c98Sjmmvwhich is a formatting string representing the regular expression,
6386f587c98Sjmmvin the literal string
6396f587c98Sjmmv.Fa str .
6406f587c98SjmmvThe variable arguments are used to construct the regular expression.
6416f587c98Sjmmv.Ed
6426f587c98Sjmmv.Pp
6436f587c98Sjmmv.Ft char *
6446f587c98Sjmmv.Fo atf_utils_readline
6456f587c98Sjmmv.Fa "int fd"
6466f587c98Sjmmv.Fc
64797bff204Sjmmv.Bd -ragged -offset indent
6486f587c98SjmmvReads a line from the file descriptor
6496f587c98Sjmmv.Fa fd .
6506f587c98SjmmvThe line, if any, is returned as a dynamically-allocated buffer that must be
6516f587c98Sjmmvreleased with
6526f587c98Sjmmv.Xr free 3 .
6536f587c98SjmmvIf there was nothing to read, returns
6546f587c98Sjmmv.Sq NULL .
6556f587c98Sjmmv.Ed
6566f587c98Sjmmv.Pp
6576f587c98Sjmmv.Ft void
6586f587c98Sjmmv.Fo atf_utils_redirect
6596f587c98Sjmmv.Fa "const int fd"
6606f587c98Sjmmv.Fa "const char *file"
6616f587c98Sjmmv.Fc
66297bff204Sjmmv.Bd -ragged -offset indent
6636f587c98SjmmvRedirects the given file descriptor
6646f587c98Sjmmv.Fa fd
6656f587c98Sjmmvto
6666f587c98Sjmmv.Fa file .
6676f587c98SjmmvThis function exits the process in case of an error and does not properly mark
6686f587c98Sjmmvthe test case as failed.
6696f587c98SjmmvAs a result, it should only be used in subprocesses of the test case; specially
6706f587c98Sjmmvthose spawned by
6716f587c98Sjmmv.Fn atf_utils_fork .
6726f587c98Sjmmv.Ed
6736f587c98Sjmmv.Pp
6746f587c98Sjmmv.Ft void
6756f587c98Sjmmv.Fo atf_utils_wait
6766f587c98Sjmmv.Fa "const pid_t pid"
6776f587c98Sjmmv.Fa "const int expected_exit_status"
6786f587c98Sjmmv.Fa "const char *expected_stdout"
6796f587c98Sjmmv.Fa "const char *expected_stderr"
6806f587c98Sjmmv.Fc
68197bff204Sjmmv.Bd -ragged -offset indent
6826f587c98SjmmvWaits and validates the result of a subprocess spawned with
6836f587c98Sjmmv.Fn atf_utils_wait .
6846f587c98SjmmvThe validation involves checking that the subprocess exited cleanly and returned
6856f587c98Sjmmvthe code specified in
6866f587c98Sjmmv.Fa expected_exit_status
6876f587c98Sjmmvand that its standard output and standard error match the strings given in
6886f587c98Sjmmv.Fa expected_stdout
6896f587c98Sjmmvand
6906f587c98Sjmmv.Fa expected_stderr .
6916f587c98Sjmmv.Pp
6926f587c98SjmmvIf any of the
6936f587c98Sjmmv.Fa expected_stdout
6946f587c98Sjmmvor
6956f587c98Sjmmv.Fa expected_stderr
6966f587c98Sjmmvstrings are prefixed with
6976f587c98Sjmmv.Sq save: ,
6986f587c98Sjmmvthen they specify the name of the file into which to store the stdout or stderr
6996f587c98Sjmmvof the subprocess, and no comparison is performed.
7006f587c98Sjmmv.Ed
701e2207522Sjmmv.Sh EXAMPLES
702e2207522SjmmvThe following shows a complete test program with a single test case that
703e2207522Sjmmvvalidates the addition operator:
704e2207522Sjmmv.Bd -literal -offset indent
705e2207522Sjmmv#include <atf-c.h>
706e2207522Sjmmv
707e2207522SjmmvATF_TC(addition);
708e2207522SjmmvATF_TC_HEAD(addition, tc)
709e2207522Sjmmv{
710e2207522Sjmmv    atf_tc_set_md_var(tc, "descr",
711e2207522Sjmmv                      "Sample tests for the addition operator");
712e2207522Sjmmv}
713e2207522SjmmvATF_TC_BODY(addition, tc)
714e2207522Sjmmv{
71512aa0b5aSjmmv    ATF_CHECK_EQ(0 + 0, 0);
71612aa0b5aSjmmv    ATF_CHECK_EQ(0 + 1, 1);
71712aa0b5aSjmmv    ATF_CHECK_EQ(1 + 0, 1);
718e2207522Sjmmv
71912aa0b5aSjmmv    ATF_CHECK_EQ(1 + 1, 2);
720e2207522Sjmmv
72112aa0b5aSjmmv    ATF_CHECK_EQ(100 + 200, 300);
72212aa0b5aSjmmv}
72312aa0b5aSjmmv
72412aa0b5aSjmmvATF_TC(string_formatting);
72512aa0b5aSjmmvATF_TC_HEAD(string_formatting, tc)
72612aa0b5aSjmmv{
72712aa0b5aSjmmv    atf_tc_set_md_var(tc, "descr",
72812aa0b5aSjmmv                      "Sample tests for the snprintf");
72912aa0b5aSjmmv}
73012aa0b5aSjmmvATF_TC_BODY(string_formatting, tc)
73112aa0b5aSjmmv{
73212aa0b5aSjmmv    char buf[1024];
73312aa0b5aSjmmv    snprintf(buf, sizeof(buf), "a %s", "string");
73412aa0b5aSjmmv    ATF_CHECK_STREQ_MSG("a string", buf, "%s is not working");
735e2207522Sjmmv}
736e2207522Sjmmv
737edebbb8eSjmmvATF_TC(open_failure);
738edebbb8eSjmmvATF_TC_HEAD(open_failure, tc)
739edebbb8eSjmmv{
740edebbb8eSjmmv    atf_tc_set_md_var(tc, "descr",
741edebbb8eSjmmv                      "Sample tests for the open function");
742edebbb8eSjmmv}
743edebbb8eSjmmvATF_TC_BODY(open_failure, tc)
744edebbb8eSjmmv{
745edebbb8eSjmmv    ATF_CHECK_ERRNO(ENOENT, open("non-existent", O_RDONLY) == -1);
746edebbb8eSjmmv}
747edebbb8eSjmmv
748edebbb8eSjmmvATF_TC(known_bug);
749edebbb8eSjmmvATF_TC_HEAD(known_bug, tc)
750edebbb8eSjmmv{
751edebbb8eSjmmv    atf_tc_set_md_var(tc, "descr",
752edebbb8eSjmmv                      "Reproduces a known bug");
753edebbb8eSjmmv}
754edebbb8eSjmmvATF_TC_BODY(known_bug, tc)
755edebbb8eSjmmv{
756edebbb8eSjmmv    atf_tc_expect_fail("See bug number foo/bar");
757edebbb8eSjmmv    ATF_CHECK_EQ(3, 1 + 1);
758edebbb8eSjmmv    atf_tc_expect_pass();
759edebbb8eSjmmv    ATF_CHECK_EQ(3, 1 + 2);
760edebbb8eSjmmv}
761edebbb8eSjmmv
762e2207522SjmmvATF_TP_ADD_TCS(tp)
763e2207522Sjmmv{
764e2207522Sjmmv    ATF_TP_ADD_TC(tp, addition);
76512aa0b5aSjmmv    ATF_TP_ADD_TC(tp, string_formatting);
766edebbb8eSjmmv    ATF_TP_ADD_TC(tp, open_failure);
767edebbb8eSjmmv    ATF_TP_ADD_TC(tp, known_bug);
768e2207522Sjmmv
769e2207522Sjmmv    return atf_no_error();
770e2207522Sjmmv}
771e2207522Sjmmv.Ed
772e2207522Sjmmv.Sh SEE ALSO
773e2207522Sjmmv.Xr atf-test-program 1 ,
774edebbb8eSjmmv.Xr atf-test-case 4 ,
775edebbb8eSjmmv.Xr atf 7
776