xref: /freebsd/contrib/atf/atf-c++/atf-c++.3 (revision cb2887746f8b9dd4ad6b1e757cdc053a08b25a2e)
1.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
2.\" All rights reserved.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions and the following disclaimer.
9.\" 2. Redistributions in binary form must reproduce the above copyright
10.\"    notice, this list of conditions and the following disclaimer in the
11.\"    documentation and/or other materials provided with the distribution.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25.Dd May 11, 2025
26.Dt ATF-C++ 3
27.Os
28.Sh NAME
29.Nm atf-c++ ,
30.Nm ATF_ADD_TEST_CASE ,
31.Nm ATF_CHECK_ERRNO ,
32.Nm ATF_FAIL ,
33.Nm ATF_INIT_TEST_CASES ,
34.Nm ATF_PASS ,
35.Nm ATF_REQUIRE ,
36.Nm ATF_REQUIRE_EQ ,
37.Nm ATF_REQUIRE_ERRNO ,
38.Nm ATF_REQUIRE_IN ,
39.Nm ATF_REQUIRE_MATCH ,
40.Nm ATF_REQUIRE_NOT_IN ,
41.Nm ATF_REQUIRE_THROW ,
42.Nm ATF_REQUIRE_THROW_RE ,
43.Nm ATF_SKIP ,
44.Nm ATF_TEST_CASE ,
45.Nm ATF_TEST_CASE_BODY ,
46.Nm ATF_TEST_CASE_CLEANUP ,
47.Nm ATF_TEST_CASE_HEAD ,
48.Nm ATF_TEST_CASE_NAME ,
49.Nm ATF_TEST_CASE_USE ,
50.Nm ATF_TEST_CASE_WITH_CLEANUP ,
51.Nm ATF_TEST_CASE_WITHOUT_HEAD ,
52.Nm atf::utils::cat_file ,
53.Nm atf::utils::compare_file ,
54.Nm atf::utils::copy_file ,
55.Nm atf::utils::create_file ,
56.Nm atf::utils::file_exists ,
57.Nm atf::utils::fork ,
58.Nm atf::utils::grep_collection ,
59.Nm atf::utils::grep_file ,
60.Nm atf::utils::grep_string ,
61.Nm atf::utils::redirect ,
62.Nm atf::utils::wait
63.Nd C++ API to write ATF-based test programs
64.Sh SYNOPSIS
65.In atf-c++.hpp
66.Fn ATF_ADD_TEST_CASE "tcs" "name"
67.Fn ATF_CHECK_ERRNO "expected_errno" "bool_expression"
68.Fn ATF_FAIL "reason"
69.Fn ATF_INIT_TEST_CASES "tcs"
70.Fn ATF_PASS
71.Fn ATF_REQUIRE "expression"
72.Fn ATF_REQUIRE_EQ "expected_expression" "actual_expression"
73.Fn ATF_REQUIRE_ERRNO "expected_errno" "bool_expression"
74.Fn ATF_REQUIRE_IN "element" "collection"
75.Fn ATF_REQUIRE_MATCH "regexp" "string_expression"
76.Fn ATF_REQUIRE_NOT_IN "element" "collection"
77.Fn ATF_REQUIRE_THROW "expected_exception" "statement"
78.Fn ATF_REQUIRE_THROW_RE "expected_exception" "regexp" "statement"
79.Fn ATF_SKIP "reason"
80.Fn ATF_TEST_CASE "name"
81.Fn ATF_TEST_CASE_BODY "name"
82.Fn ATF_TEST_CASE_CLEANUP "name"
83.Fn ATF_TEST_CASE_HEAD "name"
84.Fn ATF_TEST_CASE_NAME "name"
85.Fn ATF_TEST_CASE_USE "name"
86.Fn ATF_TEST_CASE_WITH_CLEANUP "name"
87.Fn ATF_TEST_CASE_WITHOUT_HEAD "name"
88.Ft void
89.Fo atf::utils::cat_file
90.Fa "const std::string& path"
91.Fa "const std::string& prefix"
92.Fc
93.Ft bool
94.Fo atf::utils::compare_file
95.Fa "const std::string& path"
96.Fa "const std::string& contents"
97.Fc
98.Ft void
99.Fo atf::utils::copy_file
100.Fa "const std::string& source"
101.Fa "const std::string& destination"
102.Fc
103.Ft void
104.Fo atf::utils::create_file
105.Fa "const std::string& path"
106.Fa "const std::string& contents"
107.Fc
108.Ft void
109.Fo atf::utils::file_exists
110.Fa "const std::string& path"
111.Fc
112.Ft pid_t
113.Fo atf::utils::fork
114.Fa "void"
115.Fc
116.Ft bool
117.Fo atf::utils::grep_collection
118.Fa "const std::string& regexp"
119.Fa "const Collection& collection"
120.Fc
121.Ft bool
122.Fo atf::utils::grep_file
123.Fa "const std::string& regexp"
124.Fa "const std::string& path"
125.Fc
126.Ft bool
127.Fo atf::utils::grep_string
128.Fa "const std::string& regexp"
129.Fa "const std::string& path"
130.Fc
131.Ft void
132.Fo atf::utils::redirect
133.Fa "const int fd"
134.Fa "const std::string& path"
135.Fc
136.Ft void
137.Fo atf::utils::wait
138.Fa "const pid_t pid"
139.Fa "const int expected_exit_status"
140.Fa "const std::string& expected_stdout"
141.Fa "const std::string& expected_stderr"
142.Fc
143.Sh DESCRIPTION
144ATF provides a C++ programming interface to implement test programs.
145C++-based test programs follow this template:
146.Bd -literal -offset indent
147extern "C" {
148\&... C-specific includes go here ...
149}
150
151\&... C++-specific includes go here ...
152
153#include <atf-c++.hpp>
154
155ATF_TEST_CASE(tc1);
156ATF_TEST_CASE_HEAD(tc1)
157{
158    ... first test case's header ...
159}
160ATF_TEST_CASE_BODY(tc1)
161{
162    ... first test case's body ...
163}
164
165ATF_TEST_CASE_WITH_CLEANUP(tc2);
166ATF_TEST_CASE_HEAD(tc2)
167{
168    ... second test case's header ...
169}
170ATF_TEST_CASE_BODY(tc2)
171{
172    ... second test case's body ...
173}
174ATF_TEST_CASE_CLEANUP(tc2)
175{
176    ... second test case's cleanup ...
177}
178
179ATF_TEST_CASE(tc3);
180ATF_TEST_CASE_BODY(tc3)
181{
182    ... third test case's body ...
183}
184
185\&... additional test cases ...
186
187ATF_INIT_TEST_CASES(tcs)
188{
189    ATF_ADD_TEST_CASE(tcs, tc1);
190    ATF_ADD_TEST_CASE(tcs, tc2);
191    ATF_ADD_TEST_CASE(tcs, tc3);
192    ... add additional test cases ...
193}
194.Ed
195.Ss Definition of test cases
196Test cases have an identifier and are composed of three different parts:
197the header, the body and an optional cleanup routine, all of which are
198described in
199.Xr atf-test-case 4 .
200To define test cases, one can use the
201.Fn ATF_TEST_CASE ,
202.Fn ATF_TEST_CASE_WITH_CLEANUP
203or the
204.Fn ATF_TEST_CASE_WITHOUT_HEAD
205macros, which take a single parameter specifying the test case's
206name.
207.Fn ATF_TEST_CASE ,
208requires to define a head and a body for the test case,
209.Fn ATF_TEST_CASE_WITH_CLEANUP
210requires to define a head, a body and a cleanup for the test case and
211.Fn ATF_TEST_CASE_WITHOUT_HEAD
212requires only a body for the test case.
213It is important to note that these
214.Em do not
215set the test case up for execution when the program is run.
216In order to do so, a later registration is needed through the
217.Fn ATF_ADD_TEST_CASE
218macro detailed in
219.Sx Program initialization .
220.Pp
221Later on, one must define the three parts of the body by means of three
222functions.
223Their headers are given by the
224.Fn ATF_TEST_CASE_HEAD ,
225.Fn ATF_TEST_CASE_BODY
226and
227.Fn ATF_TEST_CASE_CLEANUP
228macros, all of which take the test case's name.
229Following each of these, a block of code is expected, surrounded by the
230opening and closing brackets.
231.Pp
232Additionally, the
233.Fn ATF_TEST_CASE_NAME
234macro can be used to obtain the name of the class corresponding to a
235particular test case, as the name is internally managed by the library to
236prevent clashes with other user identifiers.
237Similarly, the
238.Fn ATF_TEST_CASE_USE
239macro can be executed on a particular test case to mark it as "used" and
240thus prevent compiler warnings regarding unused symbols.
241Note that
242.Em you should never have to use these macros during regular operation.
243.Ss Program initialization
244The library provides a way to easily define the test program's
245.Fn main
246function.
247You should never define one on your own, but rely on the
248library to do it for you.
249This is done by using the
250.Fn ATF_INIT_TEST_CASES
251macro, which is passed the name of the list that will hold the test cases.
252This name can be whatever you want as long as it is a valid variable value.
253.Pp
254After the macro, you are supposed to provide the body of a function, which
255should only use the
256.Fn ATF_ADD_TEST_CASE
257macro to register the test cases the test program will execute.
258The first parameter of this macro matches the name you provided in the
259former call.
260.Ss Header definitions
261The test case's header can define the meta-data by using the
262.Fn set_md_var
263method, which takes two parameters: the first one specifies the
264meta-data variable to be set and the second one specifies its value.
265Both of them are strings.
266.Ss Configuration variables
267The test case has read-only access to the current configuration variables
268by means of the
269.Ft bool
270.Fn has_config_var
271and the
272.Ft std::string
273.Fn get_config_var
274methods, which can be called in any of the three parts of a test case.
275.Ss Access to the source directory
276It is possible to get the path to the test case's source directory from any
277of its three components by querying the
278.Sq srcdir
279configuration variable.
280.Ss Requiring kernel modules
281Aside from the
282.Va require.kmods
283meta-data variable available in the header only, one can also check for
284additional kernel modules in the test case's body by using the
285.Fn require_kmod
286function, which takes the name of a single module.
287If it is not found, the test case will be automatically skipped.
288.Ss Requiring programs
289Aside from the
290.Va require.progs
291meta-data variable available in the header only, one can also check for
292additional programs in the test case's body by using the
293.Fn require_prog
294function, which takes the base name or full path of a single binary.
295Relative paths are forbidden.
296If it is not found, the test case will be automatically skipped.
297.Ss Test case finalization
298The test case finalizes either when the body reaches its end, at which
299point the test is assumed to have
300.Em passed ,
301or at any explicit call to
302.Fn ATF_PASS ,
303.Fn ATF_FAIL
304or
305.Fn ATF_SKIP .
306These three macros terminate the execution of the test case immediately.
307The cleanup routine will be processed afterwards in a completely automated
308way, regardless of the test case's termination reason.
309.Pp
310.Fn ATF_PASS
311does not take any parameters.
312.Fn ATF_FAIL
313and
314.Fn ATF_SKIP
315take a single string that describes why the test case failed or
316was skipped, respectively.
317It is very important to provide a clear error message in both cases so that
318the user can quickly know why the test did not pass.
319.Ss Expectations
320Everything explained in the previous section changes when the test case
321expectations are redefined by the programmer.
322.Pp
323Each test case has an internal state called
324.Sq expect
325that describes what the test case expectations are at any point in time.
326The value of this property can change during execution by any of:
327.Bl -tag -width indent
328.It Fn expect_death "reason"
329Expects the test case to exit prematurely regardless of the nature of the
330exit.
331.It Fn expect_exit "exitcode" "reason"
332Expects the test case to exit cleanly.
333If
334.Va exitcode
335is not
336.Sq -1 ,
337the runtime engine will validate that the exit code of the test case
338matches the one provided in this call.
339Otherwise, the exact value will be ignored.
340.It Fn expect_fail "reason"
341Any failure (be it fatal or non-fatal) raised in this mode is recorded.
342However, such failures do not report the test case as failed; instead, the
343test case finalizes cleanly and is reported as
344.Sq expected failure ;
345this report includes the provided
346.Fa reason
347as part of it.
348If no error is raised while running in this mode, then the test case is
349reported as
350.Sq failed .
351.Pp
352This mode is useful to reproduce actual known bugs in tests.
353Whenever the developer fixes the bug later on, the test case will start
354reporting a failure, signaling the developer that the test case must be
355adjusted to the new conditions.
356In this situation, it is useful, for example, to set
357.Fa reason
358as the bug number for tracking purposes.
359.It Fn expect_pass
360This is the normal mode of execution.
361In this mode, any failure is reported as such to the user and the test case
362is marked as
363.Sq failed .
364.It Fn expect_race "reason"
365Any failure or timeout during the execution of the test case will be
366considered as if a race condition has been triggered and reported as such.
367If no problems arise, the test will continue execution as usual.
368.It Fn expect_signal "signo" "reason"
369Expects the test case to terminate due to the reception of a signal.
370If
371.Va signo
372is not
373.Sq -1 ,
374the runtime engine will validate that the signal that terminated the test
375case matches the one provided in this call.
376Otherwise, the exact value will be ignored.
377.It Fn expect_timeout "reason"
378Expects the test case to execute for longer than its timeout.
379.El
380.Ss Helper macros for common checks
381The library provides several macros that are very handy in multiple
382situations.
383These basically check some condition after executing a given statement or
384processing a given expression and, if the condition is not met, they
385automatically call
386.Fn ATF_FAIL
387with an appropriate error message.
388.Pp
389.Fn ATF_REQUIRE
390takes an expression and raises a failure if it evaluates to false.
391.Pp
392.Fn ATF_REQUIRE_EQ
393takes two expressions and raises a failure if the two do not evaluate to
394the same exact value.
395The common style is to put the expected value in the first parameter and the
396actual value in the second parameter.
397.Pp
398.Fn ATF_REQUIRE_IN
399takes an element and a collection and validates that the element is present in
400the collection.
401.Pp
402.Fn ATF_REQUIRE_MATCH
403takes a regular expression and a string and raises a failure if the regular
404expression does not match the string.
405.Pp
406.Fn ATF_REQUIRE_NOT_IN
407takes an element and a collection and validates that the element is not present
408in the collection.
409.Pp
410.Fn ATF_REQUIRE_THROW
411takes the name of an exception and a statement and raises a failure if
412the statement does not throw the specified exception.
413.Fn ATF_REQUIRE_THROW_RE
414takes the name of an exception, a regular expression and a statement, and raises
415a failure if the statement does not throw the specified exception and if the
416message of the exception does not match the regular expression.
417.Pp
418.Fn ATF_CHECK_ERRNO
419and
420.Fn ATF_REQUIRE_ERRNO
421take, first, the error code that the check is expecting to find in the
422.Va errno
423variable and, second, a boolean expression that, if evaluates to true,
424means that a call failed and
425.Va errno
426has to be checked against the first value.
427.Ss Utility functions
428The following functions are provided as part of the
429.Nm
430API to simplify the creation of a variety of tests.
431In particular, these are useful to write tests for command-line interfaces.
432.Pp
433.Ft void
434.Fo atf::utils::cat_file
435.Fa "const std::string& path"
436.Fa "const std::string& prefix"
437.Fc
438.Bd -ragged -offset indent
439Prints the contents of
440.Fa path
441to the standard output, prefixing every line with the string in
442.Fa prefix .
443.Ed
444.Pp
445.Ft bool
446.Fo atf::utils::compare_file
447.Fa "const std::string& path"
448.Fa "const std::string& contents"
449.Fc
450.Bd -ragged -offset indent
451Returns true if the given
452.Fa path
453matches exactly the expected inlined
454.Fa contents .
455.Ed
456.Pp
457.Ft void
458.Fo atf::utils::copy_file
459.Fa "const std::string& source"
460.Fa "const std::string& destination"
461.Fc
462.Bd -ragged -offset indent
463Copies the file
464.Fa source
465to
466.Fa destination .
467The permissions of the file are preserved during the code.
468.Ed
469.Pp
470.Ft void
471.Fo atf::utils::create_file
472.Fa "const std::string& path"
473.Fa "const std::string& contents"
474.Fc
475.Bd -ragged -offset indent
476Creates
477.Fa file
478with the text given in
479.Fa contents .
480.Ed
481.Pp
482.Ft void
483.Fo atf::utils::file_exists
484.Fa "const std::string& path"
485.Fc
486.Bd -ragged -offset indent
487Checks if
488.Fa path
489exists.
490.Ed
491.Pp
492.Ft pid_t
493.Fo atf::utils::fork
494.Fa "void"
495.Fc
496.Bd -ragged -offset indent
497Forks a process and redirects the standard output and standard error of the
498child to files for later validation with
499.Fn atf::utils::wait .
500Fails the test case if the fork fails, so this does not return an error.
501.Ed
502.Pp
503.Ft bool
504.Fo atf::utils::grep_collection
505.Fa "const std::string& regexp"
506.Fa "const Collection& collection"
507.Fc
508.Bd -ragged -offset indent
509Searches for the regular expression
510.Fa regexp
511in any of the strings contained in the
512.Fa collection .
513This is a template that accepts any one-dimensional container of strings.
514.Ed
515.Pp
516.Ft bool
517.Fo atf::utils::grep_file
518.Fa "const std::string& regexp"
519.Fa "const std::string& path"
520.Fc
521.Bd -ragged -offset indent
522Searches for the regular expression
523.Fa regexp
524in the file
525.Fa path .
526The variable arguments are used to construct the regular expression.
527.Ed
528.Pp
529.Ft bool
530.Fo atf::utils::grep_string
531.Fa "const std::string& regexp"
532.Fa "const std::string& str"
533.Fc
534.Bd -ragged -offset indent
535Searches for the regular expression
536.Fa regexp
537in the string
538.Fa str .
539.Ed
540.Ft void
541.Fo atf::utils::redirect
542.Fa "const int fd"
543.Fa "const std::string& path"
544.Fc
545.Bd -ragged -offset indent
546Redirects the given file descriptor
547.Fa fd
548to the file
549.Fa path .
550This function exits the process in case of an error and does not properly mark
551the test case as failed.
552As a result, it should only be used in subprocesses of the test case; specially
553those spawned by
554.Fn atf::utils::fork .
555.Ed
556.Pp
557.Ft void
558.Fo atf::utils::wait
559.Fa "const pid_t pid"
560.Fa "const int expected_exit_status"
561.Fa "const std::string& expected_stdout"
562.Fa "const std::string& expected_stderr"
563.Fc
564.Bd -ragged -offset indent
565Waits and validates the result of a subprocess spawned with
566.Fn atf::utils::wait .
567The validation involves checking that the subprocess exited cleanly and returned
568the code specified in
569.Fa expected_exit_status
570and that its standard output and standard error match the strings given in
571.Fa expected_stdout
572and
573.Fa expected_stderr .
574.Pp
575If any of the
576.Fa expected_stdout
577or
578.Fa expected_stderr
579strings are prefixed with
580.Sq save: ,
581then they specify the name of the file into which to store the stdout or stderr
582of the subprocess, and no comparison is performed.
583.Ed
584.Sh ENVIRONMENT
585The following variables are recognized by
586.Nm
587but should not be overridden other than for testing purposes:
588.Pp
589.Bl -tag -width ATFXBUILDXCXXFLAGSXX -compact
590.It Va ATF_BUILD_CC
591Path to the C compiler.
592.It Va ATF_BUILD_CFLAGS
593C compiler flags.
594.It Va ATF_BUILD_CPP
595Path to the C/C++ preprocessor.
596.It Va ATF_BUILD_CPPFLAGS
597C/C++ preprocessor flags.
598.It Va ATF_BUILD_CXX
599Path to the C++ compiler.
600.It Va ATF_BUILD_CXXFLAGS
601C++ compiler flags.
602.El
603.Sh EXAMPLES
604The following shows a complete test program with a single test case that
605validates the addition operator:
606.Bd -literal -offset indent
607#include <atf-c++.hpp>
608
609ATF_TEST_CASE(addition);
610ATF_TEST_CASE_HEAD(addition)
611{
612    set_md_var("descr", "Sample tests for the addition operator");
613}
614ATF_TEST_CASE_BODY(addition)
615{
616    ATF_REQUIRE_EQ(0, 0 + 0);
617    ATF_REQUIRE_EQ(1, 0 + 1);
618    ATF_REQUIRE_EQ(1, 1 + 0);
619
620    ATF_REQUIRE_EQ(2, 1 + 1);
621
622    ATF_REQUIRE_EQ(300, 100 + 200);
623}
624
625ATF_TEST_CASE(open_failure);
626ATF_TEST_CASE_HEAD(open_failure)
627{
628    set_md_var("descr", "Sample tests for the open function");
629}
630ATF_TEST_CASE_BODY(open_failure)
631{
632    ATF_REQUIRE_ERRNO(ENOENT, open("non-existent", O_RDONLY) == -1);
633}
634
635ATF_TEST_CASE(known_bug);
636ATF_TEST_CASE_HEAD(known_bug)
637{
638    set_md_var("descr", "Reproduces a known bug");
639}
640ATF_TEST_CASE_BODY(known_bug)
641{
642    expect_fail("See bug number foo/bar");
643    ATF_REQUIRE_EQ(3, 1 + 1);
644    expect_pass();
645    ATF_REQUIRE_EQ(3, 1 + 2);
646}
647
648ATF_INIT_TEST_CASES(tcs)
649{
650    ATF_ADD_TEST_CASE(tcs, addition);
651    ATF_ADD_TEST_CASE(tcs, open_failure);
652    ATF_ADD_TEST_CASE(tcs, known_bug);
653}
654.Ed
655.Sh SEE ALSO
656.Xr atf-test-program 1 ,
657.Xr atf-test-case 4
658