diff options
author | jmmv <jmmv@FreeBSD.org> | 2013-11-17 23:51:19 +0000 |
---|---|---|
committer | jmmv <jmmv@FreeBSD.org> | 2013-11-17 23:51:19 +0000 |
commit | 8c7e11817a76331c10afb89d609a304c49dd588b (patch) | |
tree | e69b0ffecc81ada4e0d39442aa0f39a4abc93806 /contrib/atf/atf-c | |
parent | a21ab9564f9972a893699a0178df90fd60e11b47 (diff) | |
parent | b849e3606cf0dc725ff02712cd92907131c0188c (diff) | |
download | FreeBSD-src-8c7e11817a76331c10afb89d609a304c49dd588b.zip FreeBSD-src-8c7e11817a76331c10afb89d609a304c49dd588b.tar.gz |
MFV: Import atf-0.18.
Approved by: rpaulo (mentor)
Diffstat (limited to 'contrib/atf/atf-c')
-rw-r--r-- | contrib/atf/atf-c/Makefile.am.inc | 157 | ||||
-rw-r--r-- | contrib/atf/atf-c/atf-c-api.3 | 277 | ||||
-rw-r--r-- | contrib/atf/atf-c/check_test.c | 50 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/Atffile | 1 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/Kyuafile | 1 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/Makefile.am.inc | 104 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/process_test.c | 40 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/sanity_test.c | 40 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/test_helpers.c | 67 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/test_helpers.h | 2 | ||||
-rw-r--r-- | contrib/atf/atf-c/detail/test_helpers_test.c | 185 | ||||
-rw-r--r-- | contrib/atf/atf-c/macros.h | 20 | ||||
-rw-r--r-- | contrib/atf/atf-c/macros_test.c | 154 | ||||
-rw-r--r-- | contrib/atf/atf-c/pkg_config_test.sh | 2 | ||||
-rw-r--r-- | contrib/atf/atf-c/utils.c | 374 | ||||
-rw-r--r-- | contrib/atf/atf-c/utils.h | 19 | ||||
-rw-r--r-- | contrib/atf/atf-c/utils_test.c | 480 |
17 files changed, 1332 insertions, 641 deletions
diff --git a/contrib/atf/atf-c/Makefile.am.inc b/contrib/atf/atf-c/Makefile.am.inc deleted file mode 100644 index b813ec4..0000000 --- a/contrib/atf/atf-c/Makefile.am.inc +++ /dev/null @@ -1,157 +0,0 @@ -# -# Automated Testing Framework (atf) -# -# Copyright (c) 2007 The NetBSD Foundation, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -lib_LTLIBRARIES += libatf-c.la -libatf_c_la_SOURCES = atf-c/build.c \ - atf-c/build.h \ - atf-c/check.c \ - atf-c/check.h \ - atf-c/config.c \ - atf-c/config.h \ - atf-c/error.c \ - atf-c/error.h \ - atf-c/error_fwd.h \ - atf-c/macros.h \ - atf-c/tc.c \ - atf-c/tc.h \ - atf-c/tp.c \ - atf-c/tp.h \ - atf-c/utils.c \ - atf-c/utils.h -nodist_libatf_c_la_SOURCES = atf-c/defs.h -libatf_c_la_CPPFLAGS = "-DATF_ARCH=\"$(atf_arch)\"" \ - "-DATF_BUILD_CC=\"$(ATF_BUILD_CC)\"" \ - "-DATF_BUILD_CFLAGS=\"$(ATF_BUILD_CFLAGS)\"" \ - "-DATF_BUILD_CPP=\"$(ATF_BUILD_CPP)\"" \ - "-DATF_BUILD_CPPFLAGS=\"$(ATF_BUILD_CPPFLAGS)\"" \ - "-DATF_BUILD_CXX=\"$(ATF_BUILD_CXX)\"" \ - "-DATF_BUILD_CXXFLAGS=\"$(ATF_BUILD_CXXFLAGS)\"" \ - "-DATF_CONFDIR=\"$(atf_confdir)\"" \ - "-DATF_INCLUDEDIR=\"$(includedir)\"" \ - "-DATF_LIBDIR=\"$(libdir)\"" \ - "-DATF_LIBEXECDIR=\"$(libexecdir)\"" \ - "-DATF_MACHINE=\"$(atf_machine)\"" \ - "-DATF_M4=\"$(ATF_M4)\"" \ - "-DATF_PKGDATADIR=\"$(pkgdatadir)\"" \ - "-DATF_SHELL=\"$(ATF_SHELL)\"" \ - "-DATF_WORKDIR=\"$(ATF_WORKDIR)\"" \ - -I$(srcdir)/atf-c -libatf_c_la_LDFLAGS = -version-info 0:0:0 - -# XXX For some reason, the nodist line above does not work as expected. -# Work this problem around. -dist-hook: kill-defs-h -kill-defs-h: - rm -f $(distdir)/atf-c/defs.h - -include_HEADERS += atf-c.h -atf_c_HEADERS = atf-c/build.h \ - atf-c/check.h \ - atf-c/config.h \ - atf-c/defs.h \ - atf-c/error.h \ - atf-c/error_fwd.h \ - atf-c/macros.h \ - atf-c/tc.h \ - atf-c/tp.h \ - atf-c/utils.h -atf_cdir = $(includedir)/atf-c - -dist_man_MANS += atf-c/atf-c-api.3 - -atf_aclocal_DATA += atf-c/atf-common.m4 atf-c/atf-c.m4 -EXTRA_DIST += atf-c/atf-common.m4 atf-c/atf-c.m4 - -atf_cpkgconfigdir = $(atf_pkgconfigdir) -atf_cpkgconfig_DATA = atf-c/atf-c.pc -CLEANFILES += atf-c/atf-c.pc -EXTRA_DIST += atf-c/atf-c.pc.in -atf-c/atf-c.pc: $(srcdir)/atf-c/atf-c.pc.in Makefile - test -d atf-c || mkdir -p atf-c - sed -e 's#__ATF_VERSION__#$(PACKAGE_VERSION)#g' \ - -e 's#__CC__#$(CC)#g' \ - -e 's#__INCLUDEDIR__#$(includedir)#g' \ - -e 's#__LIBDIR__#$(libdir)#g' \ - <$(srcdir)/atf-c/atf-c.pc.in >atf-c/atf-c.pc.tmp - mv atf-c/atf-c.pc.tmp atf-c/atf-c.pc - -tests_atf_c_DATA = atf-c/Atffile \ - atf-c/Kyuafile \ - atf-c/macros_h_test.c \ - atf-c/unused_test.c -tests_atf_cdir = $(pkgtestsdir)/atf-c -EXTRA_DIST += $(tests_atf_c_DATA) - -tests_atf_c_PROGRAMS = atf-c/atf_c_test -atf_c_atf_c_test_SOURCES = atf-c/atf_c_test.c -atf_c_atf_c_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/build_test -atf_c_build_test_SOURCES = atf-c/build_test.c atf-c/h_build.h -atf_c_build_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/check_test -atf_c_check_test_SOURCES = atf-c/check_test.c -atf_c_check_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/config_test -atf_c_config_test_SOURCES = atf-c/config_test.c -atf_c_config_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/error_test -atf_c_error_test_SOURCES = atf-c/error_test.c -atf_c_error_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/macros_test -atf_c_macros_test_SOURCES = atf-c/macros_test.c -atf_c_macros_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_SCRIPTS = atf-c/pkg_config_test -CLEANFILES += atf-c/pkg_config_test -EXTRA_DIST += atf-c/pkg_config_test.sh -atf-c/pkg_config_test: $(srcdir)/atf-c/pkg_config_test.sh - test -d atf-c || mkdir -p atf-c - @src="$(srcdir)/atf-c/pkg_config_test.sh"; \ - dst="atf-c/pkg_config_test"; $(BUILD_SH_TP) - -tests_atf_c_PROGRAMS += atf-c/tc_test -atf_c_tc_test_SOURCES = atf-c/tc_test.c -atf_c_tc_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/tp_test -atf_c_tp_test_SOURCES = atf-c/tp_test.c -atf_c_tp_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_PROGRAMS += atf-c/utils_test -atf_c_utils_test_SOURCES = atf-c/utils_test.c atf-c/h_build.h -atf_c_utils_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -include atf-c/detail/Makefile.am.inc - -# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8 diff --git a/contrib/atf/atf-c/atf-c-api.3 b/contrib/atf/atf-c/atf-c-api.3 index 548db4f..366caec 100644 --- a/contrib/atf/atf-c/atf-c-api.3 +++ b/contrib/atf/atf-c/atf-c-api.3 @@ -26,14 +26,17 @@ .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd December 26, 2010 +.Dd November 15, 2013 .Dt ATF-C-API 3 .Os .Sh NAME +.Nm atf-c-api , .Nm ATF_CHECK , .Nm ATF_CHECK_MSG , .Nm ATF_CHECK_EQ , .Nm ATF_CHECK_EQ_MSG , +.Nm ATF_CHECK_MATCH , +.Nm ATF_CHECK_MATCH_MSG , .Nm ATF_CHECK_STREQ , .Nm ATF_CHECK_STREQ_MSG , .Nm ATF_CHECK_ERRNO , @@ -41,6 +44,8 @@ .Nm ATF_REQUIRE_MSG , .Nm ATF_REQUIRE_EQ , .Nm ATF_REQUIRE_EQ_MSG , +.Nm ATF_REQUIRE_MATCH , +.Nm ATF_REQUIRE_MATCH_MSG , .Nm ATF_REQUIRE_STREQ , .Nm ATF_REQUIRE_STREQ_MSG , .Nm ATF_REQUIRE_ERRNO , @@ -72,7 +77,19 @@ .Nm atf_tc_fail , .Nm atf_tc_fail_nonfatal , .Nm atf_tc_pass , -.Nm atf_tc_skip +.Nm atf_tc_skip , +.Nm atf_utils_cat_file , +.Nm atf_utils_compare_file , +.Nm atf_utils_copy_file , +.Nm atf_utils_create_file , +.Nm atf_utils_file_exists , +.Nm atf_utils_fork , +.Nm atf_utils_free_charpp , +.Nm atf_utils_grep_file , +.Nm atf_utils_grep_string , +.Nm atf_utils_readline , +.Nm atf_utils_redirect , +.Nm atf_utils_wait .Nd C API to write ATF-based test programs .Sh SYNOPSIS .In atf-c.h @@ -80,6 +97,8 @@ .Fn ATF_CHECK_MSG "expression" "fail_msg_fmt" ... .Fn ATF_CHECK_EQ "expression_1" "expression_2" .Fn ATF_CHECK_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ... +.Fn ATF_CHECK_MATCH "regexp" "string" +.Fn ATF_CHECK_MATCH_MSG "regexp" "string" "fail_msg_fmt" ... .Fn ATF_CHECK_STREQ "string_1" "string_2" .Fn ATF_CHECK_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ... .Fn ATF_CHECK_ERRNO "exp_errno" "bool_expression" @@ -87,6 +106,8 @@ .Fn ATF_REQUIRE_MSG "expression" "fail_msg_fmt" ... .Fn ATF_REQUIRE_EQ "expression_1" "expression_2" .Fn ATF_REQUIRE_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ... +.Fn ATF_REQUIRE_MATCH "regexp" "string" +.Fn ATF_REQUIRE_MATCH_MSG "regexp" "string" "fail_msg_fmt" ... .Fn ATF_REQUIRE_STREQ "string_1" "string_2" .Fn ATF_REQUIRE_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ... .Fn ATF_REQUIRE_ERRNO "exp_errno" "bool_expression" @@ -119,10 +140,70 @@ .Fn atf_tc_fail_nonfatal "reason" .Fn atf_tc_pass .Fn atf_tc_skip "reason" +.Ft void +.Fo atf_utils_cat_file +.Fa "const char *file" +.Fa "const char *prefix" +.Fc +.Ft bool +.Fo atf_utils_compare_file +.Fa "const char *file" +.Fa "const char *contents" +.Fc +.Ft void +.Fo atf_utils_copy_file +.Fa "const char *source" +.Fa "const char *destination" +.Fc +.Ft void +.Fo atf_utils_create_file +.Fa "const char *file" +.Fa "const char *contents" +.Fa "..." +.Fc +.Ft void +.Fo atf_utils_file_exists +.Fa "const char *file" +.Fc +.Ft pid_t +.Fo atf_utils_fork +.Fa "void" +.Fc +.Ft void +.Fo atf_utils_free_charpp +.Fa "char **argv" +.Fc +.Ft bool +.Fo atf_utils_grep_file +.Fa "const char *regexp" +.Fa "const char *file" +.Fa "..." +.Fc +.Ft bool +.Fo atf_utils_grep_string +.Fa "const char *regexp" +.Fa "const char *str" +.Fa "..." +.Fc +.Ft char * +.Fo atf_utils_readline +.Fa "int fd" +.Fc +.Ft void +.Fo atf_utils_redirect +.Fa "const int fd" +.Fa "const char *file" +.Fc +.Ft void +.Fo atf_utils_wait +.Fa "const pid_t pid" +.Fa "const int expected_exit_status" +.Fa "const char *expected_stdout" +.Fa "const char *expected_stderr" +.Fc .Sh DESCRIPTION -The ATF -.Pp -C-based test programs always follow this template: +ATF provides a C programming interface to implement test programs. +C-based test programs follow this template: .Bd -literal -offset indent .Ns ... C-specific includes go here ... @@ -382,7 +463,7 @@ variant of the macros immediately abort the test case as soon as an error condition is detected by calling the .Fn atf_tc_fail function. -Use this variant whenever it makes now sense to continue the execution of a +Use this variant whenever it makes no sense to continue the execution of a test case when the checked condition is not met. The .Sq CHECK @@ -417,6 +498,16 @@ and .Fn ATF_REQUIRE_EQ_MSG take two expressions and fail if the two evaluated values are not equal. .Pp +.Fn ATF_CHECK_MATCH , +.Fn ATF_CHECK_MATCH_MSG , +.Fn ATF_REQUIRE_MATCH +and +.Fn ATF_REQUIRE_MATCH_MSG +take a regular expression and a string and fail if the regular expression does +not match the given string. +Note that the regular expression is not anchored, so it will match anywhere in +the string. +.Pp .Fn ATF_CHECK_STREQ , .Fn ATF_CHECK_STREQ_MSG , .Fn ATF_REQUIRE_STREQ @@ -433,6 +524,180 @@ variable and, second, a boolean expression that, if evaluates to true, means that a call failed and .Va errno has to be checked against the first value. +.Ss Utility functions +The following functions are provided as part of the +.Nm +API to simplify the creation of a variety of tests. +In particular, these are useful to write tests for command-line interfaces. +.Pp +.Ft void +.Fo atf_utils_cat_file +.Fa "const char *file" +.Fa "const char *prefix" +.Fc +.Bd -ragged -offset indent +Prints the contents of +.Fa file +to the standard output, prefixing every line with the string in +.Fa prefix . +.Ed +.Pp +.Ft bool +.Fo atf_utils_compare_file +.Fa "const char *file" +.Fa "const char *contents" +.Fc +.Bd -ragged -offset indent +Returns true if the given +.Fa file +matches exactly the expected inlined +.Fa contents . +.Ed +.Pp +.Ft void +.Fo atf_utils_copy_file +.Fa "const char *source" +.Fa "const char *destination" +.Fc +.Bd -ragged -offset indent +Copies the file +.Fa source +to +.Fa destination . +The permissions of the file are preserved during the code. +.Ed +.Pp +.Ft void +.Fo atf_utils_create_file +.Fa "const char *file" +.Fa "const char *contents" +.Fa "..." +.Fc +.Bd -ragged -offset indent +Creates +.Fa file +with the text given in +.Fa contents , +which is a formatting string that uses the rest of the variable arguments. +.Ed +.Pp +.Ft void +.Fo atf_utils_file_exists +.Fa "const char *file" +.Fc +.Bd -ragged -offset indent +Checks if +.Fa file +exists. +.Ed +.Pp +.Ft pid_t +.Fo atf_utils_fork +.Fa "void" +.Fc +.Bd -ragged -offset indent +Forks a process and redirects the standard output and standard error of the +child to files for later validation with +.Fn atf_utils_wait . +Fails the test case if the fork fails, so this does not return an error. +.Ed +.Pp +.Ft void +.Fo atf_utils_free_charpp +.Fa "char **argv" +.Fc +.Bd -ragged -offset indent +Frees a dynamically-allocated array of dynamically-allocated strings. +.Ed +.Pp +.Ft bool +.Fo atf_utils_grep_file +.Fa "const char *regexp" +.Fa "const char *file" +.Fa "..." +.Fc +.Bd -ragged -offset indent +Searches for the +.Fa regexp , +which is a formatting string representing the regular expression, +in the +.Fa file . +The variable arguments are used to construct the regular expression. +.Ed +.Pp +.Ft bool +.Fo atf_utils_grep_string +.Fa "const char *regexp" +.Fa "const char *str" +.Fa "..." +.Fc +.Bd -ragged -offset indent +Searches for the +.Fa regexp , +which is a formatting string representing the regular expression, +in the literal string +.Fa str . +The variable arguments are used to construct the regular expression. +.Ed +.Pp +.Ft char * +.Fo atf_utils_readline +.Fa "int fd" +.Fc +.Bd -ragged -offset indent +Reads a line from the file descriptor +.Fa fd . +The line, if any, is returned as a dynamically-allocated buffer that must be +released with +.Xr free 3 . +If there was nothing to read, returns +.Sq NULL . +.Ed +.Pp +.Ft void +.Fo atf_utils_redirect +.Fa "const int fd" +.Fa "const char *file" +.Fc +.Bd -ragged -offset indent +Redirects the given file descriptor +.Fa fd +to +.Fa file . +This function exits the process in case of an error and does not properly mark +the test case as failed. +As a result, it should only be used in subprocesses of the test case; specially +those spawned by +.Fn atf_utils_fork . +.Ed +.Pp +.Ft void +.Fo atf_utils_wait +.Fa "const pid_t pid" +.Fa "const int expected_exit_status" +.Fa "const char *expected_stdout" +.Fa "const char *expected_stderr" +.Fc +.Bd -ragged -offset indent +Waits and validates the result of a subprocess spawned with +.Fn atf_utils_wait . +The validation involves checking that the subprocess exited cleanly and returned +the code specified in +.Fa expected_exit_status +and that its standard output and standard error match the strings given in +.Fa expected_stdout +and +.Fa expected_stderr . +.Pp +If any of the +.Fa expected_stdout +or +.Fa expected_stderr +strings are prefixed with +.Sq save: , +then they specify the name of the file into which to store the stdout or stderr +of the subprocess, and no comparison is performed. +.Ed .Sh EXAMPLES The following shows a complete test program with a single test case that validates the addition operator: diff --git a/contrib/atf/atf-c/check_test.c b/contrib/atf/atf-c/check_test.c index b36dd73..a26e032 100644 --- a/contrib/atf/atf-c/check_test.c +++ b/contrib/atf/atf-c/check_test.c @@ -90,14 +90,10 @@ static void check_line(int fd, const char *exp) { - atf_dynstr_t line; - - atf_dynstr_init(&line); - ATF_CHECK(!read_line(fd, &line)); - ATF_CHECK_MSG(atf_equal_dynstr_cstring(&line, exp), - "read: '%s', expected: '%s'", - atf_dynstr_cstring(&line), exp); - atf_dynstr_fini(&line); + char *line = atf_utils_readline(fd); + ATF_CHECK(line != NULL); + ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp); + free(line); } /* --------------------------------------------------------------------- @@ -246,15 +242,15 @@ ATF_TC_BODY(build_c_o, tc) { init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_ok), &ATF_TC_PACK_NAME(h_build_c_o_ok), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o test.o")); - ATF_CHECK(grep_file("stdout", "-c test.c")); + ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout")); + ATF_CHECK(atf_utils_grep_file("-c test.c", "stdout")); init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_fail), &ATF_TC_PACK_NAME(h_build_c_o_fail), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o test.o")); - ATF_CHECK(grep_file("stdout", "-c test.c")); - ATF_CHECK(grep_file("stderr", "test.c")); - ATF_CHECK(grep_file("stderr", "UNDEFINED_SYMBOL")); + ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout")); + ATF_CHECK(atf_utils_grep_file("-c test.c", "stdout")); + ATF_CHECK(atf_utils_grep_file("test.c", "stderr")); + ATF_CHECK(atf_utils_grep_file("UNDEFINED_SYMBOL", "stderr")); } ATF_TC(build_cpp); @@ -267,16 +263,16 @@ ATF_TC_BODY(build_cpp, tc) { init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_ok), &ATF_TC_PACK_NAME(h_build_cpp_ok), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o.*test.p")); - ATF_CHECK(grep_file("stdout", "test.c")); - ATF_CHECK(grep_file("test.p", "foo bar")); + ATF_CHECK(atf_utils_grep_file("-o.*test.p", "stdout")); + ATF_CHECK(atf_utils_grep_file("test.c", "stdout")); + ATF_CHECK(atf_utils_grep_file("foo bar", "test.p")); init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_fail), &ATF_TC_PACK_NAME(h_build_cpp_fail), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o test.p")); - ATF_CHECK(grep_file("stdout", "test.c")); - ATF_CHECK(grep_file("stderr", "test.c")); - ATF_CHECK(grep_file("stderr", "non-existent.h")); + ATF_CHECK(atf_utils_grep_file("-o test.p", "stdout")); + ATF_CHECK(atf_utils_grep_file("test.c", "stdout")); + ATF_CHECK(atf_utils_grep_file("test.c", "stderr")); + ATF_CHECK(atf_utils_grep_file("non-existent.h", "stderr")); } ATF_TC(build_cxx_o); @@ -289,15 +285,15 @@ ATF_TC_BODY(build_cxx_o, tc) { init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_ok), &ATF_TC_PACK_NAME(h_build_cxx_o_ok), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o test.o")); - ATF_CHECK(grep_file("stdout", "-c test.cpp")); + ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout")); + ATF_CHECK(atf_utils_grep_file("-c test.cpp", "stdout")); init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_fail), &ATF_TC_PACK_NAME(h_build_cxx_o_fail), "stdout", "stderr"); - ATF_CHECK(grep_file("stdout", "-o test.o")); - ATF_CHECK(grep_file("stdout", "-c test.cpp")); - ATF_CHECK(grep_file("stderr", "test.cpp")); - ATF_CHECK(grep_file("stderr", "UNDEFINED_SYMBOL")); + ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout")); + ATF_CHECK(atf_utils_grep_file("-c test.cpp", "stdout")); + ATF_CHECK(atf_utils_grep_file("test.cpp", "stderr")); + ATF_CHECK(atf_utils_grep_file("UNDEFINED_SYMBOL", "stderr")); } ATF_TC(exec_array); diff --git a/contrib/atf/atf-c/detail/Atffile b/contrib/atf/atf-c/detail/Atffile index f715c98..5fd8593 100644 --- a/contrib/atf/atf-c/detail/Atffile +++ b/contrib/atf/atf-c/detail/Atffile @@ -9,6 +9,5 @@ tp: list_test tp: map_test tp: process_test tp: sanity_test -tp: test_helpers_test tp: text_test tp: user_test diff --git a/contrib/atf/atf-c/detail/Kyuafile b/contrib/atf/atf-c/detail/Kyuafile index 3f4901d..bb741da 100644 --- a/contrib/atf/atf-c/detail/Kyuafile +++ b/contrib/atf/atf-c/detail/Kyuafile @@ -9,6 +9,5 @@ atf_test_program{name="list_test"} atf_test_program{name="map_test"} atf_test_program{name="process_test"} atf_test_program{name="sanity_test"} -atf_test_program{name="test_helpers_test"} atf_test_program{name="text_test"} atf_test_program{name="user_test"} diff --git a/contrib/atf/atf-c/detail/Makefile.am.inc b/contrib/atf/atf-c/detail/Makefile.am.inc deleted file mode 100644 index d3c325b..0000000 --- a/contrib/atf/atf-c/detail/Makefile.am.inc +++ /dev/null @@ -1,104 +0,0 @@ -# -# Automated Testing Framework (atf) -# -# Copyright (c) 2007 The NetBSD Foundation, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -libatf_c_la_SOURCES += atf-c/detail/dynstr.c \ - atf-c/detail/dynstr.h \ - atf-c/detail/env.c \ - atf-c/detail/env.h \ - atf-c/detail/fs.c \ - atf-c/detail/fs.h \ - atf-c/detail/list.c \ - atf-c/detail/list.h \ - atf-c/detail/map.c \ - atf-c/detail/map.h \ - atf-c/detail/process.c \ - atf-c/detail/process.h \ - atf-c/detail/sanity.c \ - atf-c/detail/sanity.h \ - atf-c/detail/text.c \ - atf-c/detail/text.h \ - atf-c/detail/tp_main.c \ - atf-c/detail/user.c \ - atf-c/detail/user.h - -tests_atf_c_detail_DATA = atf-c/detail/Atffile \ - atf-c/detail/Kyuafile -tests_atf_c_detaildir = $(pkgtestsdir)/atf-c/detail -EXTRA_DIST += $(tests_atf_c_detail_DATA) - -noinst_LTLIBRARIES += atf-c/detail/libtest_helpers.la -atf_c_detail_libtest_helpers_la_SOURCES = atf-c/detail/test_helpers.c \ - atf-c/detail/test_helpers.h -atf_c_detail_libtest_helpers_la_CPPFLAGS = -I$(srcdir)/atf-c - -tests_atf_c_detail_PROGRAMS = atf-c/detail/dynstr_test -atf_c_detail_dynstr_test_SOURCES = atf-c/detail/dynstr_test.c -atf_c_detail_dynstr_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/env_test -atf_c_detail_env_test_SOURCES = atf-c/detail/env_test.c -atf_c_detail_env_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/fs_test -atf_c_detail_fs_test_SOURCES = atf-c/detail/fs_test.c -atf_c_detail_fs_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/test_helpers_test -atf_c_detail_test_helpers_test_SOURCES = atf-c/detail/test_helpers_test.c -atf_c_detail_test_helpers_test_LDADD = atf-c/detail/libtest_helpers.la \ - libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/list_test -atf_c_detail_list_test_SOURCES = atf-c/detail/list_test.c -atf_c_detail_list_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/map_test -atf_c_detail_map_test_SOURCES = atf-c/detail/map_test.c -atf_c_detail_map_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/process_helpers -atf_c_detail_process_helpers_SOURCES = atf-c/detail/process_helpers.c - -tests_atf_c_detail_PROGRAMS += atf-c/detail/process_test -atf_c_detail_process_test_SOURCES = atf-c/detail/process_test.c -atf_c_detail_process_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/sanity_test -atf_c_detail_sanity_test_SOURCES = atf-c/detail/sanity_test.c -atf_c_detail_sanity_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/text_test -atf_c_detail_text_test_SOURCES = atf-c/detail/text_test.c -atf_c_detail_text_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -tests_atf_c_detail_PROGRAMS += atf-c/detail/user_test -atf_c_detail_user_test_SOURCES = atf-c/detail/user_test.c -atf_c_detail_user_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la - -# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8 diff --git a/contrib/atf/atf-c/detail/process_test.c b/contrib/atf/atf-c/detail/process_test.c index 229593b..9e55f70 100644 --- a/contrib/atf/atf-c/detail/process_test.c +++ b/contrib/atf/atf-c/detail/process_test.c @@ -95,12 +95,12 @@ check_file(const enum out_type type) { switch (type) { case stdout_type: - ATF_CHECK(grep_file("stdout", "stdout: msg")); - ATF_CHECK(!grep_file("stdout", "stderr: msg")); + ATF_CHECK(atf_utils_grep_file("stdout: msg", "stdout")); + ATF_CHECK(!atf_utils_grep_file("stderr: msg", "stdout")); break; case stderr_type: - ATF_CHECK(grep_file("stderr", "stderr: msg")); - ATF_CHECK(!grep_file("stderr", "stdout: msg")); + ATF_CHECK(atf_utils_grep_file("stderr: msg", "stderr")); + ATF_CHECK(!atf_utils_grep_file("stdout: msg", "stderr")); break; default: UNREACHABLE; @@ -110,7 +110,7 @@ check_file(const enum out_type type) struct capture_stream { struct base_stream m_base; - atf_dynstr_t m_msg; + char *m_msg; }; #define CAPTURE_STREAM(type) \ { .m_base = BASE_STREAM(capture_stream_init, \ @@ -126,7 +126,7 @@ capture_stream_init(void *v) s->m_base.m_sb_ptr = &s->m_base.m_sb; RE(atf_process_stream_init_capture(&s->m_base.m_sb)); - RE(atf_dynstr_init(&s->m_msg)); + s->m_msg = NULL; } static @@ -137,10 +137,10 @@ capture_stream_process(void *v, atf_process_child_t *c) switch (s->m_base.m_type) { case stdout_type: - (void)read_line(atf_process_child_stdout(c), &s->m_msg); + s->m_msg = atf_utils_readline(atf_process_child_stdout(c)); break; case stderr_type: - (void)read_line(atf_process_child_stderr(c), &s->m_msg); + s->m_msg = atf_utils_readline(atf_process_child_stderr(c)); break; default: UNREACHABLE; @@ -155,18 +155,18 @@ capture_stream_fini(void *v) switch (s->m_base.m_type) { case stdout_type: - ATF_CHECK(grep_string(&s->m_msg, "stdout: msg")); - ATF_CHECK(!grep_string(&s->m_msg, "stderr: msg")); + ATF_CHECK(atf_utils_grep_string("stdout: msg", s->m_msg)); + ATF_CHECK(!atf_utils_grep_string("stderr: msg", s->m_msg)); break; case stderr_type: - ATF_CHECK(!grep_string(&s->m_msg, "stdout: msg")); - ATF_CHECK(grep_string(&s->m_msg, "stderr: msg")); + ATF_CHECK(!atf_utils_grep_string("stdout: msg", s->m_msg)); + ATF_CHECK(atf_utils_grep_string("stderr: msg", s->m_msg)); break; default: UNREACHABLE; } - atf_dynstr_fini(&s->m_msg); + free(s->m_msg); atf_process_stream_fini(&s->m_base.m_sb); } @@ -881,16 +881,10 @@ static void check_line(int fd, const char *exp) { - atf_dynstr_t line; - bool eof; - - atf_dynstr_init(&line); - eof = read_line(fd, &line); - ATF_CHECK(!eof); - ATF_CHECK_MSG(atf_equal_dynstr_cstring(&line, exp), - "read: '%s', expected: '%s'", - atf_dynstr_cstring(&line), exp); - atf_dynstr_fini(&line); + char *line = atf_utils_readline(fd); + ATF_CHECK(line != NULL); + ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp); + free(line); } ATF_TC(exec_failure); diff --git a/contrib/atf/atf-c/detail/sanity_test.c b/contrib/atf/atf-c/detail/sanity_test.c index af2bbc0..7c8285b 100644 --- a/contrib/atf/atf-c/detail/sanity_test.c +++ b/contrib/atf/atf-c/detail/sanity_test.c @@ -53,21 +53,6 @@ enum type { inv, pre, post, unreachable }; -static -bool -grep(const atf_dynstr_t *line, const char *text) -{ - const char *l = atf_dynstr_cstring(line); - bool found; - - found = false; - - if (strstr(l, text) != NULL) - found = true; - - return found; -} - struct test_data { enum type m_type; bool m_cond; @@ -109,9 +94,8 @@ do_test(enum type t, bool cond) { atf_process_child_t child; atf_process_status_t status; - bool eof; int nlines; - atf_dynstr_t lines[3]; + char *lines[3]; { atf_process_stream_t outsb, errsb; @@ -125,13 +109,9 @@ do_test(enum type t, bool cond) } nlines = 0; - eof = false; - do { - RE(atf_dynstr_init(&lines[nlines])); - if (!eof) - eof = read_line(atf_process_child_stderr(&child), &lines[nlines]); + while (nlines < 3 && (lines[nlines] = + atf_utils_readline(atf_process_child_stderr(&child))) != NULL) nlines++; - } while (nlines < 3); ATF_REQUIRE(nlines == 0 || nlines == 3); RE(atf_process_child_wait(&child, &status)); @@ -147,29 +127,29 @@ do_test(enum type t, bool cond) if (!cond) { switch (t) { case inv: - ATF_REQUIRE(grep(&lines[0], "Invariant")); + ATF_REQUIRE(atf_utils_grep_string("Invariant", lines[0])); break; case pre: - ATF_REQUIRE(grep(&lines[0], "Precondition")); + ATF_REQUIRE(atf_utils_grep_string("Precondition", lines[0])); break; case post: - ATF_REQUIRE(grep(&lines[0], "Postcondition")); + ATF_REQUIRE(atf_utils_grep_string("Postcondition", lines[0])); break; case unreachable: - ATF_REQUIRE(grep(&lines[0], "Invariant")); + ATF_REQUIRE(atf_utils_grep_string("Invariant", lines[0])); break; } - ATF_REQUIRE(grep(&lines[0], __FILE__)); - ATF_REQUIRE(grep(&lines[2], PACKAGE_BUGREPORT)); + ATF_REQUIRE(atf_utils_grep_string(__FILE__, lines[0])); + ATF_REQUIRE(atf_utils_grep_string(PACKAGE_BUGREPORT, lines[2])); } while (nlines > 0) { nlines--; - atf_dynstr_fini(&lines[nlines]); + free(lines[nlines]); } } diff --git a/contrib/atf/atf-c/detail/test_helpers.c b/contrib/atf/atf-c/detail/test_helpers.c index b20a849..aa64c12 100644 --- a/contrib/atf/atf-c/detail/test_helpers.c +++ b/contrib/atf/atf-c/detail/test_helpers.c @@ -30,7 +30,6 @@ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> -#include <regex.h> #include <unistd.h> #include "atf-c/build.h" @@ -106,72 +105,6 @@ get_process_helpers_path(const atf_tc_t *tc, const bool is_detail, is_detail ? "" : "detail/")); } -bool -grep_string(const atf_dynstr_t *str, const char *regex) -{ - int res; - regex_t preg; - - printf("Looking for '%s' in '%s'\n", regex, atf_dynstr_cstring(str)); - ATF_REQUIRE(regcomp(&preg, regex, REG_EXTENDED) == 0); - - res = regexec(&preg, atf_dynstr_cstring(str), 0, NULL, 0); - ATF_REQUIRE(res == 0 || res == REG_NOMATCH); - - regfree(&preg); - - return res == 0; -} - -bool -grep_file(const char *file, const char *regex, ...) -{ - bool done, found; - int fd; - va_list ap; - atf_dynstr_t formatted; - - va_start(ap, regex); - RE(atf_dynstr_init_ap(&formatted, regex, ap)); - va_end(ap); - - done = false; - found = false; - ATF_REQUIRE((fd = open(file, O_RDONLY)) != -1); - do { - atf_dynstr_t line; - - RE(atf_dynstr_init(&line)); - - done = read_line(fd, &line); - if (!done) - found = grep_string(&line, atf_dynstr_cstring(&formatted)); - - atf_dynstr_fini(&line); - } while (!found && !done); - close(fd); - - atf_dynstr_fini(&formatted); - - return found; -} - -bool -read_line(int fd, atf_dynstr_t *dest) -{ - char ch; - ssize_t cnt; - - while ((cnt = read(fd, &ch, sizeof(ch))) == sizeof(ch) && - ch != '\n') { - const atf_error_t err = atf_dynstr_append_fmt(dest, "%c", ch); - ATF_REQUIRE(!atf_is_error(err)); - } - ATF_REQUIRE(cnt != -1); - - return cnt == 0; -} - struct run_h_tc_data { atf_tc_t *m_tc; const char *m_resname; diff --git a/contrib/atf/atf-c/detail/test_helpers.h b/contrib/atf/atf-c/detail/test_helpers.h index b0ce6cc..5df034f 100644 --- a/contrib/atf/atf-c/detail/test_helpers.h +++ b/contrib/atf/atf-c/detail/test_helpers.h @@ -81,7 +81,5 @@ void build_check_c_o(const atf_tc_t *, const char *, const char *, const bool); void header_check(const char *); void get_process_helpers_path(const atf_tc_t *, const bool, struct atf_fs_path *); -bool grep_string(const struct atf_dynstr *, const char *); -bool grep_file(const char *, const char *, ...); bool read_line(int, struct atf_dynstr *); void run_h_tc(atf_tc_t *, const char *, const char *, const char *); diff --git a/contrib/atf/atf-c/detail/test_helpers_test.c b/contrib/atf/atf-c/detail/test_helpers_test.c deleted file mode 100644 index 52d8608..0000000 --- a/contrib/atf/atf-c/detail/test_helpers_test.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Automated Testing Framework (atf) - * - * Copyright (c) 2009 The NetBSD Foundation, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND - * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> - -#include <atf-c.h> - -#include "dynstr.h" -#include "test_helpers.h" - -/* --------------------------------------------------------------------- - * Test cases for the free functions. - * --------------------------------------------------------------------- */ - -/* TODO: Add checks for build_check_c_o and the macros defined in the - * header file. */ - -ATF_TC(grep_string); -ATF_TC_HEAD(grep_string, tc) -{ - atf_tc_set_md_var(tc, "descr", "Tests the grep_string helper " - "function"); -} -ATF_TC_BODY(grep_string, tc) -{ - atf_dynstr_t str; - - atf_dynstr_init_fmt(&str, "a string - aaaabbbb"); - ATF_CHECK(grep_string(&str, "a string")); - ATF_CHECK(grep_string(&str, "^a string")); - ATF_CHECK(grep_string(&str, "aaaabbbb$")); - ATF_CHECK(grep_string(&str, "aa.*bb")); - ATF_CHECK(!grep_string(&str, "foo")); - ATF_CHECK(!grep_string(&str, "bar")); - ATF_CHECK(!grep_string(&str, "aaaaa")); - - atf_dynstr_fini(&str); -} - - -ATF_TC(grep_file); -ATF_TC_HEAD(grep_file, tc) -{ - atf_tc_set_md_var(tc, "descr", "Tests the grep_file helper function"); -} -ATF_TC_BODY(grep_file, tc) -{ - FILE *f; - - f = fopen("test.txt", "w"); - ATF_CHECK(f != NULL); - fprintf(f, "line1\n"); - fprintf(f, "the second line\n"); - fprintf(f, "aaaabbbb\n"); - fclose(f); - - ATF_CHECK(grep_file("test.txt", "line1")); - ATF_CHECK(grep_file("test.txt", "line%d", 1)); - ATF_CHECK(grep_file("test.txt", "second line")); - ATF_CHECK(grep_file("test.txt", "aa.*bb")); - ATF_CHECK(!grep_file("test.txt", "foo")); - ATF_CHECK(!grep_file("test.txt", "bar")); - ATF_CHECK(!grep_file("test.txt", "aaaaa")); -} - -ATF_TC(read_line); -ATF_TC_HEAD(read_line, tc) -{ - atf_tc_set_md_var(tc, "descr", "Tests the read_line function"); -} -ATF_TC_BODY(read_line, tc) -{ - const char *l1 = "First line with % formatting % characters %"; - const char *l2 = "Second line; much longer than the first one"; - const char *l3 = "Last line, without terminator"; - - { - FILE *f; - - f = fopen("test", "w"); - ATF_REQUIRE(f != NULL); - fclose(f); - } - - { - int fd; - atf_dynstr_t dest; - bool eof; - - fd = open("test", O_RDONLY); - ATF_REQUIRE(fd != -1); - - RE(atf_dynstr_init(&dest)); - eof = read_line(fd, &dest); - ATF_REQUIRE(eof); - atf_dynstr_fini(&dest); - } - - { - FILE *f; - - f = fopen("test", "w"); - ATF_REQUIRE(f != NULL); - - fprintf(f, "%s\n", l1); - fprintf(f, "%s\n", l2); - fprintf(f, "%s", l3); - - fclose(f); - } - - { - int fd; - atf_dynstr_t dest; - bool eof; - - fd = open("test", O_RDONLY); - ATF_REQUIRE(fd != -1); - - RE(atf_dynstr_init(&dest)); - eof = read_line(fd, &dest); - ATF_REQUIRE(!eof); - printf("1st line: >%s<\n", atf_dynstr_cstring(&dest)); - ATF_REQUIRE(atf_equal_dynstr_cstring(&dest, l1)); - atf_dynstr_fini(&dest); - - RE(atf_dynstr_init(&dest)); - eof = read_line(fd, &dest); - ATF_REQUIRE(!eof); - printf("2nd line: >%s<\n", atf_dynstr_cstring(&dest)); - ATF_REQUIRE(atf_equal_dynstr_cstring(&dest, l2)); - atf_dynstr_fini(&dest); - - RE(atf_dynstr_init(&dest)); - eof = read_line(fd, &dest); - ATF_REQUIRE(eof); - printf("3rd line: >%s<\n", atf_dynstr_cstring(&dest)); - ATF_REQUIRE(atf_equal_dynstr_cstring(&dest, l3)); - atf_dynstr_fini(&dest); - - close(fd); - } -} - -/* --------------------------------------------------------------------- - * Main. - * --------------------------------------------------------------------- */ - -ATF_TP_ADD_TCS(tp) -{ - /* Add the tests for the free functions. */ - ATF_TP_ADD_TC(tp, grep_string); - ATF_TP_ADD_TC(tp, grep_file); - ATF_TP_ADD_TC(tp, read_line); - - return atf_no_error(); -} diff --git a/contrib/atf/atf-c/macros.h b/contrib/atf/atf-c/macros.h index 7afe9e8..7c33ccb 100644 --- a/contrib/atf/atf-c/macros.h +++ b/contrib/atf/atf-c/macros.h @@ -80,7 +80,7 @@ #define ATF_TC_HEAD(tc, tcptr) \ static \ void \ - atfu_ ## tc ## _head(atf_tc_t *tcptr) + atfu_ ## tc ## _head(atf_tc_t *tcptr ATF_DEFS_ATTRIBUTE_UNUSED) #define ATF_TC_HEAD_NAME(tc) \ (atfu_ ## tc ## _head) @@ -181,6 +181,24 @@ ATF_CHECK_MSG(strcmp(x, y) == 0, "%s != %s (%s != %s): " fmt, \ #x, #y, x, y, ##__VA_ARGS__) +#define ATF_REQUIRE_MATCH(regexp, string) \ + ATF_REQUIRE_MSG(atf_utils_grep_string("%s", string, regexp), \ + "'%s' not matched in '%s'", regexp, string); + +#define ATF_CHECK_MATCH(regexp, string) \ + ATF_CHECK_MSG(atf_utils_grep_string("%s", string, regexp), \ + "'%s' not matched in '%s'", regexp, string); + +#define ATF_REQUIRE_MATCH_MSG(regexp, string, fmt, ...) \ + ATF_REQUIRE_MSG(atf_utils_grep_string("%s", string, regexp), \ + "'%s' not matched in '%s': " fmt, regexp, string, \ + ##__VA_ARGS__); + +#define ATF_CHECK_MATCH_MSG(regexp, string, fmt, ...) \ + ATF_CHECK_MSG(atf_utils_grep_string("%s", string, regexp), \ + "'%s' not matched in '%s': " fmt, regexp, string, \ + ##__VA_ARGS__); + #define ATF_CHECK_ERRNO(exp_errno, bool_expr) \ atf_tc_check_errno(__FILE__, __LINE__, exp_errno, #bool_expr, bool_expr) diff --git a/contrib/atf/atf-c/macros_test.c b/contrib/atf/atf-c/macros_test.c index 9cf0525..f077a27 100644 --- a/contrib/atf/atf-c/macros_test.c +++ b/contrib/atf/atf-c/macros_test.c @@ -125,6 +125,11 @@ init_and_run_h_tc(const char *name, void (*head)(atf_tc_t *), #define H_CHECK_STREQ(id, v1, v2) \ H_DEF(check_streq_ ## id, ATF_CHECK_STREQ(v1, v2)) +#define H_CHECK_MATCH_HEAD_NAME(id) ATF_TC_HEAD_NAME(h_check_match_ ## id) +#define H_CHECK_MATCH_BODY_NAME(id) ATF_TC_BODY_NAME(h_check_match_ ## id) +#define H_CHECK_MATCH(id, v1, v2) \ + H_DEF(check_match_ ## id, ATF_CHECK_MATCH(v1, v2)) + #define H_CHECK_EQ_MSG_HEAD_NAME(id) \ ATF_TC_HEAD_NAME(h_check_eq_msg_ ## id) #define H_CHECK_EQ_MSG_BODY_NAME(id) \ @@ -139,6 +144,13 @@ init_and_run_h_tc(const char *name, void (*head)(atf_tc_t *), #define H_CHECK_STREQ_MSG(id, v1, v2, msg) \ H_DEF(check_streq_msg_ ## id, ATF_CHECK_STREQ_MSG(v1, v2, msg)) +#define H_CHECK_MATCH_MSG_HEAD_NAME(id) \ + ATF_TC_HEAD_NAME(h_check_match_msg_ ## id) +#define H_CHECK_MATCH_MSG_BODY_NAME(id) \ + ATF_TC_BODY_NAME(h_check_match_msg_ ## id) +#define H_CHECK_MATCH_MSG(id, v1, v2, msg) \ + H_DEF(check_match_msg_ ## id, ATF_CHECK_MATCH_MSG(v1, v2, msg)) + #define H_CHECK_ERRNO_HEAD_NAME(id) ATF_TC_HEAD_NAME(h_check_errno_ ## id) #define H_CHECK_ERRNO_BODY_NAME(id) ATF_TC_BODY_NAME(h_check_errno_ ## id) #define H_CHECK_ERRNO(id, exp_errno, bool_expr) \ @@ -164,6 +176,11 @@ init_and_run_h_tc(const char *name, void (*head)(atf_tc_t *), #define H_REQUIRE_STREQ(id, v1, v2) \ H_DEF(require_streq_ ## id, ATF_REQUIRE_STREQ(v1, v2)) +#define H_REQUIRE_MATCH_HEAD_NAME(id) ATF_TC_HEAD_NAME(h_require_match_ ## id) +#define H_REQUIRE_MATCH_BODY_NAME(id) ATF_TC_BODY_NAME(h_require_match_ ## id) +#define H_REQUIRE_MATCH(id, v1, v2) \ + H_DEF(require_match_ ## id, ATF_REQUIRE_MATCH(v1, v2)) + #define H_REQUIRE_EQ_MSG_HEAD_NAME(id) \ ATF_TC_HEAD_NAME(h_require_eq_msg_ ## id) #define H_REQUIRE_EQ_MSG_BODY_NAME(id) \ @@ -178,6 +195,13 @@ init_and_run_h_tc(const char *name, void (*head)(atf_tc_t *), #define H_REQUIRE_STREQ_MSG(id, v1, v2, msg) \ H_DEF(require_streq_msg_ ## id, ATF_REQUIRE_STREQ_MSG(v1, v2, msg)) +#define H_REQUIRE_MATCH_MSG_HEAD_NAME(id) \ + ATF_TC_HEAD_NAME(h_require_match_msg_ ## id) +#define H_REQUIRE_MATCH_MSG_BODY_NAME(id) \ + ATF_TC_BODY_NAME(h_require_match_msg_ ## id) +#define H_REQUIRE_MATCH_MSG(id, v1, v2, msg) \ + H_DEF(require_match_msg_ ## id, ATF_REQUIRE_MATCH_MSG(v1, v2, msg)) + #define H_REQUIRE_ERRNO_HEAD_NAME(id) ATF_TC_HEAD_NAME(h_require_errno_ ## id) #define H_REQUIRE_ERRNO_BODY_NAME(id) ATF_TC_BODY_NAME(h_require_errno_ ## id) #define H_REQUIRE_ERRNO(id, exp_errno, bool_expr) \ @@ -240,11 +264,11 @@ ATF_TC_BODY(check_errno, tc) ATF_REQUIRE(exists("after")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); } else { - ATF_REQUIRE(grep_file("result", "^failed")); - ATF_REQUIRE(grep_file("error", "macros_test.c:[0-9]+: %s$", - t->exp_regex)); + ATF_REQUIRE(atf_utils_grep_file("^failed", "result")); + ATF_REQUIRE(atf_utils_grep_file( + "macros_test.c:[0-9]+: %s$", "error", t->exp_regex)); } ATF_REQUIRE(unlink("before") != -1); @@ -282,11 +306,12 @@ ATF_TC_BODY(require_errno, tc) ATF_REQUIRE(exists("before")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); ATF_REQUIRE(exists("after")); } else { - ATF_REQUIRE(grep_file("result", "^failed: .*macros_test.c:[0-9]+: " - "%s$", t->exp_regex)); + ATF_REQUIRE(atf_utils_grep_file( + "^failed: .*macros_test.c:[0-9]+: %s$", "result", + t->exp_regex)); ATF_REQUIRE(!exists("after")); } @@ -340,11 +365,11 @@ ATF_TC_BODY(check, tc) ATF_REQUIRE(exists("after")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); } else { - ATF_REQUIRE(grep_file("result", "^failed")); - ATF_REQUIRE(grep_file("error", "Check failed: .*" - "macros_test.c:[0-9]+: %s$", t->msg)); + ATF_REQUIRE(atf_utils_grep_file("^failed", "result")); + ATF_REQUIRE(atf_utils_grep_file("Check failed: .*" + "macros_test.c:[0-9]+: %s$", "error", t->msg)); } ATF_REQUIRE(unlink("before") != -1); @@ -381,11 +406,11 @@ do_check_eq_tests(const struct check_eq_test *tests) ATF_CHECK(exists("after")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); } else { - ATF_REQUIRE(grep_file("result", "^failed")); - ATF_CHECK(grep_file("error", "Check failed: .*" - "macros_test.c:[0-9]+: %s$", t->msg)); + ATF_REQUIRE(atf_utils_grep_file("^failed", "result")); + ATF_CHECK(atf_utils_grep_file("Check failed: .*" + "macros_test.c:[0-9]+: %s$", "error", t->msg)); } ATF_CHECK(unlink("before") != -1); @@ -442,8 +467,8 @@ H_CHECK_STREQ_MSG(2_1, "2", "1", "2 does not match 1"); H_CHECK_STREQ_MSG(2_2, "2", "2", "2 does not match 2"); #define CHECK_STREQ_VAR1 "5" #define CHECK_STREQ_VAR2 "9" -const const char *check_streq_var1 = CHECK_STREQ_VAR1; -const const char *check_streq_var2 = CHECK_STREQ_VAR2; +const char *check_streq_var1 = CHECK_STREQ_VAR1; +const char *check_streq_var2 = CHECK_STREQ_VAR2; H_CHECK_STREQ(vars, check_streq_var1, check_streq_var2); ATF_TC(check_streq); @@ -485,6 +510,40 @@ ATF_TC_BODY(check_streq, tc) } /* --------------------------------------------------------------------- + * Test cases for the ATF_CHECK_MATCH and ATF_CHECK_MATCH_MSG macros. + * --------------------------------------------------------------------- */ + +H_CHECK_MATCH(yes, "hello [a-z]+", "abc hello world"); +H_CHECK_MATCH(no, "hello [a-z]+", "abc hello WORLD"); +H_CHECK_MATCH_MSG(yes, "hello [a-z]+", "abc hello world", "lowercase"); +H_CHECK_MATCH_MSG(no, "hello [a-z]+", "abc hello WORLD", "uppercase"); + +ATF_TC(check_match); +ATF_TC_HEAD(check_match, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the ATF_CHECK_MATCH and " + "ATF_CHECK_MATCH_MSG macros"); +} +ATF_TC_BODY(check_match, tc) +{ + struct check_eq_test tests[] = { + { H_CHECK_MATCH_HEAD_NAME(yes), H_CHECK_MATCH_BODY_NAME(yes), + "hello [a-z]+", "abc hello world", "", true }, + { H_CHECK_MATCH_HEAD_NAME(no), H_CHECK_MATCH_BODY_NAME(no), + "hello [a-z]+", "abc hello WORLD", + "'hello \\[a-z\\]\\+' not matched in 'abc hello WORLD'", false }, + { H_CHECK_MATCH_MSG_HEAD_NAME(yes), H_CHECK_MATCH_MSG_BODY_NAME(yes), + "hello [a-z]+", "abc hello world", "", true }, + { H_CHECK_MATCH_MSG_HEAD_NAME(no), H_CHECK_MATCH_MSG_BODY_NAME(no), + "hello [a-z]+", "abc hello WORLD", + "'hello \\[a-z\\]\\+' not matched in 'abc hello WORLD': uppercase", + false }, + { NULL, NULL, 0, 0, "", false } + }; + do_check_eq_tests(tests); +} + +/* --------------------------------------------------------------------- * Test cases for the ATF_REQUIRE and ATF_REQUIRE_MSG macros. * --------------------------------------------------------------------- */ @@ -526,11 +585,11 @@ ATF_TC_BODY(require, tc) ATF_REQUIRE(exists("before")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); ATF_REQUIRE(exists("after")); } else { - ATF_REQUIRE(grep_file("result", "^failed: .*macros_test.c:[0-9]+: " - "%s$", t->msg)); + ATF_REQUIRE(atf_utils_grep_file( + "^failed: .*macros_test.c:[0-9]+: %s$", "result", t->msg)); ATF_REQUIRE(!exists("after")); } @@ -567,11 +626,11 @@ do_require_eq_tests(const struct require_eq_test *tests) ATF_REQUIRE(exists("before")); if (t->ok) { - ATF_REQUIRE(grep_file("result", "^passed")); + ATF_REQUIRE(atf_utils_grep_file("^passed", "result")); ATF_REQUIRE(exists("after")); } else { - ATF_REQUIRE(grep_file("result", "^failed: .*macros_test.c" - ":[0-9]+: %s$", t->msg)); + ATF_REQUIRE(atf_utils_grep_file("^failed: .*macros_test.c" + ":[0-9]+: %s$", "result", t->msg)); ATF_REQUIRE(!exists("after")); } @@ -630,8 +689,8 @@ H_REQUIRE_STREQ_MSG(2_1, "2", "1", "2 does not match 1"); H_REQUIRE_STREQ_MSG(2_2, "2", "2", "2 does not match 2"); #define REQUIRE_STREQ_VAR1 "5" #define REQUIRE_STREQ_VAR2 "9" -const const char *require_streq_var1 = REQUIRE_STREQ_VAR1; -const const char *require_streq_var2 = REQUIRE_STREQ_VAR2; +const char *require_streq_var1 = REQUIRE_STREQ_VAR1; +const char *require_streq_var2 = REQUIRE_STREQ_VAR2; H_REQUIRE_STREQ(vars, require_streq_var1, require_streq_var2); ATF_TC(require_streq); @@ -673,6 +732,41 @@ ATF_TC_BODY(require_streq, tc) } /* --------------------------------------------------------------------- + * Test cases for the ATF_REQUIRE_MATCH and ATF_REQUIRE_MATCH_MSG macros. + * --------------------------------------------------------------------- */ + +H_REQUIRE_MATCH(yes, "hello [a-z]+", "abc hello world"); +H_REQUIRE_MATCH(no, "hello [a-z]+", "abc hello WORLD"); +H_REQUIRE_MATCH_MSG(yes, "hello [a-z]+", "abc hello world", "lowercase"); +H_REQUIRE_MATCH_MSG(no, "hello [a-z]+", "abc hello WORLD", "uppercase"); + +ATF_TC(require_match); +ATF_TC_HEAD(require_match, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the ATF_REQUIRE_MATCH and " + "ATF_REQUIRE_MATCH_MSG macros"); +} +ATF_TC_BODY(require_match, tc) +{ + struct require_eq_test tests[] = { + { H_REQUIRE_MATCH_HEAD_NAME(yes), H_REQUIRE_MATCH_BODY_NAME(yes), + "hello [a-z]+", "abc hello world", "", true }, + { H_REQUIRE_MATCH_HEAD_NAME(no), H_REQUIRE_MATCH_BODY_NAME(no), + "hello [a-z]+", "abc hello WORLD", + "'hello \\[a-z\\]\\+' not matched in 'abc hello WORLD'", false }, + { H_REQUIRE_MATCH_MSG_HEAD_NAME(yes), + H_REQUIRE_MATCH_MSG_BODY_NAME(yes), + "hello [a-z]+", "abc hello world", "", true }, + { H_REQUIRE_MATCH_MSG_HEAD_NAME(no), H_REQUIRE_MATCH_MSG_BODY_NAME(no), + "hello [a-z]+", "abc hello WORLD", + "'hello \\[a-z\\]\\+' not matched in 'abc hello WORLD': uppercase", + false }, + { NULL, NULL, 0, 0, "", false } + }; + do_require_eq_tests(tests); +} + +/* --------------------------------------------------------------------- * Miscellaneous test cases covering several macros. * --------------------------------------------------------------------- */ @@ -728,12 +822,12 @@ ATF_TC_BODY(msg_embedded_fmt, tc) if (t->fatal) { bool matched = - grep_file("result", "^failed: .*macros_test.c:[0-9]+: " - "%s$", t->msg); + atf_utils_grep_file( + "^failed: .*macros_test.c:[0-9]+: %s$", "result", t->msg); ATF_CHECK_MSG(matched, "couldn't find error string in result"); } else { - bool matched = grep_file("error", "Check failed: .*" - "macros_test.c:[0-9]+: %s$", t->msg); + bool matched = atf_utils_grep_file("Check failed: .*" + "macros_test.c:[0-9]+: %s$", "error", t->msg); ATF_CHECK_MSG(matched, "couldn't find error string in output"); } } @@ -765,11 +859,13 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, check_eq); ATF_TP_ADD_TC(tp, check_streq); ATF_TP_ADD_TC(tp, check_errno); + ATF_TP_ADD_TC(tp, check_match); ATF_TP_ADD_TC(tp, require); ATF_TP_ADD_TC(tp, require_eq); ATF_TP_ADD_TC(tp, require_streq); ATF_TP_ADD_TC(tp, require_errno); + ATF_TP_ADD_TC(tp, require_match); ATF_TP_ADD_TC(tp, msg_embedded_fmt); diff --git a/contrib/atf/atf-c/pkg_config_test.sh b/contrib/atf/atf-c/pkg_config_test.sh index 8770808..efeae83 100644 --- a/contrib/atf/atf-c/pkg_config_test.sh +++ b/contrib/atf/atf-c/pkg_config_test.sh @@ -59,7 +59,7 @@ atf_test_case version version_head() { atf_set "descr" "Checks that the version in atf-c is correct" - atf_set "require.progs" "pkg-config" + atf_set "require.progs" "atf-version pkg-config" } version_body() { diff --git a/contrib/atf/atf-c/utils.c b/contrib/atf/atf-c/utils.c index c332703..4409f7a 100644 --- a/contrib/atf/atf-c/utils.c +++ b/contrib/atf/atf-c/utils.c @@ -27,10 +27,221 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "atf-c/utils.h" + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <regex.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <unistd.h> -#include "atf-c/utils.h" +#include <atf-c.h> + +#include "detail/dynstr.h" + +/** Searches for a regexp in a string. + * + * \param regex The regexp to look for. + * \param str The string in which to look for the expression. + * + * \return True if there is a match; false otherwise. */ +static +bool +grep_string(const char *regex, const char *str) +{ + int res; + regex_t preg; + + printf("Looking for '%s' in '%s'\n", regex, str); + ATF_REQUIRE(regcomp(&preg, regex, REG_EXTENDED) == 0); + + res = regexec(&preg, str, 0, NULL, 0); + ATF_REQUIRE(res == 0 || res == REG_NOMATCH); + + regfree(&preg); + + return res == 0; +} + +/** Prints the contents of a file to stdout. + * + * \param name The name of the file to be printed. + * \param prefix An string to be prepended to every line of the printed + * file. */ +void +atf_utils_cat_file(const char *name, const char *prefix) +{ + const int fd = open(name, O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name); + + char buffer[1024]; + ssize_t count; + bool continued = false; + while ((count = read(fd, buffer, sizeof(buffer) - 1)) > 0) { + buffer[count] = '\0'; + + if (!continued) + printf("%s", prefix); + + char *iter = buffer; + char *end; + while ((end = strchr(iter, '\n')) != NULL) { + *end = '\0'; + printf("%s\n", iter); + + iter = end + 1; + if (iter != buffer + count) + printf("%s", prefix); + else + continued = false; + } + if (iter < buffer + count) { + printf("%s", iter); + continued = true; + } + } + ATF_REQUIRE(count == 0); +} + +/** Compares a file against the given golden contents. + * + * \param name Name of the file to be compared. + * \param contents Expected contents of the file. + * + * \return True if the file matches the contents; false otherwise. */ +bool +atf_utils_compare_file(const char *name, const char *contents) +{ + const int fd = open(name, O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name); + + const char *pos = contents; + ssize_t remaining = strlen(contents); + + char buffer[1024]; + ssize_t count; + while ((count = read(fd, buffer, sizeof(buffer))) > 0 && + count <= remaining) { + if (memcmp(pos, buffer, count) != 0) { + close(fd); + return false; + } + remaining -= count; + pos += count; + } + close(fd); + return count == 0 && remaining == 0; +} + +/** Copies a file. + * + * \param source Path to the source file. + * \param destination Path to the destination file. */ +void +atf_utils_copy_file(const char *source, const char *destination) +{ + const int input = open(source, O_RDONLY); + ATF_REQUIRE_MSG(input != -1, "Failed to open source file during " + "copy (%s)", source); + + const int output = open(destination, O_WRONLY | O_CREAT | O_TRUNC, 0777); + ATF_REQUIRE_MSG(output != -1, "Failed to open destination file during " + "copy (%s)", destination); + + char buffer[1024]; + ssize_t length; + while ((length = read(input, buffer, sizeof(buffer))) > 0) + ATF_REQUIRE_MSG(write(output, buffer, length) == length, + "Failed to write to %s during copy", destination); + ATF_REQUIRE_MSG(length != -1, "Failed to read from %s during copy", source); + + struct stat sb; + ATF_REQUIRE_MSG(fstat(input, &sb) != -1, + "Failed to stat source file %s during copy", source); + ATF_REQUIRE_MSG(fchmod(output, sb.st_mode) != -1, + "Failed to chmod destination file %s during copy", + destination); + + close(output); + close(input); +} +/** Creates a file. + * + * \param name Name of the file to create. + * \param contents Text to write into the created file. + * \param ... Positional parameters to the contents. */ +void +atf_utils_create_file(const char *name, const char *contents, ...) +{ + va_list ap; + atf_dynstr_t formatted; + atf_error_t error; + + va_start(ap, contents); + error = atf_dynstr_init_ap(&formatted, contents, ap); + va_end(ap); + ATF_REQUIRE(!atf_is_error(error)); + + const int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE_MSG(fd != -1, "Cannot create file %s", name); + ATF_REQUIRE(write(fd, atf_dynstr_cstring(&formatted), + atf_dynstr_length(&formatted)) != -1); + close(fd); + + atf_dynstr_fini(&formatted); +} + +/** Checks if a file exists. + * + * \param path Location of the file to check for. + * + * \return True if the file exists, false otherwise. */ +bool +atf_utils_file_exists(const char *path) +{ + const int ret = access(path, F_OK); + if (ret == -1) { + if (errno != ENOENT) + atf_tc_fail("Failed to check the existence of %s: %s", path, + strerror(errno)); + else + return false; + } else + return true; +} + +/** Spawns a subprocess and redirects its output to files. + * + * Use the atf_utils_wait() function to wait for the completion of the spawned + * subprocess and validate its exit conditions. + * + * \return 0 in the new child; the PID of the new child in the parent. Does + * not return in error conditions. */ +pid_t +atf_utils_fork(void) +{ + const pid_t pid = fork(); + if (pid == -1) + atf_tc_fail("fork failed"); + + if (pid == 0) { + atf_utils_redirect(STDOUT_FILENO, "atf_utils_fork_out.txt"); + atf_utils_redirect(STDERR_FILENO, "atf_utils_fork_err.txt"); + } + return pid; +} + +/** Frees an dynamically-allocated "argv" array. + * + * \param argv A dynamically-allocated array of dynamically-allocated + * strings. */ void atf_utils_free_charpp(char **argv) { @@ -41,3 +252,164 @@ atf_utils_free_charpp(char **argv) free(argv); } + +/** Searches for a regexp in a file. + * + * \param regex The regexp to look for. + * \param file The file in which to look for the expression. + * \param ... Positional parameters to the regex. + * + * \return True if there is a match; false otherwise. */ +bool +atf_utils_grep_file(const char *regex, const char *file, ...) +{ + int fd; + va_list ap; + atf_dynstr_t formatted; + atf_error_t error; + + va_start(ap, file); + error = atf_dynstr_init_ap(&formatted, regex, ap); + va_end(ap); + ATF_REQUIRE(!atf_is_error(error)); + + ATF_REQUIRE((fd = open(file, O_RDONLY)) != -1); + bool found = false; + char *line = NULL; + while (!found && (line = atf_utils_readline(fd)) != NULL) { + found = grep_string(atf_dynstr_cstring(&formatted), line); + free(line); + } + close(fd); + + atf_dynstr_fini(&formatted); + + return found; +} + +/** Searches for a regexp in a string. + * + * \param regex The regexp to look for. + * \param str The string in which to look for the expression. + * \param ... Positional parameters to the regex. + * + * \return True if there is a match; false otherwise. */ +bool +atf_utils_grep_string(const char *regex, const char *str, ...) +{ + bool res; + va_list ap; + atf_dynstr_t formatted; + atf_error_t error; + + va_start(ap, str); + error = atf_dynstr_init_ap(&formatted, regex, ap); + va_end(ap); + ATF_REQUIRE(!atf_is_error(error)); + + res = grep_string(atf_dynstr_cstring(&formatted), str); + + atf_dynstr_fini(&formatted); + + return res; +} + +/** Reads a line of arbitrary length. + * + * \param fd The descriptor from which to read the line. + * + * \return A pointer to the read line, which must be released with free(), or + * NULL if there was nothing to read from the file. */ +char * +atf_utils_readline(const int fd) +{ + char ch; + ssize_t cnt; + atf_dynstr_t temp; + atf_error_t error; + + error = atf_dynstr_init(&temp); + ATF_REQUIRE(!atf_is_error(error)); + + while ((cnt = read(fd, &ch, sizeof(ch))) == sizeof(ch) && + ch != '\n') { + error = atf_dynstr_append_fmt(&temp, "%c", ch); + ATF_REQUIRE(!atf_is_error(error)); + } + ATF_REQUIRE(cnt != -1); + + if (cnt == 0 && atf_dynstr_length(&temp) == 0) { + atf_dynstr_fini(&temp); + return NULL; + } else + return atf_dynstr_fini_disown(&temp); +} + +/** Redirects a file descriptor to a file. + * + * \param target_fd The file descriptor to be replaced. + * \param name The name of the file to direct the descriptor to. + * + * \pre Should only be called from the process spawned by fork_for_testing + * because this exits uncontrolledly. + * \post Terminates execution if the redirection fails. */ +void +atf_utils_redirect(const int target_fd, const char *name) +{ + if (target_fd == STDOUT_FILENO) + fflush(stdout); + else if (target_fd == STDERR_FILENO) + fflush(stderr); + + const int new_fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (new_fd == -1) + err(EXIT_FAILURE, "Cannot create %s", name); + if (new_fd != target_fd) { + if (dup2(new_fd, target_fd) == -1) + err(EXIT_FAILURE, "Cannot redirect to fd %d", target_fd); + } + close(new_fd); +} + +/** Waits for a subprocess and validates its exit condition. + * + * \param pid The process to be waited for. Must have been started by + * testutils_fork(). + * \param exitstatus Expected exit status. + * \param expout Expected contents of stdout. + * \param experr Expected contents of stderr. */ +void +atf_utils_wait(const pid_t pid, const int exitstatus, const char *expout, + const char *experr) +{ + int status; + ATF_REQUIRE(waitpid(pid, &status, 0) != -1); + + atf_utils_cat_file("atf_utils_fork_out.txt", "subprocess stdout: "); + atf_utils_cat_file("atf_utils_fork_err.txt", "subprocess stderr: "); + + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(exitstatus, WEXITSTATUS(status)); + + const char *save_prefix = "save:"; + const size_t save_prefix_length = strlen(save_prefix); + + if (strlen(expout) > save_prefix_length && + strncmp(expout, save_prefix, save_prefix_length) == 0) { + atf_utils_copy_file("atf_utils_fork_out.txt", + expout + save_prefix_length); + } else { + ATF_REQUIRE(atf_utils_compare_file("atf_utils_fork_out.txt", expout)); + } + + if (strlen(experr) > save_prefix_length && + strncmp(experr, save_prefix, save_prefix_length) == 0) { + atf_utils_copy_file("atf_utils_fork_err.txt", + experr + save_prefix_length); + } else { + ATF_REQUIRE(atf_utils_compare_file("atf_utils_fork_err.txt", experr)); + } + + ATF_REQUIRE(unlink("atf_utils_fork_out.txt") != -1); + ATF_REQUIRE(unlink("atf_utils_fork_err.txt") != -1); +} diff --git a/contrib/atf/atf-c/utils.h b/contrib/atf/atf-c/utils.h index dc4c5ae..666804d 100644 --- a/contrib/atf/atf-c/utils.h +++ b/contrib/atf/atf-c/utils.h @@ -30,6 +30,25 @@ #if !defined(ATF_C_UTILS_H) #define ATF_C_UTILS_H +#include <stdbool.h> +#include <unistd.h> + +#include <atf-c/defs.h> + +void atf_utils_cat_file(const char *, const char *); +bool atf_utils_compare_file(const char *, const char *); +void atf_utils_copy_file(const char *, const char *); +void atf_utils_create_file(const char *, const char *, ...) + ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 3); +bool atf_utils_file_exists(const char *); +pid_t atf_utils_fork(void); void atf_utils_free_charpp(char **); +bool atf_utils_grep_file(const char *, const char *, ...) + ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 3); +bool atf_utils_grep_string(const char *, const char *, ...) + ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 3); +char *atf_utils_readline(int); +void atf_utils_redirect(const int, const char *); +void atf_utils_wait(const pid_t, const int, const char *, const char *); #endif /* ATF_C_UTILS_H */ diff --git a/contrib/atf/atf-c/utils_test.c b/contrib/atf/atf-c/utils_test.c index 146272a..57d6af8 100644 --- a/contrib/atf/atf-c/utils_test.c +++ b/contrib/atf/atf-c/utils_test.c @@ -27,8 +27,15 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/stat.h> +#include <sys/wait.h> + +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <atf-c.h> @@ -36,8 +43,218 @@ #include "detail/test_helpers.h" -ATF_TC_WITHOUT_HEAD(free_charpp_empty); -ATF_TC_BODY(free_charpp_empty, tc) +/** Reads the contents of a file into a buffer. + * + * Up to buflen-1 characters are read into buffer. If this function returns, + * the contents read into the buffer are guaranteed to be nul-terminated. + * Note, however, that if the file contains any nul characters itself, + * comparing it "as a string" will not work. + * + * \param path The file to be read, which must exist. + * \param buffer Buffer into which to store the file contents. + * \param buflen Size of the target buffer. + * + * \return The count of bytes read. */ +static ssize_t +read_file(const char *path, void *const buffer, const size_t buflen) +{ + const int fd = open(path, O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", path); + const ssize_t length = read(fd, buffer, buflen - 1); + close(fd); + ATF_REQUIRE(length != -1); + ((char *)buffer)[length] = '\0'; + return length; +} + +ATF_TC_WITHOUT_HEAD(cat_file__empty); +ATF_TC_BODY(cat_file__empty, tc) +{ + atf_utils_create_file("file.txt", "%s", ""); + atf_utils_redirect(STDOUT_FILENO, "captured.txt"); + atf_utils_cat_file("file.txt", "PREFIX"); + fflush(stdout); + close(STDOUT_FILENO); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("", buffer); +} + +ATF_TC_WITHOUT_HEAD(cat_file__one_line); +ATF_TC_BODY(cat_file__one_line, tc) +{ + atf_utils_create_file("file.txt", "This is a single line\n"); + atf_utils_redirect(STDOUT_FILENO, "captured.txt"); + atf_utils_cat_file("file.txt", "PREFIX"); + fflush(stdout); + close(STDOUT_FILENO); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("PREFIXThis is a single line\n", buffer); +} + +ATF_TC_WITHOUT_HEAD(cat_file__several_lines); +ATF_TC_BODY(cat_file__several_lines, tc) +{ + atf_utils_create_file("file.txt", "First\nSecond line\nAnd third\n"); + atf_utils_redirect(STDOUT_FILENO, "captured.txt"); + atf_utils_cat_file("file.txt", ">"); + fflush(stdout); + close(STDOUT_FILENO); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ(">First\n>Second line\n>And third\n", buffer); +} + +ATF_TC_WITHOUT_HEAD(cat_file__no_newline_eof); +ATF_TC_BODY(cat_file__no_newline_eof, tc) +{ + atf_utils_create_file("file.txt", "Foo\n bar baz"); + atf_utils_redirect(STDOUT_FILENO, "captured.txt"); + atf_utils_cat_file("file.txt", "PREFIX"); + fflush(stdout); + close(STDOUT_FILENO); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("PREFIXFoo\nPREFIX bar baz", buffer); +} + +ATF_TC_WITHOUT_HEAD(compare_file__empty__match); +ATF_TC_BODY(compare_file__empty__match, tc) +{ + atf_utils_create_file("test.txt", "%s", ""); + ATF_REQUIRE(atf_utils_compare_file("test.txt", "")); +} + +ATF_TC_WITHOUT_HEAD(compare_file__empty__not_match); +ATF_TC_BODY(compare_file__empty__not_match, tc) +{ + atf_utils_create_file("test.txt", "%s", ""); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "foo")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", " ")); +} + +ATF_TC_WITHOUT_HEAD(compare_file__short__match); +ATF_TC_BODY(compare_file__short__match, tc) +{ + atf_utils_create_file("test.txt", "this is a short file"); + ATF_REQUIRE(atf_utils_compare_file("test.txt", "this is a short file")); +} + +ATF_TC_WITHOUT_HEAD(compare_file__short__not_match); +ATF_TC_BODY(compare_file__short__not_match, tc) +{ + atf_utils_create_file("test.txt", "this is a short file"); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a Short file")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short fil")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short file ")); +} + +ATF_TC_WITHOUT_HEAD(compare_file__long__match); +ATF_TC_BODY(compare_file__long__match, tc) +{ + char long_contents[3456]; + size_t i = 0; + for (; i < sizeof(long_contents) - 1; i++) + long_contents[i] = '0' + (i % 10); + long_contents[i] = '\0'; + atf_utils_create_file("test.txt", "%s", long_contents); + + ATF_REQUIRE(atf_utils_compare_file("test.txt", long_contents)); +} + +ATF_TC_WITHOUT_HEAD(compare_file__long__not_match); +ATF_TC_BODY(compare_file__long__not_match, tc) +{ + char long_contents[3456]; + size_t i = 0; + for (; i < sizeof(long_contents) - 1; i++) + long_contents[i] = '0' + (i % 10); + long_contents[i] = '\0'; + atf_utils_create_file("test.txt", "%s", long_contents); + + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); + ATF_REQUIRE(!atf_utils_compare_file("test.txt", "0123456789")); + long_contents[i - 1] = 'Z'; + ATF_REQUIRE(!atf_utils_compare_file("test.txt", long_contents)); +} + +ATF_TC_WITHOUT_HEAD(copy_file__empty); +ATF_TC_BODY(copy_file__empty, tc) +{ + atf_utils_create_file("src.txt", "%s", ""); + ATF_REQUIRE(chmod("src.txt", 0520) != -1); + + atf_utils_copy_file("src.txt", "dest.txt"); + ATF_REQUIRE(atf_utils_compare_file("dest.txt", "")); + struct stat sb; + ATF_REQUIRE(stat("dest.txt", &sb) != -1); + ATF_REQUIRE_EQ(0520, sb.st_mode & 0xfff); +} + +ATF_TC_WITHOUT_HEAD(copy_file__some_contents); +ATF_TC_BODY(copy_file__some_contents, tc) +{ + atf_utils_create_file("src.txt", "This is a\ntest file\n"); + atf_utils_copy_file("src.txt", "dest.txt"); + ATF_REQUIRE(atf_utils_compare_file("dest.txt", "This is a\ntest file\n")); +} + +ATF_TC_WITHOUT_HEAD(create_file); +ATF_TC_BODY(create_file, tc) +{ + atf_utils_create_file("test.txt", "This is a test with %d", 12345); + + char buffer[128]; + read_file("test.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("This is a test with 12345", buffer); +} + +ATF_TC_WITHOUT_HEAD(file_exists); +ATF_TC_BODY(file_exists, tc) +{ + atf_utils_create_file("test.txt", "foo"); + + ATF_REQUIRE( atf_utils_file_exists("test.txt")); + ATF_REQUIRE( atf_utils_file_exists("./test.txt")); + ATF_REQUIRE(!atf_utils_file_exists("./test.tx")); + ATF_REQUIRE(!atf_utils_file_exists("test.txt2")); +} + +ATF_TC_WITHOUT_HEAD(fork); +ATF_TC_BODY(fork, tc) +{ + fprintf(stdout, "Should not get into child\n"); + fprintf(stderr, "Should not get into child\n"); + pid_t pid = atf_utils_fork(); + if (pid == 0) { + fprintf(stdout, "Child stdout\n"); + fprintf(stderr, "Child stderr\n"); + exit(EXIT_SUCCESS); + } + + int status; + ATF_REQUIRE(waitpid(pid, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + char buffer[1024]; + read_file("atf_utils_fork_out.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("Child stdout\n", buffer); + read_file("atf_utils_fork_err.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("Child stderr\n", buffer); +} + +ATF_TC_WITHOUT_HEAD(free_charpp__empty); +ATF_TC_BODY(free_charpp__empty, tc) { char **array = malloc(sizeof(char *) * 1); array[0] = NULL; @@ -45,8 +262,8 @@ ATF_TC_BODY(free_charpp_empty, tc) atf_utils_free_charpp(array); } -ATF_TC_WITHOUT_HEAD(free_charpp_some); -ATF_TC_BODY(free_charpp_some, tc) +ATF_TC_WITHOUT_HEAD(free_charpp__some); +ATF_TC_BODY(free_charpp__some, tc) { char **array = malloc(sizeof(char *) * 4); array[0] = strdup("first"); @@ -57,12 +274,263 @@ ATF_TC_BODY(free_charpp_some, tc) atf_utils_free_charpp(array); } +ATF_TC_WITHOUT_HEAD(grep_file); +ATF_TC_BODY(grep_file, tc) +{ + atf_utils_create_file("test.txt", "line1\nthe second line\naaaabbbb\n"); + + ATF_CHECK(atf_utils_grep_file("line1", "test.txt")); + ATF_CHECK(atf_utils_grep_file("line%d", "test.txt", 1)); + ATF_CHECK(atf_utils_grep_file("second line", "test.txt")); + ATF_CHECK(atf_utils_grep_file("aa.*bb", "test.txt")); + ATF_CHECK(!atf_utils_grep_file("foo", "test.txt")); + ATF_CHECK(!atf_utils_grep_file("bar", "test.txt")); + ATF_CHECK(!atf_utils_grep_file("aaaaa", "test.txt")); +} + +ATF_TC_WITHOUT_HEAD(grep_string); +ATF_TC_BODY(grep_string, tc) +{ + const char *str = "a string - aaaabbbb"; + ATF_CHECK(atf_utils_grep_string("a string", str)); + ATF_CHECK(atf_utils_grep_string("^a string", str)); + ATF_CHECK(atf_utils_grep_string("aaaabbbb$", str)); + ATF_CHECK(atf_utils_grep_string("a%s*bb", str, "a.")); + ATF_CHECK(!atf_utils_grep_string("foo", str)); + ATF_CHECK(!atf_utils_grep_string("bar", str)); + ATF_CHECK(!atf_utils_grep_string("aaaaa", str)); +} + +ATF_TC_WITHOUT_HEAD(readline__none); +ATF_TC_BODY(readline__none, tc) +{ + atf_utils_create_file("empty.txt", "%s", ""); + + const int fd = open("empty.txt", O_RDONLY); + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(atf_utils_readline(fd) == NULL); + close(fd); +} + +ATF_TC_WITHOUT_HEAD(readline__some); +ATF_TC_BODY(readline__some, tc) +{ + const char *l1 = "First line with % formatting % characters %"; + const char *l2 = "Second line; much longer than the first one"; + const char *l3 = "Last line, without terminator"; + + atf_utils_create_file("test.txt", "%s\n%s\n%s", l1, l2, l3); + + const int fd = open("test.txt", O_RDONLY); + ATF_REQUIRE(fd != -1); + + char *line; + + line = atf_utils_readline(fd); + ATF_REQUIRE_STREQ(l1, line); + free(line); + + line = atf_utils_readline(fd); + ATF_REQUIRE_STREQ(l2, line); + free(line); + + line = atf_utils_readline(fd); + ATF_REQUIRE_STREQ(l3, line); + free(line); + + close(fd); +} + +ATF_TC_WITHOUT_HEAD(redirect__stdout); +ATF_TC_BODY(redirect__stdout, tc) +{ + printf("Buffer this"); + atf_utils_redirect(STDOUT_FILENO, "captured.txt"); + printf("The printed message"); + fflush(stdout); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("The printed message", buffer); +} + +ATF_TC_WITHOUT_HEAD(redirect__stderr); +ATF_TC_BODY(redirect__stderr, tc) +{ + fprintf(stderr, "Buffer this"); + atf_utils_redirect(STDERR_FILENO, "captured.txt"); + fprintf(stderr, "The printed message"); + fflush(stderr); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ("The printed message", buffer); +} + +ATF_TC_WITHOUT_HEAD(redirect__other); +ATF_TC_BODY(redirect__other, tc) +{ + const char *message = "Foo bar\nbaz\n"; + atf_utils_redirect(15, "captured.txt"); + ATF_REQUIRE(write(15, message, strlen(message)) != -1); + close(15); + + char buffer[1024]; + read_file("captured.txt", buffer, sizeof(buffer)); + ATF_REQUIRE_STREQ(message, buffer); +} + +static void +fork_and_wait(const int exitstatus, const char* expout, const char* experr) +{ + const pid_t pid = atf_utils_fork(); + if (pid == 0) { + fprintf(stdout, "Some output\n"); + fprintf(stderr, "Some error\n"); + exit(123); + } + atf_utils_wait(pid, exitstatus, expout, experr); + exit(EXIT_SUCCESS); +} + +ATF_TC_WITHOUT_HEAD(wait__ok); +ATF_TC_BODY(wait__ok, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(123, "Some output\n", "Some error\n"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + } +} + +ATF_TC_WITHOUT_HEAD(wait__invalid_exitstatus); +ATF_TC_BODY(wait__invalid_exitstatus, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(120, "Some output\n", "Some error\n"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); + } +} + +ATF_TC_WITHOUT_HEAD(wait__invalid_stdout); +ATF_TC_BODY(wait__invalid_stdout, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(123, "Some output foo\n", "Some error\n"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); + } +} + +ATF_TC_WITHOUT_HEAD(wait__invalid_stderr); +ATF_TC_BODY(wait__invalid_stderr, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(123, "Some output\n", "Some error foo\n"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); + } +} + +ATF_TC_WITHOUT_HEAD(wait__save_stdout); +ATF_TC_BODY(wait__save_stdout, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(123, "save:my-output.txt", "Some error\n"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some output\n")); + } +} + +ATF_TC_WITHOUT_HEAD(wait__save_stderr); +ATF_TC_BODY(wait__save_stderr, tc) +{ + const pid_t control = fork(); + ATF_REQUIRE(control != -1); + if (control == 0) + fork_and_wait(123, "Some output\n", "save:my-output.txt"); + else { + int status; + ATF_REQUIRE(waitpid(control, &status, 0) != -1); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some error\n")); + } +} + HEADER_TC(include, "atf-c/utils.h"); ATF_TP_ADD_TCS(tp) { - ATF_TP_ADD_TC(tp, free_charpp_empty); - ATF_TP_ADD_TC(tp, free_charpp_some); + ATF_TP_ADD_TC(tp, cat_file__empty); + ATF_TP_ADD_TC(tp, cat_file__one_line); + ATF_TP_ADD_TC(tp, cat_file__several_lines); + ATF_TP_ADD_TC(tp, cat_file__no_newline_eof); + + ATF_TP_ADD_TC(tp, compare_file__empty__match); + ATF_TP_ADD_TC(tp, compare_file__empty__not_match); + ATF_TP_ADD_TC(tp, compare_file__short__match); + ATF_TP_ADD_TC(tp, compare_file__short__not_match); + ATF_TP_ADD_TC(tp, compare_file__long__match); + ATF_TP_ADD_TC(tp, compare_file__long__not_match); + + ATF_TP_ADD_TC(tp, copy_file__empty); + ATF_TP_ADD_TC(tp, copy_file__some_contents); + + ATF_TP_ADD_TC(tp, create_file); + + ATF_TP_ADD_TC(tp, file_exists); + + ATF_TP_ADD_TC(tp, fork); + + ATF_TP_ADD_TC(tp, free_charpp__empty); + ATF_TP_ADD_TC(tp, free_charpp__some); + + ATF_TP_ADD_TC(tp, grep_file); + ATF_TP_ADD_TC(tp, grep_string); + + ATF_TP_ADD_TC(tp, readline__none); + ATF_TP_ADD_TC(tp, readline__some); + + ATF_TP_ADD_TC(tp, redirect__stdout); + ATF_TP_ADD_TC(tp, redirect__stderr); + ATF_TP_ADD_TC(tp, redirect__other); + + ATF_TP_ADD_TC(tp, wait__ok); + ATF_TP_ADD_TC(tp, wait__save_stdout); + ATF_TP_ADD_TC(tp, wait__save_stderr); + ATF_TP_ADD_TC(tp, wait__invalid_exitstatus); + ATF_TP_ADD_TC(tp, wait__invalid_stdout); + ATF_TP_ADD_TC(tp, wait__invalid_stderr); ATF_TP_ADD_TC(tp, include); |