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