summaryrefslogtreecommitdiffstats
path: root/contrib/atf/atf-c++
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/atf/atf-c++')
-rw-r--r--contrib/atf/atf-c++/Atffile14
-rw-r--r--contrib/atf/atf-c++/Kyuafile14
-rw-r--r--contrib/atf/atf-c++/Makefile.am.inc111
-rw-r--r--contrib/atf/atf-c++/atf-c++-api.3420
-rw-r--r--contrib/atf/atf-c++/atf-c++.m448
-rw-r--r--contrib/atf/atf-c++/atf-c++.pc.in11
-rw-r--r--contrib/atf/atf-c++/atf_c++_test.cpp48
-rw-r--r--contrib/atf/atf-c++/build.cpp119
-rw-r--r--contrib/atf/atf-c++/build.hpp57
-rw-r--r--contrib/atf/atf-c++/build_test.cpp247
-rw-r--r--contrib/atf/atf-c++/check.cpp158
-rw-r--r--contrib/atf/atf-c++/check.hpp133
-rw-r--r--contrib/atf/atf-c++/check_test.cpp408
-rw-r--r--contrib/atf/atf-c++/config.cpp123
-rw-r--r--contrib/atf/atf-c++/config.hpp75
-rw-r--r--contrib/atf/atf-c++/config_test.cpp231
-rw-r--r--contrib/atf/atf-c++/detail/Atffile13
-rw-r--r--contrib/atf/atf-c++/detail/Kyuafile13
-rw-r--r--contrib/atf/atf-c++/detail/Makefile.am.inc99
-rw-r--r--contrib/atf/atf-c++/detail/application.cpp345
-rw-r--r--contrib/atf/atf-c++/detail/application.hpp115
-rw-r--r--contrib/atf/atf-c++/detail/application_test.cpp94
-rw-r--r--contrib/atf/atf-c++/detail/env.cpp73
-rw-r--r--contrib/atf/atf-c++/detail/env.hpp84
-rw-r--r--contrib/atf/atf-c++/detail/env_test.cpp91
-rw-r--r--contrib/atf/atf-c++/detail/exceptions.cpp157
-rw-r--r--contrib/atf/atf-c++/detail/exceptions.hpp99
-rw-r--r--contrib/atf/atf-c++/detail/exceptions_test.cpp148
-rw-r--r--contrib/atf/atf-c++/detail/expand.cpp81
-rw-r--r--contrib/atf/atf-c++/detail/expand.hpp82
-rw-r--r--contrib/atf/atf-c++/detail/expand_test.cpp272
-rw-r--r--contrib/atf/atf-c++/detail/fs.cpp517
-rw-r--r--contrib/atf/atf-c++/detail/fs.hpp391
-rw-r--r--contrib/atf/atf-c++/detail/fs_test.cpp545
-rw-r--r--contrib/atf/atf-c++/detail/parser.cpp384
-rw-r--r--contrib/atf/atf-c++/detail/parser.hpp607
-rw-r--r--contrib/atf/atf-c++/detail/parser_test.cpp1043
-rw-r--r--contrib/atf/atf-c++/detail/process.cpp355
-rw-r--r--contrib/atf/atf-c++/detail/process.hpp280
-rw-r--r--contrib/atf/atf-c++/detail/process_test.cpp357
-rw-r--r--contrib/atf/atf-c++/detail/sanity.hpp37
-rw-r--r--contrib/atf/atf-c++/detail/sanity_test.cpp41
-rw-r--r--contrib/atf/atf-c++/detail/test_helpers.cpp160
-rw-r--r--contrib/atf/atf-c++/detail/test_helpers.hpp166
-rw-r--r--contrib/atf/atf-c++/detail/text.cpp160
-rw-r--r--contrib/atf/atf-c++/detail/text.hpp153
-rw-r--r--contrib/atf/atf-c++/detail/text_test.cpp390
-rw-r--r--contrib/atf/atf-c++/detail/ui.cpp173
-rw-r--r--contrib/atf/atf-c++/detail/ui.hpp105
-rw-r--r--contrib/atf/atf-c++/detail/ui_test.cpp462
-rw-r--r--contrib/atf/atf-c++/macros.hpp222
-rw-r--r--contrib/atf/atf-c++/macros_hpp_test.cpp130
-rw-r--r--contrib/atf/atf-c++/macros_test.cpp793
-rw-r--r--contrib/atf/atf-c++/pkg_config_test.sh149
-rw-r--r--contrib/atf/atf-c++/tests.cpp710
-rw-r--r--contrib/atf/atf-c++/tests.hpp127
-rw-r--r--contrib/atf/atf-c++/tests_test.cpp201
-rw-r--r--contrib/atf/atf-c++/unused_test.cpp52
-rw-r--r--contrib/atf/atf-c++/utils.hpp200
-rw-r--r--contrib/atf/atf-c++/utils_test.cpp310
60 files changed, 13203 insertions, 0 deletions
diff --git a/contrib/atf/atf-c++/Atffile b/contrib/atf/atf-c++/Atffile
new file mode 100644
index 0000000..ba11f21
--- /dev/null
+++ b/contrib/atf/atf-c++/Atffile
@@ -0,0 +1,14 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = atf
+
+tp: detail
+
+tp: atf_c++_test
+tp: build_test
+tp: check_test
+tp: config_test
+tp: macros_test
+tp: pkg_config_test
+tp: tests_test
+tp: utils_test
diff --git a/contrib/atf/atf-c++/Kyuafile b/contrib/atf/atf-c++/Kyuafile
new file mode 100644
index 0000000..6df836f
--- /dev/null
+++ b/contrib/atf/atf-c++/Kyuafile
@@ -0,0 +1,14 @@
+syntax("kyuafile", 1)
+
+test_suite("atf")
+
+atf_test_program{name="atf_c++_test"}
+atf_test_program{name="build_test"}
+atf_test_program{name="check_test"}
+atf_test_program{name="config_test"}
+atf_test_program{name="macros_test"}
+atf_test_program{name="pkg_config_test"}
+atf_test_program{name="tests_test"}
+atf_test_program{name="utils_test"}
+
+include("detail/Kyuafile")
diff --git a/contrib/atf/atf-c++/Makefile.am.inc b/contrib/atf/atf-c++/Makefile.am.inc
new file mode 100644
index 0000000..23d497d
--- /dev/null
+++ b/contrib/atf/atf-c++/Makefile.am.inc
@@ -0,0 +1,111 @@
+#
+# 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.
+#
+
+ATF_CXX_LIBS = libatf-c++.la libatf-c.la
+
+lib_LTLIBRARIES += libatf-c++.la
+libatf_c___la_LIBADD = libatf-c.la
+libatf_c___la_SOURCES = atf-c++/build.cpp \
+ atf-c++/build.hpp \
+ atf-c++/check.cpp \
+ atf-c++/check.hpp \
+ atf-c++/config.cpp \
+ atf-c++/config.hpp \
+ atf-c++/macros.hpp \
+ atf-c++/tests.cpp \
+ atf-c++/tests.hpp \
+ atf-c++/utils.hpp
+libatf_c___la_LDFLAGS = -version-info 0:0:0
+
+include_HEADERS += atf-c++.hpp
+atf_c___HEADERS = atf-c++/build.hpp \
+ atf-c++/check.hpp \
+ atf-c++/config.hpp \
+ atf-c++/macros.hpp \
+ atf-c++/tests.hpp \
+ atf-c++/utils.hpp
+atf_c__dir = $(includedir)/atf-c++
+
+dist_man_MANS += atf-c++/atf-c++-api.3
+
+atf_aclocal_DATA += atf-c++/atf-c++.m4
+EXTRA_DIST += atf-c++/atf-c++.m4
+
+atf_c__dirpkgconfigdir = $(atf_pkgconfigdir)
+atf_c__dirpkgconfig_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#__CXX__#$(CXX)#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_hpp_test.cpp \
+ atf-c++/unused_test.cpp
+tests_atf_c__dir = $(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.cpp
+atf_c___atf_c___test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+tests_atf_c___PROGRAMS += atf-c++/build_test
+atf_c___build_test_SOURCES = atf-c++/build_test.cpp atf-c/h_build.h
+atf_c___build_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+tests_atf_c___PROGRAMS += atf-c++/check_test
+atf_c___check_test_SOURCES = atf-c++/check_test.cpp
+atf_c___check_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+tests_atf_c___PROGRAMS += atf-c++/config_test
+atf_c___config_test_SOURCES = atf-c++/config_test.cpp
+atf_c___config_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+tests_atf_c___PROGRAMS += atf-c++/macros_test
+atf_c___macros_test_SOURCES = atf-c++/macros_test.cpp
+atf_c___macros_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+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++/tests_test
+atf_c___tests_test_SOURCES = atf-c++/tests_test.cpp
+atf_c___tests_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+tests_atf_c___PROGRAMS += atf-c++/utils_test
+atf_c___utils_test_SOURCES = atf-c++/utils_test.cpp
+atf_c___utils_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+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
new file mode 100644
index 0000000..5d6618b
--- /dev/null
+++ b/contrib/atf/atf-c++/atf-c++-api.3
@@ -0,0 +1,420 @@
+.\"
+.\" Automated Testing Framework (atf)
+.\"
+.\" Copyright (c) 2008 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.
+.\"
+.Dd January 21, 2012
+.Dt ATF-C++-API 3
+.Os
+.Sh NAME
+.Nm ATF_ADD_TEST_CASE ,
+.Nm ATF_CHECK_ERRNO ,
+.Nm ATF_FAIL ,
+.Nm ATF_INIT_TEST_CASES ,
+.Nm ATF_PASS ,
+.Nm ATF_REQUIRE ,
+.Nm ATF_REQUIRE_EQ ,
+.Nm ATF_REQUIRE_ERRNO ,
+.Nm ATF_REQUIRE_IN ,
+.Nm ATF_REQUIRE_MATCH ,
+.Nm ATF_REQUIRE_NOT_IN ,
+.Nm ATF_REQUIRE_THROW ,
+.Nm ATF_REQUIRE_THROW_RE ,
+.Nm ATF_SKIP ,
+.Nm ATF_TEST_CASE ,
+.Nm ATF_TEST_CASE_BODY ,
+.Nm ATF_TEST_CASE_CLEANUP ,
+.Nm ATF_TEST_CASE_HEAD ,
+.Nm ATF_TEST_CASE_NAME ,
+.Nm ATF_TEST_CASE_USE ,
+.Nm ATF_TEST_CASE_WITH_CLEANUP ,
+.Nm ATF_TEST_CASE_WITHOUT_HEAD ,
+.Nd C++ API to write ATF-based test programs
+.Sh SYNOPSIS
+.In atf-c++.hpp
+.Fn ATF_ADD_TEST_CASE "tcs" "name"
+.Fn ATF_CHECK_ERRNO "exp_errno" "bool_expression"
+.Fn ATF_FAIL "reason"
+.Fn ATF_INIT_TEST_CASES "tcs"
+.Fn ATF_PASS
+.Fn ATF_REQUIRE "expression"
+.Fn ATF_REQUIRE_EQ "expression_1" "expression_2"
+.Fn ATF_REQUIRE_ERRNO "exp_errno" "bool_expression"
+.Fn ATF_REQUIRE_IN "element" "collection"
+.Fn ATF_REQUIRE_MATCH "regexp" "string_expression"
+.Fn ATF_REQUIRE_NOT_IN "element" "collection"
+.Fn ATF_REQUIRE_THROW "expected_exception" "statement"
+.Fn ATF_REQUIRE_THROW_RE "expected_exception" "regexp" "statement"
+.Fn ATF_SKIP "reason"
+.Fn ATF_TEST_CASE "name"
+.Fn ATF_TEST_CASE_BODY "name"
+.Fn ATF_TEST_CASE_CLEANUP "name"
+.Fn ATF_TEST_CASE_HEAD "name"
+.Fn ATF_TEST_CASE_NAME "name"
+.Fn ATF_TEST_CASE_USE "name"
+.Fn ATF_TEST_CASE_WITH_CLEANUP "name"
+.Fn ATF_TEST_CASE_WITHOUT_HEAD "name"
+.Sh DESCRIPTION
+ATF provides a mostly-macro-based programming interface to implement test
+programs in C or C++.
+This interface is backed by a C++ implementation, but this fact is
+hidden from the developer as much as possible through the use of
+macros to simplify programming.
+However, the use of C++ is not hidden everywhere and while you can
+implement test cases without knowing anything at all about the object model
+underneath the provided calls, you might need some minimum notions of the
+language in very specific circumstances.
+.Pp
+C++-based test programs always follow this template:
+.Bd -literal -offset indent
+extern "C" {
+.Ns ... C-specific includes go here ...
+}
+
+.Ns ... C++-specific includes go here ...
+
+#include <atf-c++.hpp>
+
+ATF_TEST_CASE(tc1);
+ATF_TEST_CASE_HEAD(tc1)
+{
+ ... first test case's header ...
+}
+ATF_TEST_CASE_BODY(tc1)
+{
+ ... first test case's body ...
+}
+
+ATF_TEST_CASE_WITH_CLEANUP(tc2);
+ATF_TEST_CASE_HEAD(tc2)
+{
+ ... second test case's header ...
+}
+ATF_TEST_CASE_BODY(tc2)
+{
+ ... second test case's body ...
+}
+ATF_TEST_CASE_CLEANUP(tc2)
+{
+ ... second test case's cleanup ...
+}
+
+ATF_TEST_CASE(tc3);
+ATF_TEST_CASE_BODY(tc3)
+{
+ ... third test case's body ...
+}
+
+.Ns ... additional test cases ...
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, tc1);
+ ATF_ADD_TEST_CASE(tcs, tc2);
+ ATF_ADD_TEST_CASE(tcs, tc3);
+ ... add additional test cases ...
+}
+.Ed
+.Ss Definition of test cases
+Test cases have an identifier and are composed of three different parts:
+the header, the body and an optional cleanup routine, all of which are
+described in
+.Xr atf-test-case 4 .
+To define test cases, one can use the
+.Fn ATF_TEST_CASE ,
+.Fn ATF_TEST_CASE_WITH_CLEANUP
+or the
+.Fn ATF_TEST_CASE_WITHOUT_HEAD
+macros, which take a single parameter specifiying the test case's
+name.
+.Fn ATF_TEST_CASE ,
+requires to define a head and a body for the test case,
+.Fn ATF_TEST_CASE_WITH_CLEANUP
+requires to define a head, a body and a cleanup for the test case and
+.Fn ATF_TEST_CASE_WITHOUT_HEAD
+requires only a body for the test case.
+It is important to note that these
+.Em do not
+set the test case up for execution when the program is run.
+In order to do so, a later registration is needed through the
+.Fn ATF_ADD_TEST_CASE
+macro detailed in
+.Sx Program initialization .
+.Pp
+Later on, one must define the three parts of the body by means of three
+functions.
+Their headers are given by the
+.Fn ATF_TEST_CASE_HEAD ,
+.Fn ATF_TEST_CASE_BODY
+and
+.Fn ATF_TEST_CASE_CLEANUP
+macros, all of which take the test case's name.
+Following each of these, a block of code is expected, surrounded by the
+opening and closing brackets.
+.Pp
+Additionally, the
+.Fn ATF_TEST_CASE_NAME
+macro can be used to obtain the name of the class corresponding to a
+particular test case, as the name is internally manged by the library to
+prevent clashes with other user identifiers.
+Similarly, the
+.Fn ATF_TEST_CASE_USE
+macro can be executed on a particular test case to mark it as "used" and
+thus prevent compiler warnings regarding unused symbols.
+Note that
+.Em you should never have to use these macros during regular operation.
+.Ss Program initialization
+The library provides a way to easily define the test program's
+.Fn main
+function.
+You should never define one on your own, but rely on the
+library to do it for you.
+This is done by using the
+.Fn ATF_INIT_TEST_CASES
+macro, which is passed the name of the list that will hold the test cases.
+This name can be whatever you want as long as it is a valid variable value.
+.Pp
+After the macro, you are supposed to provide the body of a function, which
+should only use the
+.Fn ATF_ADD_TEST_CASE
+macro to register the test cases the test program will execute.
+The first parameter of this macro matches the name you provided in the
+former call.
+.Ss Header definitions
+The test case's header can define the meta-data by using the
+.Fn set
+method, which takes two parameters: the first one specifies the
+meta-data variable to be set and the second one specifies its value.
+Both of them are strings.
+.Ss Configuration variables
+The test case has read-only access to the current configuration variables
+by means of the
+.Ft bool
+.Fn has_config_var
+and the
+.Ft std::string
+.Fn get_config_var
+methods, which can be called in any of the three parts of a test case.
+.Ss Access to the source directory
+It is possible to get the path to the test case's source directory from any
+of its three components by querying the
+.Sq srcdir
+configuration variable.
+.Ss Requiring programs
+Aside from the
+.Va require.progs
+meta-data variable available in the header only, one can also check for
+additional programs in the test case's body by using the
+.Fn require_prog
+function, which takes the base name or full path of a single binary.
+Relative paths are forbidden.
+If it is not found, the test case will be automatically skipped.
+.Ss Test case finalization
+The test case finalizes either when the body reaches its end, at which
+point the test is assumed to have
+.Em passed ,
+or at any explicit call to
+.Fn ATF_PASS ,
+.Fn ATF_FAIL
+or
+.Fn ATF_SKIP .
+These three macros terminate the execution of the test case immediately.
+The cleanup routine will be processed afterwards in a completely automated
+way, regardless of the test case's termination reason.
+.Pp
+.Fn ATF_PASS
+does not take any parameters.
+.Fn ATF_FAIL
+and
+.Fn ATF_SKIP
+take a single string that describes why the test case failed or
+was skipped, respectively.
+It is very important to provide a clear error message in both cases so that
+the user can quickly know why the test did not pass.
+.Ss Expectations
+Everything explained in the previous section changes when the test case
+expectations are redefined by the programmer.
+.Pp
+Each test case has an internal state called
+.Sq expect
+that describes what the test case expectations are at any point in time.
+The value of this property can change during execution by any of:
+.Bl -tag -width indent
+.It Fn expect_death "reason"
+Expects the test case to exit prematurely regardless of the nature of the
+exit.
+.It Fn expect_exit "exitcode" "reason"
+Expects the test case to exit cleanly.
+If
+.Va exitcode
+is not
+.Sq -1 ,
+.Xr atf-run 1
+will validate that the exit code of the test case matches the one provided
+in this call.
+Otherwise, the exact value will be ignored.
+.It Fn expect_fail "reason"
+Any failure (be it fatal or non-fatal) raised in this mode is recorded.
+However, such failures do not report the test case as failed; instead, the
+test case finalizes cleanly and is reported as
+.Sq expected failure ;
+this report includes the provided
+.Fa reason
+as part of it.
+If no error is raised while running in this mode, then the test case is
+reported as
+.Sq failed .
+.Pp
+This mode is useful to reproduce actual known bugs in tests.
+Whenever the developer fixes the bug later on, the test case will start
+reporting a failure, signaling the developer that the test case must be
+adjusted to the new conditions.
+In this situation, it is useful, for example, to set
+.Fa reason
+as the bug number for tracking purposes.
+.It Fn expect_pass
+This is the normal mode of execution.
+In this mode, any failure is reported as such to the user and the test case
+is marked as
+.Sq failed .
+.It Fn expect_race "reason"
+Any failure or timeout during the execution of the test case will be
+considered as if a race condition has been triggered and reported as such.
+If no problems arise, the test will continue execution as usual.
+.It Fn expect_signal "signo" "reason"
+Expects the test case to terminate due to the reception of a signal.
+If
+.Va signo
+is not
+.Sq -1 ,
+.Xr atf-run 1
+will validate that the signal that terminated the test case matches the one
+provided in this call.
+Otherwise, the exact value will be ignored.
+.It Fn expect_timeout "reason"
+Expects the test case to execute for longer than its timeout.
+.El
+.Ss Helper macros for common checks
+The library provides several macros that are very handy in multiple
+situations.
+These basically check some condition after executing a given statement or
+processing a given expression and, if the condition is not met, they
+automatically call
+.Fn ATF_FAIL
+with an appropriate error message.
+.Pp
+.Fn ATF_REQUIRE
+takes an expression and raises a failure if it evaluates to false.
+.Pp
+.Fn ATF_REQUIRE_EQ
+takes two expressions and raises a failure if the two do not evaluate to
+the same exact value.
+.Pp
+.Fn ATF_REQUIRE_IN
+takes an element and a collection and validates that the element is present in
+the collection.
+.Pp
+.Fn ATF_REQUIRE_MATCH
+takes a regular expression and a string and raises a failure if the regular
+expression does not match the string.
+.Pp
+.Fn ATF_REQUIRE_NOT_IN
+takes an element and a collection and validates that the element is not present
+in the collection.
+.Pp
+.Fn ATF_REQUIRE_THROW
+takes the name of an exception and a statement and raises a failure if
+the statement does not throw the specified exception.
+.Fn ATF_REQUIRE_THROW_EQ
+takes the name of an exception, a regular expresion and a statement and raises a
+failure if the statement does not throw the specified exception and if the
+message of the exception does not match the regular expression.
+.Pp
+.Fn ATF_CHECK_ERRNO
+and
+.Fn ATF_REQUIRE_ERRNO
+take, first, the error code that the check is expecting to find in the
+.Va errno
+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.
+.Sh EXAMPLES
+The following shows a complete test program with a single test case that
+validates the addition operator:
+.Bd -literal -offset indent
+#include <atf-c++.hpp>
+
+ATF_TEST_CASE(addition);
+ATF_TEST_CASE_HEAD(addition)
+{
+ set("descr", "Sample tests for the addition operator");
+}
+ATF_TEST_CASE_BODY(addition)
+{
+ ATF_REQUIRE_EQ(0 + 0, 0);
+ ATF_REQUIRE_EQ(0 + 1, 1);
+ ATF_REQUIRE_EQ(1 + 0, 1);
+
+ ATF_REQUIRE_EQ(1 + 1, 2);
+
+ ATF_REQUIRE_EQ(100 + 200, 300);
+}
+
+ATF_TEST_CASE(open_failure);
+ATF_TEST_CASE_HEAD(open_failure)
+{
+ set("descr", "Sample tests for the open function");
+}
+ATF_TEST_CASE_BODY(open_failure)
+{
+ ATF_REQUIRE_ERRNO(ENOENT, open("non-existent", O_RDONLY) == -1);
+}
+
+ATF_TEST_CASE(known_bug);
+ATF_TEST_CASE_HEAD(known_bug)
+{
+ set("descr", "Reproduces a known bug");
+}
+ATF_TEST_CASE_BODY(known_bug)
+{
+ expect_fail("See bug number foo/bar");
+ ATF_REQUIRE_EQ(3, 1 + 1);
+ expect_pass();
+ ATF_REQUIRE_EQ(3, 1 + 2);
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, addition);
+ ATF_ADD_TEST_CASE(tcs, open_failure);
+ ATF_ADD_TEST_CASE(tcs, known_bug);
+}
+.Ed
+.Sh SEE ALSO
+.Xr atf-test-program 1 ,
+.Xr atf-test-case 4 ,
+.Xr atf 7
diff --git a/contrib/atf/atf-c++/atf-c++.m4 b/contrib/atf/atf-c++/atf-c++.m4
new file mode 100644
index 0000000..0763d04
--- /dev/null
+++ b/contrib/atf/atf-c++/atf-c++.m4
@@ -0,0 +1,48 @@
+dnl
+dnl Automated Testing Framework (atf)
+dnl
+dnl Copyright 2011 Google Inc.
+dnl All rights reserved.
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions are
+dnl met:
+dnl
+dnl * Redistributions of source code must retain the above copyright
+dnl notice, this list of conditions and the following disclaimer.
+dnl * Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl * Neither the name of Google Inc. nor the names of its contributors
+dnl may be used to endorse or promote products derived from this software
+dnl without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+dnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+dnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+dnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+dnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+dnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+dnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+dnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+dnl
+
+dnl ATF_CHECK_CXX([version-spec])
+dnl
+dnl Checks if atf-c++ is present. If version-spec is provided, ensures that
+dnl the installed version of atf-sh matches the required version. This
+dnl argument must be something like '>= 0.14' and accepts any version
+dnl specification supported by pkg-config.
+dnl
+dnl Defines and substitutes ATF_CXX_CFLAGS and ATF_CXX_LIBS with the compiler
+dnl and linker flags need to build against atf-c++.
+AC_DEFUN([ATF_CHECK_CXX], [
+ spec="atf-c++[]m4_default_nblank([ $1], [])"
+ _ATF_CHECK_ARG_WITH(
+ [PKG_CHECK_MODULES([ATF_CXX], [${spec}],
+ [found=yes found_atf_cxx=yes], [found=no])],
+ [required ${spec} not found])
+])
diff --git a/contrib/atf/atf-c++/atf-c++.pc.in b/contrib/atf/atf-c++/atf-c++.pc.in
new file mode 100644
index 0000000..f366bb0
--- /dev/null
+++ b/contrib/atf/atf-c++/atf-c++.pc.in
@@ -0,0 +1,11 @@
+# ATF pkg-config file
+
+cxx=__CXX__
+includedir=__INCLUDEDIR__
+libdir=__LIBDIR__
+
+Name: atf-c++
+Description: Automated Testing Framework (C++ binding)
+Version: __ATF_VERSION__
+Cflags: -I${includedir}
+Libs: -L${libdir} -latf-c++ -latf-c
diff --git a/contrib/atf/atf-c++/atf_c++_test.cpp b/contrib/atf/atf-c++/atf_c++_test.cpp
new file mode 100644
index 0000000..c09e4b1
--- /dev/null
+++ b/contrib/atf/atf-c++/atf_c++_test.cpp
@@ -0,0 +1,48 @@
+//
+// 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 "macros.hpp"
+
+#include "detail/test_helpers.hpp"
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
diff --git a/contrib/atf/atf-c++/build.cpp b/contrib/atf/atf-c++/build.cpp
new file mode 100644
index 0000000..9ce134c
--- /dev/null
+++ b/contrib/atf/atf-c++/build.cpp
@@ -0,0 +1,119 @@
+//
+// 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.
+//
+
+extern "C" {
+#include "atf-c/build.h"
+#include "atf-c/error.h"
+#include "atf-c/utils.h"
+}
+
+#include "build.hpp"
+
+#include "detail/exceptions.hpp"
+#include "detail/process.hpp"
+
+namespace impl = atf::build;
+#define IMPL_NAME "atf::build"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+inline
+atf::process::argv_array
+cargv_to_argv(const atf_list_t* l)
+{
+ std::vector< const char* > aux;
+
+ atf_list_citer_t iter;
+ atf_list_for_each_c(iter, l)
+ aux.push_back(static_cast< const char* >(atf_list_citer_data(iter)));
+
+ return atf::process::argv_array(aux);
+}
+
+inline
+atf::process::argv_array
+cargv_to_argv_and_free(char** l)
+{
+ try {
+ atf::process::argv_array argv((const char* const*)l);
+ atf_utils_free_charpp(l);
+ return argv;
+ } catch (...) {
+ atf_utils_free_charpp(l);
+ throw;
+ }
+}
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+atf::process::argv_array
+impl::c_o(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ char** l;
+
+ atf_error_t err = atf_build_c_o(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &l);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return cargv_to_argv_and_free(l);
+}
+
+atf::process::argv_array
+impl::cpp(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ char** l;
+
+ atf_error_t err = atf_build_cpp(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &l);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return cargv_to_argv_and_free(l);
+}
+
+atf::process::argv_array
+impl::cxx_o(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ char** l;
+
+ atf_error_t err = atf_build_cxx_o(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &l);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return cargv_to_argv_and_free(l);
+}
diff --git a/contrib/atf/atf-c++/build.hpp b/contrib/atf/atf-c++/build.hpp
new file mode 100644
index 0000000..5a291b4
--- /dev/null
+++ b/contrib/atf/atf-c++/build.hpp
@@ -0,0 +1,57 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_BUILD_HPP_)
+#define _ATF_CXX_BUILD_HPP_
+
+#include <string>
+
+namespace atf {
+
+namespace process {
+class argv_array;
+} // namespace process
+
+namespace build {
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+process::argv_array c_o(const std::string&, const std::string&,
+ const process::argv_array&);
+process::argv_array cpp(const std::string&, const std::string&,
+ const process::argv_array&);
+process::argv_array cxx_o(const std::string&, const std::string&,
+ const process::argv_array&);
+
+} // namespace build
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_BUILD_HPP_)
diff --git a/contrib/atf/atf-c++/build_test.cpp b/contrib/atf/atf-c++/build_test.cpp
new file mode 100644
index 0000000..6852905
--- /dev/null
+++ b/contrib/atf/atf-c++/build_test.cpp
@@ -0,0 +1,247 @@
+//
+// 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 <cstring>
+#include <iostream>
+
+#include "../atf-c/h_build.h"
+
+#include "build.hpp"
+#include "config.hpp"
+#include "macros.hpp"
+
+#include "detail/env.hpp"
+#include "detail/process.hpp"
+#include "detail/test_helpers.hpp"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+namespace atf {
+ namespace config {
+ void __reinit(void);
+ }
+}
+
+template< class C >
+void
+print_col(const char* prefix, const C& c)
+{
+ std::cout << prefix << ":";
+ for (typename C::const_iterator iter = c.begin(); iter != c.end();
+ iter++)
+ std::cout << " '" << *iter << "'";
+ std::cout << "\n";
+}
+
+static
+void
+print_array(const char* prefix, const char* const* a)
+{
+ std::cout << prefix << ":";
+ for (; *a != NULL; a++)
+ std::cout << " '" << *a << "'";
+ std::cout << "\n";
+}
+
+static
+void
+verbose_set_env(const char *var, const char *val)
+{
+ std::cout << "Setting " << var << " to '" << val << "'\n";
+ atf::env::set(var, val);
+}
+
+static
+bool
+equal_argvs(const atf::process::argv_array& aa, const char* const* array)
+{
+ bool equal = true;
+
+ atf::process::argv_array::size_type i = 0;
+ while (equal && (i < aa.size() && array[i] != NULL)) {
+ if (std::strcmp(aa[i], array[i]) != 0)
+ equal = false;
+ else
+ i++;
+ }
+
+ if (equal && (i < aa.size() || array[i] != NULL))
+ equal = false;
+
+ return equal;
+}
+
+static
+void
+check_equal_argvs(const atf::process::argv_array& aa, const char* const* array)
+{
+ print_array("Expected arguments", array);
+ print_col("Arguments returned", aa);
+
+ if (!equal_argvs(aa, array))
+ ATF_FAIL("The constructed argv differs from the expected values");
+}
+
+// ------------------------------------------------------------------------
+// Internal test cases.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(equal_argvs);
+ATF_TEST_CASE_HEAD(equal_argvs)
+{
+ set_md_var("descr", "Tests the test case internal equal_argvs function");
+}
+ATF_TEST_CASE_BODY(equal_argvs)
+{
+ {
+ const char* const array[] = { NULL };
+ const char* const argv[] = { NULL };
+
+ ATF_REQUIRE(equal_argvs(atf::process::argv_array(argv), array));
+ }
+
+ {
+ const char* const array[] = { NULL };
+ const char* const argv[] = { "foo", NULL };
+
+ ATF_REQUIRE(!equal_argvs(atf::process::argv_array(argv), array));
+ }
+
+ {
+ const char* const array[] = { "foo", NULL };
+ const char* const argv[] = { NULL };
+
+ ATF_REQUIRE(!equal_argvs(atf::process::argv_array(argv), array));
+ }
+
+ {
+ const char* const array[] = { "foo", NULL };
+ const char* const argv[] = { "foo", NULL };
+
+ ATF_REQUIRE(equal_argvs(atf::process::argv_array(argv), array));
+ }
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(c_o);
+ATF_TEST_CASE_HEAD(c_o)
+{
+ set_md_var("descr", "Tests the c_o function");
+}
+ATF_TEST_CASE_BODY(c_o)
+{
+ for (struct c_o_test* test = c_o_tests; test->expargv[0] != NULL;
+ test++) {
+ std::cout << "> Test: " << test->msg << "\n";
+
+ verbose_set_env("ATF_BUILD_CC", test->cc);
+ verbose_set_env("ATF_BUILD_CFLAGS", test->cflags);
+ verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
+ atf::config::__reinit();
+
+ atf::process::argv_array argv =
+ atf::build::c_o(test->sfile, test->ofile,
+ atf::process::argv_array(test->optargs));
+ check_equal_argvs(argv, test->expargv);
+ }
+}
+
+ATF_TEST_CASE(cpp);
+ATF_TEST_CASE_HEAD(cpp)
+{
+ set_md_var("descr", "Tests the cpp function");
+}
+ATF_TEST_CASE_BODY(cpp)
+{
+ for (struct cpp_test* test = cpp_tests; test->expargv[0] != NULL;
+ test++) {
+ std::cout << "> Test: " << test->msg << "\n";
+
+ verbose_set_env("ATF_BUILD_CPP", test->cpp);
+ verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
+ atf::config::__reinit();
+
+ atf::process::argv_array argv =
+ atf::build::cpp(test->sfile, test->ofile,
+ atf::process::argv_array(test->optargs));
+ check_equal_argvs(argv, test->expargv);
+ }
+}
+
+ATF_TEST_CASE(cxx_o);
+ATF_TEST_CASE_HEAD(cxx_o)
+{
+ set_md_var("descr", "Tests the cxx_o function");
+}
+ATF_TEST_CASE_BODY(cxx_o)
+{
+ for (struct cxx_o_test* test = cxx_o_tests; test->expargv[0] != NULL;
+ test++) {
+ std::cout << "> Test: " << test->msg << "\n";
+
+ verbose_set_env("ATF_BUILD_CXX", test->cxx);
+ verbose_set_env("ATF_BUILD_CXXFLAGS", test->cxxflags);
+ verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
+ atf::config::__reinit();
+
+ atf::process::argv_array argv =
+ atf::build::cxx_o(test->sfile, test->ofile,
+ atf::process::argv_array(test->optargs));
+ check_equal_argvs(argv, test->expargv);
+ }
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/build.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the internal test cases.
+ ATF_ADD_TEST_CASE(tcs, equal_argvs);
+
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, c_o);
+ ATF_ADD_TEST_CASE(tcs, cpp);
+ ATF_ADD_TEST_CASE(tcs, cxx_o);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
diff --git a/contrib/atf/atf-c++/check.cpp b/contrib/atf/atf-c++/check.cpp
new file mode 100644
index 0000000..b099b07
--- /dev/null
+++ b/contrib/atf/atf-c++/check.cpp
@@ -0,0 +1,158 @@
+//
+// 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.
+//
+
+#include <cstring>
+
+extern "C" {
+#include "atf-c/build.h"
+#include "atf-c/error.h"
+}
+
+#include "check.hpp"
+
+#include "detail/exceptions.hpp"
+#include "detail/process.hpp"
+#include "detail/sanity.hpp"
+
+namespace impl = atf::check;
+#define IMPL_NAME "atf::check"
+
+// ------------------------------------------------------------------------
+// The "check_result" class.
+// ------------------------------------------------------------------------
+
+impl::check_result::check_result(const atf_check_result_t* result)
+{
+ std::memcpy(&m_result, result, sizeof(m_result));
+}
+
+impl::check_result::~check_result(void)
+{
+ atf_check_result_fini(&m_result);
+}
+
+bool
+impl::check_result::exited(void)
+ const
+{
+ return atf_check_result_exited(&m_result);
+}
+
+int
+impl::check_result::exitcode(void)
+ const
+{
+ PRE(exited());
+ return atf_check_result_exitcode(&m_result);
+}
+
+bool
+impl::check_result::signaled(void)
+ const
+{
+ return atf_check_result_signaled(&m_result);
+}
+
+int
+impl::check_result::termsig(void)
+ const
+{
+ PRE(signaled());
+ return atf_check_result_termsig(&m_result);
+}
+
+const std::string
+impl::check_result::stdout_path(void) const
+{
+ return atf_check_result_stdout(&m_result);
+}
+
+const std::string
+impl::check_result::stderr_path(void) const
+{
+ return atf_check_result_stderr(&m_result);
+}
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+bool
+impl::build_c_o(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ bool success;
+
+ atf_error_t err = atf_check_build_c_o(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &success);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return success;
+}
+
+bool
+impl::build_cpp(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ bool success;
+
+ atf_error_t err = atf_check_build_cpp(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &success);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return success;
+}
+
+bool
+impl::build_cxx_o(const std::string& sfile, const std::string& ofile,
+ const atf::process::argv_array& optargs)
+{
+ bool success;
+
+ atf_error_t err = atf_check_build_cxx_o(sfile.c_str(), ofile.c_str(),
+ optargs.exec_argv(), &success);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return success;
+}
+
+std::auto_ptr< impl::check_result >
+impl::exec(const atf::process::argv_array& argva)
+{
+ atf_check_result_t result;
+
+ atf_error_t err = atf_check_exec_array(argva.exec_argv(), &result);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return std::auto_ptr< impl::check_result >(new impl::check_result(&result));
+}
diff --git a/contrib/atf/atf-c++/check.hpp b/contrib/atf/atf-c++/check.hpp
new file mode 100644
index 0000000..055dd4f
--- /dev/null
+++ b/contrib/atf/atf-c++/check.hpp
@@ -0,0 +1,133 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_CHECK_HPP_)
+#define _ATF_CXX_CHECK_HPP_
+
+extern "C" {
+#include <atf-c/check.h>
+}
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <atf-c++/utils.hpp>
+
+namespace atf {
+
+namespace process {
+class argv_array;
+} // namespace process
+
+namespace check {
+
+// ------------------------------------------------------------------------
+// The "check_result" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief A class that contains results of executed command.
+//!
+//! The check_result class holds information about results
+//! of executing arbitrary command and manages files containing
+//! its output.
+//!
+class check_result : utils::noncopyable {
+ //!
+ //! \brief Internal representation of a result.
+ //!
+ atf_check_result_t m_result;
+
+ //!
+ //! \brief Constructs a results object and grabs ownership of the
+ //! parameter passed in.
+ //!
+ check_result(const atf_check_result_t* result);
+
+ friend check_result test_constructor(const char* const*);
+ friend std::auto_ptr< check_result > exec(const atf::process::argv_array&);
+
+public:
+ //!
+ //! \brief Destroys object and removes all managed files.
+ //!
+ ~check_result(void);
+
+ //!
+ //! \brief Returns whether the command exited correctly or not.
+ //!
+ bool exited(void) const;
+
+ //!
+ //! \brief Returns command's exit status.
+ //!
+ int exitcode(void) const;
+
+ //!
+ //! \brief Returns whether the command received a signal or not.
+ //!
+ bool signaled(void) const;
+
+ //!
+ //! \brief Returns the signal that terminated the command.
+ //!
+ int termsig(void) const;
+
+ //!
+ //! \brief Returns the path to file contaning command's stdout.
+ //!
+ const std::string stdout_path(void) const;
+
+ //!
+ //! \brief Returns the path to file contaning command's stderr.
+ //!
+ const std::string stderr_path(void) const;
+};
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+bool build_c_o(const std::string&, const std::string&,
+ const atf::process::argv_array&);
+bool build_cpp(const std::string&, const std::string&,
+ const atf::process::argv_array&);
+bool build_cxx_o(const std::string&, const std::string&,
+ const atf::process::argv_array&);
+std::auto_ptr< check_result > exec(const atf::process::argv_array&);
+
+// Useful for testing only.
+check_result test_constructor(void);
+
+} // namespace check
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_CHECK_HPP_)
diff --git a/contrib/atf/atf-c++/check_test.cpp b/contrib/atf/atf-c++/check_test.cpp
new file mode 100644
index 0000000..fd528e9
--- /dev/null
+++ b/contrib/atf/atf-c++/check_test.cpp
@@ -0,0 +1,408 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+}
+
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <memory>
+#include <vector>
+
+#include <atf-c++.hpp>
+
+#include "check.hpp"
+#include "config.hpp"
+#include "utils.hpp"
+
+#include "detail/fs.hpp"
+#include "detail/process.hpp"
+#include "detail/test_helpers.hpp"
+#include "detail/text.hpp"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+static
+std::auto_ptr< atf::check::check_result >
+do_exec(const atf::tests::tc* tc, const char* helper_name)
+{
+ std::vector< std::string > argv;
+ argv.push_back(get_process_helpers_path(*tc).str());
+ argv.push_back(helper_name);
+ std::cout << "Executing " << argv[0] << " " << argv[1] << "\n";
+
+ atf::process::argv_array argva(argv);
+ return atf::check::exec(argva);
+}
+
+static
+std::auto_ptr< atf::check::check_result >
+do_exec(const atf::tests::tc* tc, const char* helper_name, const char *carg2)
+{
+ std::vector< std::string > argv;
+ argv.push_back(get_process_helpers_path(*tc).str());
+ argv.push_back(helper_name);
+ argv.push_back(carg2);
+ std::cout << "Executing " << argv[0] << " " << argv[1] << " "
+ << argv[2] << "\n";
+
+ atf::process::argv_array argva(argv);
+ return atf::check::exec(argva);
+}
+
+// ------------------------------------------------------------------------
+// Helper test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(h_build_c_o_ok);
+ATF_TEST_CASE_HEAD(h_build_c_o_ok)
+{
+ set_md_var("descr", "Helper test case for build_c_o");
+}
+ATF_TEST_CASE_BODY(h_build_c_o_ok)
+{
+ std::ofstream sfile("test.c");
+ sfile << "#include <stdio.h>\n";
+ sfile.close();
+
+ ATF_REQUIRE(atf::check::build_c_o("test.c", "test.o",
+ atf::process::argv_array()));
+}
+
+ATF_TEST_CASE(h_build_c_o_fail);
+ATF_TEST_CASE_HEAD(h_build_c_o_fail)
+{
+ set_md_var("descr", "Helper test case for build_c_o");
+}
+ATF_TEST_CASE_BODY(h_build_c_o_fail)
+{
+ std::ofstream sfile("test.c");
+ sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
+ sfile.close();
+
+ ATF_REQUIRE(!atf::check::build_c_o("test.c", "test.o",
+ atf::process::argv_array()));
+}
+
+ATF_TEST_CASE(h_build_cpp_ok);
+ATF_TEST_CASE_HEAD(h_build_cpp_ok)
+{
+ set_md_var("descr", "Helper test case for build_cpp");
+}
+ATF_TEST_CASE_BODY(h_build_cpp_ok)
+{
+ std::ofstream sfile("test.c");
+ sfile << "#define A foo\n";
+ sfile << "#define B bar\n";
+ sfile << "A B\n";
+ sfile.close();
+
+ ATF_REQUIRE(atf::check::build_cpp("test.c", "test.p",
+ atf::process::argv_array()));
+}
+
+ATF_TEST_CASE(h_build_cpp_fail);
+ATF_TEST_CASE_HEAD(h_build_cpp_fail)
+{
+ set_md_var("descr", "Helper test case for build_cpp");
+}
+ATF_TEST_CASE_BODY(h_build_cpp_fail)
+{
+ std::ofstream sfile("test.c");
+ sfile << "#include \"./non-existent.h\"\n";
+ sfile.close();
+
+ ATF_REQUIRE(!atf::check::build_cpp("test.c", "test.p",
+ atf::process::argv_array()));
+}
+
+ATF_TEST_CASE(h_build_cxx_o_ok);
+ATF_TEST_CASE_HEAD(h_build_cxx_o_ok)
+{
+ set_md_var("descr", "Helper test case for build_cxx_o");
+}
+ATF_TEST_CASE_BODY(h_build_cxx_o_ok)
+{
+ std::ofstream sfile("test.cpp");
+ sfile << "#include <iostream>\n";
+ sfile.close();
+
+ ATF_REQUIRE(atf::check::build_cxx_o("test.cpp", "test.o",
+ atf::process::argv_array()));
+}
+
+ATF_TEST_CASE(h_build_cxx_o_fail);
+ATF_TEST_CASE_HEAD(h_build_cxx_o_fail)
+{
+ set_md_var("descr", "Helper test case for build_cxx_o");
+}
+ATF_TEST_CASE_BODY(h_build_cxx_o_fail)
+{
+ std::ofstream sfile("test.cpp");
+ sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
+ sfile.close();
+
+ ATF_REQUIRE(!atf::check::build_cxx_o("test.cpp", "test.o",
+ atf::process::argv_array()));
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(build_c_o);
+ATF_TEST_CASE_HEAD(build_c_o)
+{
+ set_md_var("descr", "Tests the build_c_o function");
+}
+ATF_TEST_CASE_BODY(build_c_o)
+{
+ ATF_TEST_CASE_USE(h_build_c_o_ok);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_ok) >();
+ ATF_REQUIRE(grep_file("stdout", "-o test.o"));
+ ATF_REQUIRE(grep_file("stdout", "-c test.c"));
+
+ ATF_TEST_CASE_USE(h_build_c_o_fail);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_fail) >();
+ ATF_REQUIRE(grep_file("stdout", "-o test.o"));
+ ATF_REQUIRE(grep_file("stdout", "-c test.c"));
+ ATF_REQUIRE(grep_file("stderr", "test.c"));
+ ATF_REQUIRE(grep_file("stderr", "UNDEFINED_SYMBOL"));
+}
+
+ATF_TEST_CASE(build_cpp);
+ATF_TEST_CASE_HEAD(build_cpp)
+{
+ set_md_var("descr", "Tests the build_cpp function");
+}
+ATF_TEST_CASE_BODY(build_cpp)
+{
+ ATF_TEST_CASE_USE(h_build_cpp_ok);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_ok) >();
+ ATF_REQUIRE(grep_file("stdout", "-o.*test.p"));
+ ATF_REQUIRE(grep_file("stdout", "test.c"));
+ ATF_REQUIRE(grep_file("test.p", "foo bar"));
+
+ ATF_TEST_CASE_USE(h_build_cpp_fail);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_fail) >();
+ ATF_REQUIRE(grep_file("stdout", "-o test.p"));
+ ATF_REQUIRE(grep_file("stdout", "test.c"));
+ ATF_REQUIRE(grep_file("stderr", "test.c"));
+ ATF_REQUIRE(grep_file("stderr", "non-existent.h"));
+}
+
+ATF_TEST_CASE(build_cxx_o);
+ATF_TEST_CASE_HEAD(build_cxx_o)
+{
+ set_md_var("descr", "Tests the build_cxx_o function");
+}
+ATF_TEST_CASE_BODY(build_cxx_o)
+{
+ ATF_TEST_CASE_USE(h_build_cxx_o_ok);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_ok) >();
+ ATF_REQUIRE(grep_file("stdout", "-o test.o"));
+ ATF_REQUIRE(grep_file("stdout", "-c test.cpp"));
+
+ ATF_TEST_CASE_USE(h_build_cxx_o_fail);
+ run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_fail) >();
+ ATF_REQUIRE(grep_file("stdout", "-o test.o"));
+ ATF_REQUIRE(grep_file("stdout", "-c test.cpp"));
+ ATF_REQUIRE(grep_file("stderr", "test.cpp"));
+ ATF_REQUIRE(grep_file("stderr", "UNDEFINED_SYMBOL"));
+}
+
+ATF_TEST_CASE(exec_cleanup);
+ATF_TEST_CASE_HEAD(exec_cleanup)
+{
+ set_md_var("descr", "Tests that exec properly cleans up the temporary "
+ "files it creates");
+}
+ATF_TEST_CASE_BODY(exec_cleanup)
+{
+ std::auto_ptr< atf::fs::path > out;
+ std::auto_ptr< atf::fs::path > err;
+
+ {
+ std::auto_ptr< atf::check::check_result > r =
+ do_exec(this, "exit-success");
+ out.reset(new atf::fs::path(r->stdout_path()));
+ err.reset(new atf::fs::path(r->stderr_path()));
+ ATF_REQUIRE(atf::fs::exists(*out.get()));
+ ATF_REQUIRE(atf::fs::exists(*err.get()));
+ }
+ ATF_REQUIRE(!atf::fs::exists(*out.get()));
+ ATF_REQUIRE(!atf::fs::exists(*err.get()));
+}
+
+ATF_TEST_CASE(exec_exitstatus);
+ATF_TEST_CASE_HEAD(exec_exitstatus)
+{
+ set_md_var("descr", "Tests that exec properly captures the exit "
+ "status of the executed command");
+}
+ATF_TEST_CASE_BODY(exec_exitstatus)
+{
+ {
+ std::auto_ptr< atf::check::check_result > r =
+ do_exec(this, "exit-success");
+ ATF_REQUIRE(r->exited());
+ ATF_REQUIRE(!r->signaled());
+ ATF_REQUIRE_EQ(r->exitcode(), EXIT_SUCCESS);
+ }
+
+ {
+ std::auto_ptr< atf::check::check_result > r =
+ do_exec(this, "exit-failure");
+ ATF_REQUIRE(r->exited());
+ ATF_REQUIRE(!r->signaled());
+ ATF_REQUIRE_EQ(r->exitcode(), EXIT_FAILURE);
+ }
+
+ {
+ std::auto_ptr< atf::check::check_result > r =
+ do_exec(this, "exit-signal");
+ ATF_REQUIRE(!r->exited());
+ ATF_REQUIRE(r->signaled());
+ ATF_REQUIRE_EQ(r->termsig(), SIGKILL);
+ }
+}
+
+static
+void
+check_lines(const std::string& path, const char* outname,
+ const char* resname)
+{
+ std::ifstream f(path.c_str());
+ ATF_REQUIRE(f);
+
+ std::string line;
+ std::getline(f, line);
+ ATF_REQUIRE_EQ(line, std::string("Line 1 to ") + outname + " for " +
+ resname);
+ std::getline(f, line);
+ ATF_REQUIRE_EQ(line, std::string("Line 2 to ") + outname + " for " +
+ resname);
+}
+
+ATF_TEST_CASE(exec_stdout_stderr);
+ATF_TEST_CASE_HEAD(exec_stdout_stderr)
+{
+ set_md_var("descr", "Tests that exec properly captures the stdout "
+ "and stderr streams of the child process");
+}
+ATF_TEST_CASE_BODY(exec_stdout_stderr)
+{
+ std::auto_ptr< atf::check::check_result > r1 =
+ do_exec(this, "stdout-stderr", "result1");
+ ATF_REQUIRE(r1->exited());
+ ATF_REQUIRE_EQ(r1->exitcode(), EXIT_SUCCESS);
+
+ std::auto_ptr< atf::check::check_result > r2 =
+ do_exec(this, "stdout-stderr", "result2");
+ ATF_REQUIRE(r2->exited());
+ ATF_REQUIRE_EQ(r2->exitcode(), EXIT_SUCCESS);
+
+ const std::string out1 = r1->stdout_path();
+ const std::string out2 = r2->stdout_path();
+ const std::string err1 = r1->stderr_path();
+ const std::string err2 = r2->stderr_path();
+
+ ATF_REQUIRE(out1.find("check.XXXXXX") == std::string::npos);
+ ATF_REQUIRE(out2.find("check.XXXXXX") == std::string::npos);
+ ATF_REQUIRE(err1.find("check.XXXXXX") == std::string::npos);
+ ATF_REQUIRE(err2.find("check.XXXXXX") == std::string::npos);
+
+ ATF_REQUIRE(out1.find("/check") != std::string::npos);
+ ATF_REQUIRE(out2.find("/check") != std::string::npos);
+ ATF_REQUIRE(err1.find("/check") != std::string::npos);
+ ATF_REQUIRE(err2.find("/check") != std::string::npos);
+
+ ATF_REQUIRE(out1.find("/stdout") != std::string::npos);
+ ATF_REQUIRE(out2.find("/stdout") != std::string::npos);
+ ATF_REQUIRE(err1.find("/stderr") != std::string::npos);
+ ATF_REQUIRE(err2.find("/stderr") != std::string::npos);
+
+ ATF_REQUIRE(out1 != out2);
+ ATF_REQUIRE(err1 != err2);
+
+ check_lines(out1, "stdout", "result1");
+ check_lines(out2, "stdout", "result2");
+ check_lines(err1, "stderr", "result1");
+ check_lines(err2, "stderr", "result2");
+}
+
+ATF_TEST_CASE(exec_unknown);
+ATF_TEST_CASE_HEAD(exec_unknown)
+{
+ set_md_var("descr", "Tests that running a non-existing binary "
+ "is handled correctly");
+}
+ATF_TEST_CASE_BODY(exec_unknown)
+{
+ std::vector< std::string > argv;
+ argv.push_back(atf::config::get("atf_workdir") + "/non-existent");
+
+ atf::process::argv_array argva(argv);
+ std::auto_ptr< atf::check::check_result > r = atf::check::exec(argva);
+ ATF_REQUIRE(r->exited());
+ ATF_REQUIRE_EQ(r->exitcode(), 127);
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/check.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, build_c_o);
+ ATF_ADD_TEST_CASE(tcs, build_cpp);
+ ATF_ADD_TEST_CASE(tcs, build_cxx_o);
+ ATF_ADD_TEST_CASE(tcs, exec_cleanup);
+ ATF_ADD_TEST_CASE(tcs, exec_exitstatus);
+ ATF_ADD_TEST_CASE(tcs, exec_stdout_stderr);
+ ATF_ADD_TEST_CASE(tcs, exec_unknown);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
diff --git a/contrib/atf/atf-c++/config.cpp b/contrib/atf/atf-c++/config.cpp
new file mode 100644
index 0000000..7b7d641
--- /dev/null
+++ b/contrib/atf/atf-c++/config.cpp
@@ -0,0 +1,123 @@
+//
+// 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.
+//
+
+#include <map>
+
+extern "C" {
+#include "atf-c/config.h"
+}
+
+#include "config.hpp"
+
+#include "detail/env.hpp"
+#include "detail/sanity.hpp"
+
+static std::map< std::string, std::string > m_variables;
+
+//
+// Adds all predefined standard build-time variables to the m_variables
+// map, considering the values a user may have provided in the environment.
+//
+// Can only be called once during the program's lifetime.
+//
+static
+void
+init_variables(void)
+{
+ PRE(m_variables.empty());
+
+ m_variables["atf_arch"] = atf_config_get("atf_arch");
+ m_variables["atf_build_cc"] = atf_config_get("atf_build_cc");
+ m_variables["atf_build_cflags"] = atf_config_get("atf_build_cflags");
+ m_variables["atf_build_cpp"] = atf_config_get("atf_build_cpp");
+ m_variables["atf_build_cppflags"] = atf_config_get("atf_build_cppflags");
+ m_variables["atf_build_cxx"] = atf_config_get("atf_build_cxx");
+ m_variables["atf_build_cxxflags"] = atf_config_get("atf_build_cxxflags");
+ m_variables["atf_confdir"] = atf_config_get("atf_confdir");
+ m_variables["atf_includedir"] = atf_config_get("atf_includedir");
+ m_variables["atf_libdir"] = atf_config_get("atf_libdir");
+ m_variables["atf_libexecdir"] = atf_config_get("atf_libexecdir");
+ m_variables["atf_machine"] = atf_config_get("atf_machine");
+ m_variables["atf_pkgdatadir"] = atf_config_get("atf_pkgdatadir");
+ m_variables["atf_shell"] = atf_config_get("atf_shell");
+ m_variables["atf_workdir"] = atf_config_get("atf_workdir");
+
+ POST(!m_variables.empty());
+}
+
+const std::string&
+atf::config::get(const std::string& varname)
+{
+ if (m_variables.empty())
+ init_variables();
+
+ PRE(has(varname));
+ return m_variables[varname];
+}
+
+const std::map< std::string, std::string >&
+atf::config::get_all(void)
+{
+ if (m_variables.empty())
+ init_variables();
+
+ return m_variables;
+}
+
+bool
+atf::config::has(const std::string& varname)
+{
+ if (m_variables.empty())
+ init_variables();
+
+ return m_variables.find(varname) != m_variables.end();
+}
+
+extern "C" {
+void __atf_config_reinit(void);
+}
+
+namespace atf {
+namespace config {
+//
+// Auxiliary function for the t_config test program so that it can
+// revert the configuration's global status to an empty state and
+// do new tests from there on.
+//
+// Ideally this shouldn't be part of the production library... but
+// this is so small that it does not matter.
+//
+void
+__reinit(void)
+{
+ __atf_config_reinit();
+ m_variables.clear();
+}
+} // namespace config
+} // namespace atf
diff --git a/contrib/atf/atf-c++/config.hpp b/contrib/atf/atf-c++/config.hpp
new file mode 100644
index 0000000..e11b9bb
--- /dev/null
+++ b/contrib/atf/atf-c++/config.hpp
@@ -0,0 +1,75 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_CONFIG_HPP_)
+#define _ATF_CXX_CONFIG_HPP_
+
+#include <map>
+#include <string>
+
+namespace atf {
+
+namespace config {
+
+//!
+//! \brief Gets a build-time configuration variable's value.
+//!
+//! Given the name of a build-time configuration variable, returns its
+//! textual value. The user is free to override these by setting their
+//! corresponding environment variables. Therefore always use this
+//! interface to get the value of these variables.
+//!
+//! \pre The variable must exist.
+//!
+const std::string& get(const std::string&);
+
+//!
+//! \brief Returns all the build-time configuration variables.
+//!
+//! Returns a name to value map containing all build-time configuration
+//! variables.
+//!
+const std::map< std::string, std::string >& get_all(void);
+
+//!
+//! \brief Checks whether a build-time configuration variable exists.
+//!
+//! Given the name of a build-time configuration variable, checks
+//! whether it is defined and returns a boolean indicating this
+//! condition. The program only has to use this function to sanity-check
+//! a variable name provided by the user. Otherwise it can assume that
+//! the variables are defined.
+//!
+bool has(const std::string&);
+
+} // namespace config
+
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_CONFIG_HPP_)
diff --git a/contrib/atf/atf-c++/config_test.cpp b/contrib/atf/atf-c++/config_test.cpp
new file mode 100644
index 0000000..a3cd2bb
--- /dev/null
+++ b/contrib/atf/atf-c++/config_test.cpp
@@ -0,0 +1,231 @@
+//
+// 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.
+//
+
+#include <cstring>
+#include <iostream>
+
+#include "config.hpp"
+#include "macros.hpp"
+
+#include "detail/env.hpp"
+#include "detail/exceptions.hpp"
+#include "detail/test_helpers.hpp"
+
+static const char *test_value = "env-value";
+
+static struct varnames {
+ const char *lc;
+ const char *uc;
+ bool can_be_empty;
+} all_vars[] = {
+ { "atf_arch", "ATF_ARCH", false },
+ { "atf_build_cc", "ATF_BUILD_CC", false },
+ { "atf_build_cflags", "ATF_BUILD_CFLAGS", true },
+ { "atf_build_cpp", "ATF_BUILD_CPP", false },
+ { "atf_build_cppflags", "ATF_BUILD_CPPFLAGS", true },
+ { "atf_build_cxx", "ATF_BUILD_CXX", false },
+ { "atf_build_cxxflags", "ATF_BUILD_CXXFLAGS", true },
+ { "atf_confdir", "ATF_CONFDIR", false },
+ { "atf_includedir", "ATF_INCLUDEDIR", false },
+ { "atf_libdir", "ATF_LIBDIR", false },
+ { "atf_libexecdir", "ATF_LIBEXECDIR", false },
+ { "atf_machine", "ATF_MACHINE", false },
+ { "atf_pkgdatadir", "ATF_PKGDATADIR", false },
+ { "atf_shell", "ATF_SHELL", false },
+ { "atf_workdir", "ATF_WORKDIR", false },
+ { NULL, NULL, false }
+};
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+namespace atf {
+ namespace config {
+ void __reinit(void);
+ }
+}
+
+static
+void
+set_env_var(const char* name, const char* val)
+{
+ try {
+ atf::env::set(name, val);
+ } catch (const atf::system_error&) {
+ ATF_FAIL(std::string("set_env_var(") + name + ", " + val +
+ ") failed");
+ }
+}
+
+static
+void
+unset_env_var(const char* name)
+{
+ try {
+ atf::env::unset(name);
+ } catch (const atf::system_error&) {
+ ATF_FAIL(std::string("unset_env_var(") + name + ") failed");
+ }
+}
+
+static
+size_t
+all_vars_count(void)
+{
+ size_t count = 0;
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ count++;
+ return count;
+}
+
+static
+void
+unset_all(void)
+{
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ unset_env_var(v->uc);
+}
+
+static
+void
+compare_one(const char* var, const char* expvalue)
+{
+ std::cout << "Checking that " << var << " is set to " << expvalue << "\n";
+
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
+ if (std::strcmp(v->lc, var) == 0)
+ ATF_REQUIRE_EQ(atf::config::get(v->lc), test_value);
+ else
+ ATF_REQUIRE(atf::config::get(v->lc) != test_value);
+ }
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(get);
+ATF_TEST_CASE_HEAD(get)
+{
+ set_md_var("descr", "Tests the config::get function");
+}
+ATF_TEST_CASE_BODY(get)
+{
+ // Unset all known environment variables and make sure the built-in
+ // values do not match the bogus value we will use for testing.
+ unset_all();
+ atf::config::__reinit();
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ ATF_REQUIRE(atf::config::get(v->lc) != test_value);
+
+ // Test the behavior of empty values.
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
+ unset_all();
+ if (!atf::config::get(v->lc).empty()) {
+ set_env_var(v->uc, "");
+ atf::config::__reinit();
+ if (v->can_be_empty)
+ ATF_REQUIRE(atf::config::get(v->lc).empty());
+ else
+ ATF_REQUIRE(!atf::config::get(v->lc).empty());
+ }
+ }
+
+ // Check if the ATF_ARCH variable is recognized.
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
+ unset_all();
+ set_env_var(v->uc, test_value);
+ atf::config::__reinit();
+ compare_one(v->lc, test_value);
+ }
+}
+
+ATF_TEST_CASE(get_all);
+ATF_TEST_CASE_HEAD(get_all)
+{
+ set_md_var("descr", "Tests the config::get_all function");
+}
+ATF_TEST_CASE_BODY(get_all)
+{
+ atf::config::__reinit();
+
+ // Check that the valid variables, and only those, are returned.
+ std::map< std::string, std::string > vars = atf::config::get_all();
+ ATF_REQUIRE_EQ(vars.size(), all_vars_count());
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ ATF_REQUIRE(vars.find(v->lc) != vars.end());
+}
+
+ATF_TEST_CASE(has);
+ATF_TEST_CASE_HEAD(has)
+{
+ set_md_var("descr", "Tests the config::has function");
+}
+ATF_TEST_CASE_BODY(has)
+{
+ atf::config::__reinit();
+
+ // Check for all the variables that must exist.
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ ATF_REQUIRE(atf::config::has(v->lc));
+
+ // Same as above, but using uppercase (which is incorrect).
+ for (const struct varnames* v = all_vars; v->lc != NULL; v++)
+ ATF_REQUIRE(!atf::config::has(v->uc));
+
+ // Check for some other variables that cannot exist.
+ ATF_REQUIRE(!atf::config::has("foo"));
+ ATF_REQUIRE(!atf::config::has("BAR"));
+ ATF_REQUIRE(!atf::config::has("atf_foo"));
+ ATF_REQUIRE(!atf::config::has("ATF_BAR"));
+ ATF_REQUIRE(!atf::config::has("atf_shel"));
+ ATF_REQUIRE(!atf::config::has("atf_shells"));
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/config.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, has);
+ ATF_ADD_TEST_CASE(tcs, get);
+ ATF_ADD_TEST_CASE(tcs, get_all);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
diff --git a/contrib/atf/atf-c++/detail/Atffile b/contrib/atf/atf-c++/detail/Atffile
new file mode 100644
index 0000000..ead6ec3
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/Atffile
@@ -0,0 +1,13 @@
+Content-Type: application/X-atf-atffile; version="1"
+
+prop: test-suite = atf
+
+tp: application_test
+tp: env_test
+tp: exceptions_test
+tp: expand_test
+tp: fs_test
+tp: parser_test
+tp: sanity_test
+tp: text_test
+tp: ui_test
diff --git a/contrib/atf/atf-c++/detail/Kyuafile b/contrib/atf/atf-c++/detail/Kyuafile
new file mode 100644
index 0000000..472c122
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/Kyuafile
@@ -0,0 +1,13 @@
+syntax("kyuafile", 1)
+
+test_suite("atf")
+
+atf_test_program{name="application_test"}
+atf_test_program{name="env_test"}
+atf_test_program{name="exceptions_test"}
+atf_test_program{name="expand_test"}
+atf_test_program{name="fs_test"}
+atf_test_program{name="parser_test"}
+atf_test_program{name="sanity_test"}
+atf_test_program{name="text_test"}
+atf_test_program{name="ui_test"}
diff --git a/contrib/atf/atf-c++/detail/Makefile.am.inc b/contrib/atf/atf-c++/detail/Makefile.am.inc
new file mode 100644
index 0000000..fcadd77
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/Makefile.am.inc
@@ -0,0 +1,99 @@
+#
+# 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/application.cpp \
+ atf-c++/detail/application.hpp \
+ atf-c++/detail/env.cpp \
+ atf-c++/detail/env.hpp \
+ atf-c++/detail/exceptions.cpp \
+ atf-c++/detail/exceptions.hpp \
+ atf-c++/detail/expand.cpp \
+ atf-c++/detail/expand.hpp \
+ atf-c++/detail/fs.cpp \
+ atf-c++/detail/fs.hpp \
+ atf-c++/detail/parser.cpp \
+ atf-c++/detail/parser.hpp \
+ atf-c++/detail/process.cpp \
+ atf-c++/detail/process.hpp \
+ atf-c++/detail/sanity.hpp \
+ atf-c++/detail/text.cpp \
+ atf-c++/detail/text.hpp \
+ atf-c++/detail/ui.cpp \
+ atf-c++/detail/ui.hpp
+
+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.cpp \
+ atf-c++/detail/test_helpers.hpp
+
+tests_atf_c___detail_PROGRAMS = atf-c++/detail/application_test
+atf_c___detail_application_test_SOURCES = atf-c++/detail/application_test.cpp
+atf_c___detail_application_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/env_test
+atf_c___detail_env_test_SOURCES = atf-c++/detail/env_test.cpp
+atf_c___detail_env_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/exceptions_test
+atf_c___detail_exceptions_test_SOURCES = atf-c++/detail/exceptions_test.cpp
+atf_c___detail_exceptions_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/expand_test
+atf_c___detail_expand_test_SOURCES = atf-c++/detail/expand_test.cpp
+atf_c___detail_expand_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/fs_test
+atf_c___detail_fs_test_SOURCES = atf-c++/detail/fs_test.cpp
+atf_c___detail_fs_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/parser_test
+atf_c___detail_parser_test_SOURCES = atf-c++/detail/parser_test.cpp
+atf_c___detail_parser_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/process_test
+atf_c___detail_process_test_SOURCES = atf-c++/detail/process_test.cpp
+atf_c___detail_process_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/sanity_test
+atf_c___detail_sanity_test_SOURCES = atf-c++/detail/sanity_test.cpp
+atf_c___detail_sanity_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/text_test
+atf_c___detail_text_test_SOURCES = atf-c++/detail/text_test.cpp
+atf_c___detail_text_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+tests_atf_c___detail_PROGRAMS += atf-c++/detail/ui_test
+atf_c___detail_ui_test_SOURCES = atf-c++/detail/ui_test.cpp
+atf_c___detail_ui_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
+
+# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8
diff --git a/contrib/atf/atf-c++/detail/application.cpp b/contrib/atf/atf-c++/detail/application.cpp
new file mode 100644
index 0000000..878b010
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/application.cpp
@@ -0,0 +1,345 @@
+//
+// 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.
+//
+
+#if defined(HAVE_CONFIG_H)
+#include "bconfig.h"
+#endif
+
+extern "C" {
+#include <unistd.h>
+}
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+extern "C" {
+#include "atf-c/defs.h"
+}
+
+#include "application.hpp"
+#include "sanity.hpp"
+#include "ui.hpp"
+
+#if !defined(HAVE_VSNPRINTF_IN_STD)
+namespace std {
+using ::vsnprintf;
+}
+#endif // !defined(HAVE_VSNPRINTF_IN_STD)
+
+namespace impl = atf::application;
+#define IMPL_NAME "atf::application"
+
+// ------------------------------------------------------------------------
+// The "usage_error" class.
+// ------------------------------------------------------------------------
+
+impl::usage_error::usage_error(const char *fmt, ...)
+ throw() :
+ std::runtime_error("usage_error; message unformatted")
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ std::vsnprintf(m_text, sizeof(m_text), fmt, ap);
+ va_end(ap);
+}
+
+impl::usage_error::~usage_error(void)
+ throw()
+{
+}
+
+const char*
+impl::usage_error::what(void)
+ const throw()
+{
+ return m_text;
+}
+
+// ------------------------------------------------------------------------
+// The "application" class.
+// ------------------------------------------------------------------------
+
+impl::option::option(char ch,
+ const std::string& a,
+ const std::string& desc) :
+ m_character(ch),
+ m_argument(a),
+ m_description(desc)
+{
+}
+
+bool
+impl::option::operator<(const impl::option& o)
+ const
+{
+ return m_character < o.m_character;
+}
+
+impl::app::app(const std::string& description,
+ const std::string& manpage,
+ const std::string& global_manpage,
+ const bool use_ui) :
+ m_hflag(false),
+ m_argc(-1),
+ m_argv(NULL),
+ m_prog_name(NULL),
+ m_description(description),
+ m_manpage(manpage),
+ m_global_manpage(global_manpage),
+ m_use_ui(use_ui)
+{
+}
+
+impl::app::~app(void)
+{
+}
+
+bool
+impl::app::inited(void)
+{
+ return m_argc != -1;
+}
+
+impl::app::options_set
+impl::app::options(void)
+{
+ options_set opts = specific_options();
+ if (m_use_ui) {
+ opts.insert(option('h', "", "Shows this help message"));
+ }
+ return opts;
+}
+
+std::string
+impl::app::specific_args(void)
+ const
+{
+ return "";
+}
+
+impl::app::options_set
+impl::app::specific_options(void)
+ const
+{
+ return options_set();
+}
+
+void
+impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,
+ const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)
+{
+}
+
+void
+impl::app::process_options(void)
+{
+ PRE(inited());
+
+ std::string optstr;
+#if defined(HAVE_GNU_GETOPT)
+ optstr += '+'; // Turn on POSIX behavior.
+#endif
+ optstr += ':';
+ {
+ options_set opts = options();
+ for (options_set::const_iterator iter = opts.begin();
+ iter != opts.end(); iter++) {
+ const option& opt = (*iter);
+
+ optstr += opt.m_character;
+ if (!opt.m_argument.empty())
+ optstr += ':';
+ }
+ }
+
+ int ch;
+ const int old_opterr = ::opterr;
+ ::opterr = 0;
+ while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
+ switch (ch) {
+ case 'h':
+ INV(m_use_ui);
+ m_hflag = true;
+ break;
+
+ case ':':
+ throw usage_error("Option -%c requires an argument.",
+ ::optopt);
+
+ case '?':
+ throw usage_error("Unknown option -%c.", ::optopt);
+
+ default:
+ process_option(ch, ::optarg);
+ }
+ }
+ m_argc -= ::optind;
+ m_argv += ::optind;
+
+ // Clear getopt state just in case the test wants to use it.
+ opterr = old_opterr;
+ optind = 1;
+#if defined(HAVE_OPTRESET)
+ optreset = 1;
+#endif
+}
+
+void
+impl::app::usage(std::ostream& os)
+{
+ PRE(inited());
+
+ std::string args = specific_args();
+ if (!args.empty())
+ args = " " + args;
+ os << ui::format_text_with_tag(std::string(m_prog_name) + " [options]" +
+ args, "Usage: ", false) << "\n\n"
+ << ui::format_text(m_description) << "\n\n";
+
+ options_set opts = options();
+ INV(!opts.empty());
+ os << "Available options:\n";
+ size_t coldesc = 0;
+ for (options_set::const_iterator iter = opts.begin();
+ iter != opts.end(); iter++) {
+ const option& opt = (*iter);
+
+ if (opt.m_argument.length() + 1 > coldesc)
+ coldesc = opt.m_argument.length() + 1;
+ }
+ for (options_set::const_iterator iter = opts.begin();
+ iter != opts.end(); iter++) {
+ const option& opt = (*iter);
+
+ std::string tag = std::string(" -") + opt.m_character;
+ if (opt.m_argument.empty())
+ tag += " ";
+ else
+ tag += " " + opt.m_argument + " ";
+ os << ui::format_text_with_tag(opt.m_description, tag, false,
+ coldesc + 10) << "\n";
+ }
+ os << "\n";
+
+ std::string gmp;
+ if (!m_global_manpage.empty())
+ gmp = " and " + m_global_manpage;
+ os << ui::format_text("For more details please see " + m_manpage +
+ gmp + ".")
+ << "\n";
+}
+
+int
+impl::app::run(int argc, char* const* argv)
+{
+ PRE(argc > 0);
+ PRE(argv != NULL);
+
+ m_argc = argc;
+ m_argv = argv;
+
+ m_argv0 = m_argv[0];
+
+ m_prog_name = std::strrchr(m_argv[0], '/');
+ if (m_prog_name == NULL)
+ m_prog_name = m_argv[0];
+ else
+ m_prog_name++;
+
+ // Libtool workaround: if running from within the source tree (binaries
+ // that are not installed yet), skip the "lt-" prefix added to files in
+ // the ".libs" directory to show the real (not temporary) name.
+ if (std::strncmp(m_prog_name, "lt-", 3) == 0)
+ m_prog_name += 3;
+
+ const std::string bug =
+ std::string("This is probably a bug in ") + m_prog_name +
+ " or one of the libraries it uses. Please report this problem to "
+ PACKAGE_BUGREPORT " and provide as many details as possible "
+ "describing how you got to this condition.";
+
+ int errcode;
+ try {
+ int oldargc = m_argc;
+
+ process_options();
+
+ if (m_hflag) {
+ INV(m_use_ui);
+ if (oldargc != 2)
+ throw usage_error("-h must be given alone.");
+
+ usage(std::cout);
+ errcode = EXIT_SUCCESS;
+ } else
+ errcode = main();
+ } catch (const usage_error& e) {
+ if (m_use_ui) {
+ std::cerr << ui::format_error(m_prog_name, e.what()) << "\n"
+ << ui::format_info(m_prog_name, std::string("Type `") +
+ m_prog_name + " -h' for more details.")
+ << "\n";
+ } else {
+ std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
+ std::cerr << m_prog_name << ": See " << m_manpage << " for usage "
+ "details.\n";
+ }
+ errcode = EXIT_FAILURE;
+ } catch (const std::runtime_error& e) {
+ if (m_use_ui) {
+ std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
+ << "\n";
+ } else {
+ std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
+ }
+ errcode = EXIT_FAILURE;
+ } catch (const std::exception& e) {
+ if (m_use_ui) {
+ std::cerr << ui::format_error(m_prog_name, std::string("Caught "
+ "unexpected error: ") + e.what() + "\n" + bug) << "\n";
+ } else {
+ std::cerr << m_prog_name << ": ERROR: Caught unexpected error: "
+ << e.what() << "\n";
+ }
+ errcode = EXIT_FAILURE;
+ } catch (...) {
+ if (m_use_ui) {
+ std::cerr << ui::format_error(m_prog_name, std::string("Caught "
+ "unknown error\n") + bug) << "\n";
+ } else {
+ std::cerr << m_prog_name << ": ERROR: Caught unknown error\n";
+ }
+ errcode = EXIT_FAILURE;
+ }
+ return errcode;
+}
diff --git a/contrib/atf/atf-c++/detail/application.hpp b/contrib/atf/atf-c++/detail/application.hpp
new file mode 100644
index 0000000..9d1f242
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/application.hpp
@@ -0,0 +1,115 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_APPLICATION_HPP_)
+#define _ATF_CXX_APPLICATION_HPP_
+
+#include <ostream>
+#include <set>
+#include <stdexcept>
+#include <string>
+
+namespace atf {
+namespace application {
+
+// ------------------------------------------------------------------------
+// The "usage_error" class.
+// ------------------------------------------------------------------------
+
+class usage_error : public std::runtime_error {
+ char m_text[4096];
+
+public:
+ usage_error(const char*, ...) throw();
+ ~usage_error(void) throw();
+
+ const char* what(void) const throw();
+};
+
+// ------------------------------------------------------------------------
+// The "option" class.
+// ------------------------------------------------------------------------
+
+class option {
+ char m_character;
+ std::string m_argument;
+ std::string m_description;
+
+ friend class app;
+
+public:
+ option(char, const std::string&, const std::string&);
+
+ bool operator<(const option&) const;
+};
+
+// ------------------------------------------------------------------------
+// The "app" class.
+// ------------------------------------------------------------------------
+
+class app {
+ bool m_hflag;
+
+ void process_options(void);
+ void usage(std::ostream&);
+
+ bool inited(void);
+
+protected:
+ typedef std::set< option > options_set;
+
+ int m_argc;
+ char* const* m_argv;
+
+ const char* m_argv0;
+ const char* m_prog_name;
+ std::string m_description;
+ std::string m_manpage, m_global_manpage;
+ const bool m_use_ui;
+
+ options_set options(void);
+
+ // To be redefined.
+ virtual std::string specific_args(void) const;
+ virtual options_set specific_options(void) const;
+ virtual void process_option(int, const char*);
+ virtual int main(void) = 0;
+
+public:
+ app(const std::string&, const std::string&, const std::string&,
+ bool = true);
+ virtual ~app(void);
+
+ int run(int, char* const*);
+};
+
+} // namespace application
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_APPLICATION_HPP_)
diff --git a/contrib/atf/atf-c++/detail/application_test.cpp b/contrib/atf/atf-c++/detail/application_test.cpp
new file mode 100644
index 0000000..2a788bf
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/application_test.cpp
@@ -0,0 +1,94 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <unistd.h>
+}
+
+#include "application.hpp"
+
+#include "../macros.hpp"
+
+class getopt_app : public atf::application::app {
+public:
+ getopt_app(void) : app("description", "manpage", "other") {}
+
+ int main(void)
+ {
+ // Provide an option that is unknown to the application driver and
+ // one that is, together with an argument that would be swallowed by
+ // the test program option if it were recognized.
+ int argc = 4;
+ char arg1[] = "progname";
+ char arg2[] = "-Z";
+ char arg3[] = "-s";
+ char arg4[] = "foo";
+ char *const argv[] = { arg1, arg2, arg3, arg4, NULL };
+
+ int ch;
+ bool zflag;
+
+ // Given that this obviously is an application, and that we used the
+ // same driver to start, we can test getopt(3) right here without doing
+ // any fancy stuff.
+ zflag = false;
+ while ((ch = ::getopt(argc, argv, ":Z")) != -1) {
+ switch (ch) {
+ case 'Z':
+ zflag = true;
+ break;
+
+ case '?':
+ default:
+ if (optopt != 's')
+ ATF_FAIL("Unexpected unknown option found");
+ }
+ }
+
+ ATF_REQUIRE(zflag);
+ ATF_REQUIRE_EQ(1, argc - optind);
+ ATF_REQUIRE_EQ(std::string("foo"), argv[optind]);
+
+ return 0;
+ }
+};
+
+ATF_TEST_CASE_WITHOUT_HEAD(getopt);
+ATF_TEST_CASE_BODY(getopt)
+{
+ int argc = 1;
+ char arg1[] = "progname";
+ char *const argv[] = { arg1, NULL };
+ ATF_REQUIRE_EQ(0, getopt_app().run(argc, argv));
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, getopt);
+}
diff --git a/contrib/atf/atf-c++/detail/env.cpp b/contrib/atf/atf-c++/detail/env.cpp
new file mode 100644
index 0000000..5ca7f09
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/env.cpp
@@ -0,0 +1,73 @@
+//
+// 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.
+//
+
+extern "C" {
+#include "../../atf-c/error.h"
+
+#include "../../atf-c/detail/env.h"
+}
+
+#include "env.hpp"
+#include "exceptions.hpp"
+#include "sanity.hpp"
+
+namespace impl = atf::env;
+#define IMPL_NAME "atf::env"
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+std::string
+impl::get(const std::string& name)
+{
+ return atf_env_get(name.c_str());
+}
+
+bool
+impl::has(const std::string& name)
+{
+ return atf_env_has(name.c_str());
+}
+
+void
+impl::set(const std::string& name, const std::string& val)
+{
+ atf_error_t err = atf_env_set(name.c_str(), val.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+void
+impl::unset(const std::string& name)
+{
+ atf_error_t err = atf_env_unset(name.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
diff --git a/contrib/atf/atf-c++/detail/env.hpp b/contrib/atf/atf-c++/detail/env.hpp
new file mode 100644
index 0000000..afdf69b
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/env.hpp
@@ -0,0 +1,84 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_ENV_HPP_)
+#define _ATF_CXX_ENV_HPP_
+
+#include <string>
+
+namespace atf {
+namespace env {
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief Returns the value of an environment variable.
+//!
+//! Returns the value of the specified environment variable. The variable
+//! must be defined.
+//!
+std::string get(const std::string&);
+
+//!
+//! \brief Checks if the environment has a variable.
+//!
+//! Checks if the environment has a given variable.
+//!
+bool has(const std::string&);
+
+//!
+//! \brief Sets an environment variable to a given value.
+//!
+//! Sets the specified environment variable to the given value. Note that
+//! variables set to the empty string are different to undefined ones.
+//!
+//! Be aware that this alters the program's global status, which in general
+//! is a bad thing to do due to the side-effects it may have. There are
+//! some legitimate usages for this function, though.
+//!
+void set(const std::string&, const std::string&);
+
+//!
+//! \brief Unsets an environment variable.
+//!
+//! Unsets the specified environment variable Note that undefined
+//! variables are different to those defined but set to an empty value.
+//!
+//! Be aware that this alters the program's global status, which in general
+//! is a bad thing to do due to the side-effects it may have. There are
+//! some legitimate usages for this function, though.
+//!
+void unset(const std::string&);
+
+} // namespace env
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_ENV_HPP_)
diff --git a/contrib/atf/atf-c++/detail/env_test.cpp b/contrib/atf/atf-c++/detail/env_test.cpp
new file mode 100644
index 0000000..a7b681d
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/env_test.cpp
@@ -0,0 +1,91 @@
+//
+// 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.
+//
+
+#include "../macros.hpp"
+
+#include "env.hpp"
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(has_get);
+ATF_TEST_CASE_HEAD(has_get)
+{
+ set_md_var("descr", "Tests the has and get functions");
+}
+ATF_TEST_CASE_BODY(has_get)
+{
+ ATF_REQUIRE(atf::env::has("PATH"));
+ ATF_REQUIRE(!atf::env::get("PATH").empty());
+
+ ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
+}
+
+ATF_TEST_CASE(set);
+ATF_TEST_CASE_HEAD(set)
+{
+ set_md_var("descr", "Tests the set function");
+}
+ATF_TEST_CASE_BODY(set)
+{
+ ATF_REQUIRE(atf::env::has("PATH"));
+ const std::string& oldval = atf::env::get("PATH");
+ atf::env::set("PATH", "foo-bar");
+ ATF_REQUIRE(atf::env::get("PATH") != oldval);
+ ATF_REQUIRE_EQ(atf::env::get("PATH"), "foo-bar");
+
+ ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
+ atf::env::set("_UNDEFINED_VARIABLE_", "foo2-bar2");
+ ATF_REQUIRE_EQ(atf::env::get("_UNDEFINED_VARIABLE_"), "foo2-bar2");
+}
+
+ATF_TEST_CASE(unset);
+ATF_TEST_CASE_HEAD(unset)
+{
+ set_md_var("descr", "Tests the unset function");
+}
+ATF_TEST_CASE_BODY(unset)
+{
+ ATF_REQUIRE(atf::env::has("PATH"));
+ atf::env::unset("PATH");
+ ATF_REQUIRE(!atf::env::has("PATH"));
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, has_get);
+ ATF_ADD_TEST_CASE(tcs, set);
+ ATF_ADD_TEST_CASE(tcs, unset);
+}
diff --git a/contrib/atf/atf-c++/detail/exceptions.cpp b/contrib/atf/atf-c++/detail/exceptions.cpp
new file mode 100644
index 0000000..79c5b48
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/exceptions.cpp
@@ -0,0 +1,157 @@
+//
+// 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.
+//
+
+#if defined(HAVE_CONFIG_H)
+#include "bconfig.h"
+#endif
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstring>
+#include <new>
+
+extern "C" {
+#include "../../atf-c/error.h"
+};
+
+#include "exceptions.hpp"
+#include "sanity.hpp"
+
+// ------------------------------------------------------------------------
+// The "system_error" type.
+// ------------------------------------------------------------------------
+
+atf::system_error::system_error(const std::string& who,
+ const std::string& message,
+ int sys_err) :
+ std::runtime_error(who + ": " + message),
+ m_sys_err(sys_err)
+{
+}
+
+atf::system_error::~system_error(void)
+ throw()
+{
+}
+
+int
+atf::system_error::code(void)
+ const
+ throw()
+{
+ return m_sys_err;
+}
+
+const char*
+atf::system_error::what(void)
+ const
+ throw()
+{
+ try {
+ if (m_message.length() == 0) {
+ m_message = std::string(std::runtime_error::what()) + ": ";
+ m_message += ::strerror(m_sys_err);
+ }
+
+ return m_message.c_str();
+ } catch (...) {
+ return "Unable to format system_error message";
+ }
+}
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+static
+void
+throw_libc_error(atf_error_t err)
+{
+ PRE(atf_error_is(err, "libc"));
+
+ const int ecode = atf_libc_error_code(err);
+ const std::string msg = atf_libc_error_msg(err);
+ atf_error_free(err);
+ throw atf::system_error("XXX", msg, ecode);
+}
+
+static
+void
+throw_no_memory_error(atf_error_t err)
+{
+ PRE(atf_error_is(err, "no_memory"));
+
+ atf_error_free(err);
+ throw std::bad_alloc();
+}
+
+static
+void
+throw_unknown_error(atf_error_t err)
+{
+ PRE(atf_is_error(err));
+
+ static char buf[4096];
+ atf_error_format(err, buf, sizeof(buf));
+ atf_error_free(err);
+ throw std::runtime_error(buf);
+}
+
+void
+atf::throw_atf_error(atf_error_t err)
+{
+ static struct handler {
+ const char* m_name;
+ void (*m_func)(atf_error_t);
+ } handlers[] = {
+ { "libc", throw_libc_error },
+ { "no_memory", throw_no_memory_error },
+ { NULL, throw_unknown_error },
+ };
+
+ PRE(atf_is_error(err));
+
+ handler* h = handlers;
+ while (h->m_name != NULL) {
+ if (atf_error_is(err, h->m_name)) {
+ h->m_func(err);
+ UNREACHABLE;
+ } else
+ h++;
+ }
+ // XXX: I'm not sure that raising an "unknown" error is a wise thing
+ // to do here. The C++ binding is supposed to have feature parity
+ // with the C one, so all possible errors raised by the C library
+ // should have their counterpart in the C++ library. Still, removing
+ // this will require some code auditing that I can't afford at the
+ // moment.
+ INV(h->m_name == NULL && h->m_func != NULL);
+ h->m_func(err);
+ UNREACHABLE;
+}
diff --git a/contrib/atf/atf-c++/detail/exceptions.hpp b/contrib/atf/atf-c++/detail/exceptions.hpp
new file mode 100644
index 0000000..f655a84
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/exceptions.hpp
@@ -0,0 +1,99 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_EXCEPTIONS_HPP_)
+#define _ATF_CXX_EXCEPTIONS_HPP_
+
+#include <stdexcept>
+#include <string>
+
+extern "C" {
+struct atf_error;
+}
+
+namespace atf {
+
+template< class T >
+class not_found_error :
+ public std::runtime_error
+{
+ T m_value;
+
+public:
+ not_found_error(const std::string& message, const T& value) throw();
+
+ virtual ~not_found_error(void) throw();
+
+ const T& get_value(void) const throw();
+};
+
+template< class T >
+inline
+not_found_error< T >::not_found_error(const std::string& message,
+ const T& value)
+ throw() :
+ std::runtime_error(message),
+ m_value(value)
+{
+}
+
+template< class T >
+inline
+not_found_error< T >::~not_found_error(void)
+ throw()
+{
+}
+
+template< class T >
+inline
+const T&
+not_found_error< T >::get_value(void)
+ const
+ throw()
+{
+ return m_value;
+}
+
+class system_error : public std::runtime_error {
+ int m_sys_err;
+ mutable std::string m_message;
+
+public:
+ system_error(const std::string&, const std::string&, int);
+ ~system_error(void) throw();
+
+ int code(void) const throw();
+ const char* what(void) const throw();
+};
+
+void throw_atf_error(struct atf_error *);
+
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_EXCEPTIONS_HPP_)
diff --git a/contrib/atf/atf-c++/detail/exceptions_test.cpp b/contrib/atf/atf-c++/detail/exceptions_test.cpp
new file mode 100644
index 0000000..821c192
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/exceptions_test.cpp
@@ -0,0 +1,148 @@
+//
+// 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.
+//
+
+extern "C" {
+#include "../../atf-c/error.h"
+}
+
+#include <cstdio>
+#include <new>
+
+#include "../macros.hpp"
+
+#include "exceptions.hpp"
+#include "sanity.hpp"
+
+// ------------------------------------------------------------------------
+// The "test" error.
+// ------------------------------------------------------------------------
+
+extern "C" {
+
+struct test_error_data {
+ const char* m_msg;
+};
+typedef struct test_error_data test_error_data_t;
+
+static
+void
+test_format(const atf_error_t err, char *buf, size_t buflen)
+{
+ const test_error_data_t* data;
+
+ PRE(atf_error_is(err, "test"));
+
+ data = static_cast< const test_error_data_t * >(atf_error_data(err));
+ snprintf(buf, buflen, "Message: %s", data->m_msg);
+}
+
+static
+atf_error_t
+test_error(const char* msg)
+{
+ atf_error_t err;
+ test_error_data_t data;
+
+ data.m_msg = msg;
+
+ err = atf_error_new("test", &data, sizeof(data), test_format);
+
+ return err;
+}
+
+} // extern
+
+// ------------------------------------------------------------------------
+// Tests cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(throw_atf_error_libc);
+ATF_TEST_CASE_HEAD(throw_atf_error_libc)
+{
+ set_md_var("descr", "Tests the throw_atf_error function when raising "
+ "a libc error");
+}
+ATF_TEST_CASE_BODY(throw_atf_error_libc)
+{
+ try {
+ atf::throw_atf_error(atf_libc_error(1, "System error 1"));
+ } catch (const atf::system_error& e) {
+ ATF_REQUIRE(e.code() == 1);
+ ATF_REQUIRE(std::string(e.what()).find("System error 1") !=
+ std::string::npos);
+ } catch (const std::exception& e) {
+ ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
+ }
+}
+
+ATF_TEST_CASE(throw_atf_error_no_memory);
+ATF_TEST_CASE_HEAD(throw_atf_error_no_memory)
+{
+ set_md_var("descr", "Tests the throw_atf_error function when raising "
+ "a no_memory error");
+}
+ATF_TEST_CASE_BODY(throw_atf_error_no_memory)
+{
+ try {
+ atf::throw_atf_error(atf_no_memory_error());
+ } catch (const std::bad_alloc&) {
+ } catch (const std::exception& e) {
+ ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
+ }
+}
+
+ATF_TEST_CASE(throw_atf_error_unknown);
+ATF_TEST_CASE_HEAD(throw_atf_error_unknown)
+{
+ set_md_var("descr", "Tests the throw_atf_error function when raising "
+ "an unknown error");
+}
+ATF_TEST_CASE_BODY(throw_atf_error_unknown)
+{
+ try {
+ atf::throw_atf_error(test_error("The message"));
+ } catch (const std::runtime_error& e) {
+ const std::string msg = e.what();
+ ATF_REQUIRE(msg.find("The message") != std::string::npos);
+ } catch (const std::exception& e) {
+ ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
+ }
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, throw_atf_error_libc);
+ ATF_ADD_TEST_CASE(tcs, throw_atf_error_no_memory);
+ ATF_ADD_TEST_CASE(tcs, throw_atf_error_unknown);
+}
diff --git a/contrib/atf/atf-c++/detail/expand.cpp b/contrib/atf/atf-c++/detail/expand.cpp
new file mode 100644
index 0000000..f6f9b68
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/expand.cpp
@@ -0,0 +1,81 @@
+//
+// 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.
+//
+
+#include <stdexcept>
+
+#include "expand.hpp"
+#include "text.hpp"
+
+namespace impl = atf::expand;
+#define IMPL_NAME "atf::expand"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+namespace {
+
+std::string
+glob_to_regex(const std::string& glob)
+{
+ std::string regex;
+ regex.reserve(glob.length() * 2);
+
+ regex += '^';
+ for (std::string::const_iterator iter = glob.begin(); iter != glob.end();
+ iter++) {
+ switch (*iter) {
+ case '*': regex += ".*"; break;
+ case '?': regex += "."; break;
+ default: regex += *iter;
+ }
+ }
+ regex += '$';
+
+ return regex;
+}
+
+} // anonymous namespace
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+bool
+impl::is_glob(const std::string& glob)
+{
+ // NOTE: Keep this in sync with glob_to_regex!
+ return glob.find_first_of("*?") != std::string::npos;
+}
+
+bool
+impl::matches_glob(const std::string& glob, const std::string& candidate)
+{
+ return atf::text::match(candidate, glob_to_regex(glob));
+}
diff --git a/contrib/atf/atf-c++/detail/expand.hpp b/contrib/atf/atf-c++/detail/expand.hpp
new file mode 100644
index 0000000..7f4071e
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/expand.hpp
@@ -0,0 +1,82 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_EXPAND_HPP_)
+#define _ATF_CXX_EXPAND_HPP_
+
+#include <string>
+#include <vector>
+
+namespace atf {
+namespace expand {
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief Checks if the given string is a glob pattern.
+//!
+//! Returns true if the given string is a glob pattern; i.e. if it contains
+//! any character that will be expanded by expand_glob.
+//!
+bool is_glob(const std::string&);
+
+//!
+//! \brief Checks if a given string matches a glob pattern.
+//!
+//! Given a glob pattern and a string, checks whether the former matches
+//! the latter. Returns a boolean indicating this condition.
+//!
+bool matches_glob(const std::string&, const std::string&);
+
+//!
+//! \brief Expands a glob pattern among multiple candidates.
+//!
+//! Given a glob pattern and a set of candidate strings, checks which of
+//! those strings match the glob pattern and returns them.
+//!
+template< class T >
+std::vector< std::string > expand_glob(const std::string& glob,
+ const T& candidates)
+{
+ std::vector< std::string > exps;
+
+ for (typename T::const_iterator iter = candidates.begin();
+ iter != candidates.end(); iter++)
+ if (matches_glob(glob, *iter))
+ exps.push_back(*iter);
+
+ return exps;
+}
+
+} // namespace expand
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_EXPAND_HPP_)
diff --git a/contrib/atf/atf-c++/detail/expand_test.cpp b/contrib/atf/atf-c++/detail/expand_test.cpp
new file mode 100644
index 0000000..222ab3a
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/expand_test.cpp
@@ -0,0 +1,272 @@
+//
+// 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.
+//
+
+#include <cstring>
+
+#include "../macros.hpp"
+
+#include "expand.hpp"
+
+// XXX Many of the tests here are duplicated in atf-c/t_expand. Should
+// find a way to easily share them, or maybe remove the ones here.
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(is_glob);
+ATF_TEST_CASE_HEAD(is_glob)
+{
+ set_md_var("descr", "Tests the is_glob function.");
+}
+ATF_TEST_CASE_BODY(is_glob)
+{
+ using atf::expand::is_glob;
+
+ ATF_REQUIRE(!is_glob(""));
+ ATF_REQUIRE(!is_glob("a"));
+ ATF_REQUIRE(!is_glob("foo"));
+
+ ATF_REQUIRE( is_glob("*"));
+ ATF_REQUIRE( is_glob("a*"));
+ ATF_REQUIRE( is_glob("*a"));
+ ATF_REQUIRE( is_glob("a*b"));
+
+ ATF_REQUIRE( is_glob("?"));
+ ATF_REQUIRE( is_glob("a?"));
+ ATF_REQUIRE( is_glob("?a"));
+ ATF_REQUIRE( is_glob("a?b"));
+}
+
+ATF_TEST_CASE(matches_glob_plain);
+ATF_TEST_CASE_HEAD(matches_glob_plain)
+{
+ set_md_var("descr", "Tests the matches_glob function by using plain "
+ "text strings as patterns only.");
+}
+ATF_TEST_CASE_BODY(matches_glob_plain)
+{
+ using atf::expand::matches_glob;
+
+ ATF_REQUIRE( matches_glob("", ""));
+ ATF_REQUIRE(!matches_glob("a", ""));
+ ATF_REQUIRE(!matches_glob("", "a"));
+
+ ATF_REQUIRE( matches_glob("ab", "ab"));
+ ATF_REQUIRE(!matches_glob("abc", "ab"));
+ ATF_REQUIRE(!matches_glob("ab", "abc"));
+}
+
+ATF_TEST_CASE(matches_glob_star);
+ATF_TEST_CASE_HEAD(matches_glob_star)
+{
+ set_md_var("descr", "Tests the matches_glob function by using the '*' "
+ "meta-character as part of the pattern.");
+}
+ATF_TEST_CASE_BODY(matches_glob_star)
+{
+ using atf::expand::matches_glob;
+
+ ATF_REQUIRE( matches_glob("*", ""));
+ ATF_REQUIRE( matches_glob("*", "a"));
+ ATF_REQUIRE( matches_glob("*", "ab"));
+
+ ATF_REQUIRE(!matches_glob("a*", ""));
+ ATF_REQUIRE( matches_glob("a*", "a"));
+ ATF_REQUIRE( matches_glob("a*", "aa"));
+ ATF_REQUIRE( matches_glob("a*", "ab"));
+ ATF_REQUIRE( matches_glob("a*", "abc"));
+ ATF_REQUIRE(!matches_glob("a*", "ba"));
+
+ ATF_REQUIRE( matches_glob("*a", "a"));
+ ATF_REQUIRE( matches_glob("*a", "ba"));
+ ATF_REQUIRE(!matches_glob("*a", "bc"));
+ ATF_REQUIRE(!matches_glob("*a", "bac"));
+
+ ATF_REQUIRE( matches_glob("*ab", "ab"));
+ ATF_REQUIRE( matches_glob("*ab", "aab"));
+ ATF_REQUIRE( matches_glob("*ab", "aaab"));
+ ATF_REQUIRE( matches_glob("*ab", "bab"));
+ ATF_REQUIRE(!matches_glob("*ab", "bcb"));
+ ATF_REQUIRE(!matches_glob("*ab", "bacb"));
+
+ ATF_REQUIRE( matches_glob("a*b", "ab"));
+ ATF_REQUIRE( matches_glob("a*b", "acb"));
+ ATF_REQUIRE( matches_glob("a*b", "acdeb"));
+ ATF_REQUIRE(!matches_glob("a*b", "acdebz"));
+ ATF_REQUIRE(!matches_glob("a*b", "zacdeb"));
+}
+
+ATF_TEST_CASE(matches_glob_question);
+ATF_TEST_CASE_HEAD(matches_glob_question)
+{
+ set_md_var("descr", "Tests the matches_glob function by using the '?' "
+ "meta-character as part of the pattern.");
+}
+ATF_TEST_CASE_BODY(matches_glob_question)
+{
+ using atf::expand::matches_glob;
+
+ ATF_REQUIRE(!matches_glob("?", ""));
+ ATF_REQUIRE( matches_glob("?", "a"));
+ ATF_REQUIRE(!matches_glob("?", "ab"));
+
+ ATF_REQUIRE( matches_glob("?", "b"));
+ ATF_REQUIRE( matches_glob("?", "c"));
+
+ ATF_REQUIRE( matches_glob("a?", "ab"));
+ ATF_REQUIRE( matches_glob("a?", "ac"));
+ ATF_REQUIRE(!matches_glob("a?", "ca"));
+
+ ATF_REQUIRE( matches_glob("???", "abc"));
+ ATF_REQUIRE( matches_glob("???", "def"));
+ ATF_REQUIRE(!matches_glob("???", "a"));
+ ATF_REQUIRE(!matches_glob("???", "ab"));
+ ATF_REQUIRE(!matches_glob("???", "abcd"));
+}
+
+ATF_TEST_CASE(expand_glob_base);
+ATF_TEST_CASE_HEAD(expand_glob_base)
+{
+ set_md_var("descr", "Tests the expand_glob function with random "
+ "patterns.");
+}
+ATF_TEST_CASE_BODY(expand_glob_base)
+{
+ using atf::expand::expand_glob;
+
+ std::vector< std::string > candidates;
+ candidates.push_back("foo");
+ candidates.push_back("bar");
+ candidates.push_back("baz");
+ candidates.push_back("foobar");
+ candidates.push_back("foobarbaz");
+ candidates.push_back("foobarbazfoo");
+
+ std::vector< std::string > exps;
+
+ exps = expand_glob("foo", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 1);
+ ATF_REQUIRE(exps[0] == "foo");
+
+ exps = expand_glob("bar", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 1);
+ ATF_REQUIRE(exps[0] == "bar");
+
+ exps = expand_glob("foo*", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 4);
+ ATF_REQUIRE(exps[0] == "foo");
+ ATF_REQUIRE(exps[1] == "foobar");
+ ATF_REQUIRE(exps[2] == "foobarbaz");
+ ATF_REQUIRE(exps[3] == "foobarbazfoo");
+
+ exps = expand_glob("*foo", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 2);
+ ATF_REQUIRE(exps[0] == "foo");
+ ATF_REQUIRE(exps[1] == "foobarbazfoo");
+
+ exps = expand_glob("*foo*", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 4);
+ ATF_REQUIRE(exps[0] == "foo");
+ ATF_REQUIRE(exps[1] == "foobar");
+ ATF_REQUIRE(exps[2] == "foobarbaz");
+ ATF_REQUIRE(exps[3] == "foobarbazfoo");
+
+ exps = expand_glob("ba", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 0);
+
+ exps = expand_glob("ba*", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 2);
+ ATF_REQUIRE(exps[0] == "bar");
+ ATF_REQUIRE(exps[1] == "baz");
+
+ exps = expand_glob("*ba", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 0);
+
+ exps = expand_glob("*ba*", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 5);
+ ATF_REQUIRE(exps[0] == "bar");
+ ATF_REQUIRE(exps[1] == "baz");
+ ATF_REQUIRE(exps[2] == "foobar");
+ ATF_REQUIRE(exps[3] == "foobarbaz");
+ ATF_REQUIRE(exps[4] == "foobarbazfoo");
+}
+
+ATF_TEST_CASE(expand_glob_tps);
+ATF_TEST_CASE_HEAD(expand_glob_tps)
+{
+ set_md_var("descr", "Tests the expand_glob function with patterns that "
+ "match typical test program names. This is just a subcase "
+ "of expand_base, but it is nice to make sure that it really "
+ "works.");
+}
+ATF_TEST_CASE_BODY(expand_glob_tps)
+{
+ using atf::expand::expand_glob;
+
+ std::vector< std::string > candidates;
+ candidates.push_back("Atffile");
+ candidates.push_back("h_foo");
+ candidates.push_back("t_foo");
+ candidates.push_back("t_bar");
+ candidates.push_back("t_baz");
+ candidates.push_back("foo_helper");
+ candidates.push_back("foo_test");
+ candidates.push_back("bar_test");
+ candidates.push_back("baz_test");
+
+ std::vector< std::string > exps;
+
+ exps = expand_glob("t_*", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 3);
+ ATF_REQUIRE(exps[0] == "t_foo");
+ ATF_REQUIRE(exps[1] == "t_bar");
+ ATF_REQUIRE(exps[2] == "t_baz");
+
+ exps = expand_glob("*_test", candidates);
+ ATF_REQUIRE_EQ(exps.size(), 3);
+ ATF_REQUIRE(exps[0] == "foo_test");
+ ATF_REQUIRE(exps[1] == "bar_test");
+ ATF_REQUIRE(exps[2] == "baz_test");
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the tests for the free functions.
+ ATF_ADD_TEST_CASE(tcs, is_glob);
+ ATF_ADD_TEST_CASE(tcs, matches_glob_plain);
+ ATF_ADD_TEST_CASE(tcs, matches_glob_star);
+ ATF_ADD_TEST_CASE(tcs, matches_glob_question);
+ ATF_ADD_TEST_CASE(tcs, expand_glob_base);
+ ATF_ADD_TEST_CASE(tcs, expand_glob_tps);
+}
diff --git a/contrib/atf/atf-c++/detail/fs.cpp b/contrib/atf/atf-c++/detail/fs.cpp
new file mode 100644
index 0000000..3517e26
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/fs.cpp
@@ -0,0 +1,517 @@
+//
+// 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.
+//
+
+#if defined(HAVE_CONFIG_H)
+#include "bconfig.h"
+#endif
+
+extern "C" {
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <unistd.h>
+}
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+
+extern "C" {
+#include "../../atf-c/error.h"
+}
+
+#include "../utils.hpp"
+
+#include "exceptions.hpp"
+#include "env.hpp"
+#include "fs.hpp"
+#include "process.hpp"
+#include "sanity.hpp"
+#include "text.hpp"
+
+namespace impl = atf::fs;
+#define IMPL_NAME "atf::fs"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+static bool safe_access(const impl::path&, int, int);
+
+//!
+//! \brief A controlled version of access(2).
+//!
+//! This function reimplements the standard access(2) system call to
+//! safely control its exit status and raise an exception in case of
+//! failure.
+//!
+static
+bool
+safe_access(const impl::path& p, int mode, int experr)
+{
+ bool ok;
+
+ atf_error_t err = atf_fs_eaccess(p.c_path(), mode);
+ if (atf_is_error(err)) {
+ if (atf_error_is(err, "libc")) {
+ if (atf_libc_error_code(err) == experr) {
+ atf_error_free(err);
+ ok = false;
+ } else {
+ atf::throw_atf_error(err);
+ // XXX Silence warning; maybe throw_atf_error should be
+ // an exception and not a function.
+ ok = false;
+ }
+ } else {
+ atf::throw_atf_error(err);
+ // XXX Silence warning; maybe throw_atf_error should be
+ // an exception and not a function.
+ ok = false;
+ }
+ } else
+ ok = true;
+
+ return ok;
+}
+
+// ------------------------------------------------------------------------
+// The "path" class.
+// ------------------------------------------------------------------------
+
+impl::path::path(const std::string& s)
+{
+ atf_error_t err = atf_fs_path_init_fmt(&m_path, "%s", s.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+impl::path::path(const path& p)
+{
+ atf_error_t err = atf_fs_path_copy(&m_path, &p.m_path);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+impl::path::path(const atf_fs_path_t *p)
+{
+ atf_error_t err = atf_fs_path_copy(&m_path, p);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+impl::path::~path(void)
+{
+ atf_fs_path_fini(&m_path);
+}
+
+const char*
+impl::path::c_str(void)
+ const
+{
+ return atf_fs_path_cstring(&m_path);
+}
+
+const atf_fs_path_t*
+impl::path::c_path(void)
+ const
+{
+ return &m_path;
+}
+
+std::string
+impl::path::str(void)
+ const
+{
+ return c_str();
+}
+
+bool
+impl::path::is_absolute(void)
+ const
+{
+ return atf_fs_path_is_absolute(&m_path);
+}
+
+bool
+impl::path::is_root(void)
+ const
+{
+ return atf_fs_path_is_root(&m_path);
+}
+
+impl::path
+impl::path::branch_path(void)
+ const
+{
+ atf_fs_path_t bp;
+ atf_error_t err;
+
+ err = atf_fs_path_branch_path(&m_path, &bp);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ path p(atf_fs_path_cstring(&bp));
+ atf_fs_path_fini(&bp);
+ return p;
+}
+
+std::string
+impl::path::leaf_name(void)
+ const
+{
+ atf_dynstr_t ln;
+ atf_error_t err;
+
+ err = atf_fs_path_leaf_name(&m_path, &ln);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ std::string s(atf_dynstr_cstring(&ln));
+ atf_dynstr_fini(&ln);
+ return s;
+}
+
+impl::path
+impl::path::to_absolute(void)
+ const
+{
+ atf_fs_path_t pa;
+
+ atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ path p(atf_fs_path_cstring(&pa));
+ atf_fs_path_fini(&pa);
+ return p;
+}
+
+impl::path&
+impl::path::operator=(const path& p)
+{
+ atf_fs_path_t tmp;
+
+ atf_error_t err = atf_fs_path_init_fmt(&tmp, "%s", p.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ else {
+ atf_fs_path_fini(&m_path);
+ m_path = tmp;
+ }
+
+ return *this;
+}
+
+bool
+impl::path::operator==(const path& p)
+ const
+{
+ return atf_equal_fs_path_fs_path(&m_path, &p.m_path);
+}
+
+bool
+impl::path::operator!=(const path& p)
+ const
+{
+ return !atf_equal_fs_path_fs_path(&m_path, &p.m_path);
+}
+
+impl::path
+impl::path::operator/(const std::string& p)
+ const
+{
+ path p2 = *this;
+
+ atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", p.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return p2;
+}
+
+impl::path
+impl::path::operator/(const path& p)
+ const
+{
+ path p2 = *this;
+
+ atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s",
+ atf_fs_path_cstring(&p.m_path));
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return p2;
+}
+
+bool
+impl::path::operator<(const path& p)
+ const
+{
+ const char *s1 = atf_fs_path_cstring(&m_path);
+ const char *s2 = atf_fs_path_cstring(&p.m_path);
+ return std::strcmp(s1, s2) < 0;
+}
+
+// ------------------------------------------------------------------------
+// The "file_info" class.
+// ------------------------------------------------------------------------
+
+const int impl::file_info::blk_type = atf_fs_stat_blk_type;
+const int impl::file_info::chr_type = atf_fs_stat_chr_type;
+const int impl::file_info::dir_type = atf_fs_stat_dir_type;
+const int impl::file_info::fifo_type = atf_fs_stat_fifo_type;
+const int impl::file_info::lnk_type = atf_fs_stat_lnk_type;
+const int impl::file_info::reg_type = atf_fs_stat_reg_type;
+const int impl::file_info::sock_type = atf_fs_stat_sock_type;
+const int impl::file_info::wht_type = atf_fs_stat_wht_type;
+
+impl::file_info::file_info(const path& p)
+{
+ atf_error_t err;
+
+ err = atf_fs_stat_init(&m_stat, p.c_path());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+impl::file_info::file_info(const file_info& fi)
+{
+ atf_fs_stat_copy(&m_stat, &fi.m_stat);
+}
+
+impl::file_info::~file_info(void)
+{
+ atf_fs_stat_fini(&m_stat);
+}
+
+dev_t
+impl::file_info::get_device(void)
+ const
+{
+ return atf_fs_stat_get_device(&m_stat);
+}
+
+ino_t
+impl::file_info::get_inode(void)
+ const
+{
+ return atf_fs_stat_get_inode(&m_stat);
+}
+
+mode_t
+impl::file_info::get_mode(void)
+ const
+{
+ return atf_fs_stat_get_mode(&m_stat);
+}
+
+off_t
+impl::file_info::get_size(void)
+ const
+{
+ return atf_fs_stat_get_size(&m_stat);
+}
+
+int
+impl::file_info::get_type(void)
+ const
+{
+ return atf_fs_stat_get_type(&m_stat);
+}
+
+bool
+impl::file_info::is_owner_readable(void)
+ const
+{
+ return atf_fs_stat_is_owner_readable(&m_stat);
+}
+
+bool
+impl::file_info::is_owner_writable(void)
+ const
+{
+ return atf_fs_stat_is_owner_writable(&m_stat);
+}
+
+bool
+impl::file_info::is_owner_executable(void)
+ const
+{
+ return atf_fs_stat_is_owner_executable(&m_stat);
+}
+
+bool
+impl::file_info::is_group_readable(void)
+ const
+{
+ return atf_fs_stat_is_group_readable(&m_stat);
+}
+
+bool
+impl::file_info::is_group_writable(void)
+ const
+{
+ return atf_fs_stat_is_group_writable(&m_stat);
+}
+
+bool
+impl::file_info::is_group_executable(void)
+ const
+{
+ return atf_fs_stat_is_group_executable(&m_stat);
+}
+
+bool
+impl::file_info::is_other_readable(void)
+ const
+{
+ return atf_fs_stat_is_other_readable(&m_stat);
+}
+
+bool
+impl::file_info::is_other_writable(void)
+ const
+{
+ return atf_fs_stat_is_other_writable(&m_stat);
+}
+
+bool
+impl::file_info::is_other_executable(void)
+ const
+{
+ return atf_fs_stat_is_other_executable(&m_stat);
+}
+
+// ------------------------------------------------------------------------
+// The "directory" class.
+// ------------------------------------------------------------------------
+
+impl::directory::directory(const path& p)
+{
+ DIR* dp = ::opendir(p.c_str());
+ if (dp == NULL)
+ throw system_error(IMPL_NAME "::directory::directory(" +
+ p.str() + ")", "opendir(3) failed", errno);
+
+ struct dirent* dep;
+ while ((dep = ::readdir(dp)) != NULL) {
+ path entryp = p / dep->d_name;
+ insert(value_type(dep->d_name, file_info(entryp)));
+ }
+
+ if (::closedir(dp) == -1)
+ throw system_error(IMPL_NAME "::directory::directory(" +
+ p.str() + ")", "closedir(3) failed", errno);
+}
+
+std::set< std::string >
+impl::directory::names(void)
+ const
+{
+ std::set< std::string > ns;
+
+ for (const_iterator iter = begin(); iter != end(); iter++)
+ ns.insert((*iter).first);
+
+ return ns;
+}
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+bool
+impl::exists(const path& p)
+{
+ atf_error_t err;
+ bool b;
+
+ err = atf_fs_exists(p.c_path(), &b);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return b;
+}
+
+bool
+impl::have_prog_in_path(const std::string& prog)
+{
+ PRE(prog.find('/') == std::string::npos);
+
+ // Do not bother to provide a default value for PATH. If it is not
+ // there something is broken in the user's environment.
+ if (!atf::env::has("PATH"))
+ throw std::runtime_error("PATH not defined in the environment");
+ std::vector< std::string > dirs =
+ atf::text::split(atf::env::get("PATH"), ":");
+
+ bool found = false;
+ for (std::vector< std::string >::const_iterator iter = dirs.begin();
+ !found && iter != dirs.end(); iter++) {
+ const path& dir = path(*iter);
+
+ if (is_executable(dir / prog))
+ found = true;
+ }
+ return found;
+}
+
+bool
+impl::is_executable(const path& p)
+{
+ if (!exists(p))
+ return false;
+ return safe_access(p, atf_fs_access_x, EACCES);
+}
+
+void
+impl::remove(const path& p)
+{
+ if (file_info(p).get_type() == file_info::dir_type)
+ throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
+ "Is a directory",
+ EPERM);
+ if (::unlink(p.c_str()) == -1)
+ throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
+ "unlink(" + p.str() + ") failed",
+ errno);
+}
+
+void
+impl::rmdir(const path& p)
+{
+ atf_error_t err = atf_fs_rmdir(p.c_path());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
diff --git a/contrib/atf/atf-c++/detail/fs.hpp b/contrib/atf/atf-c++/detail/fs.hpp
new file mode 100644
index 0000000..4ffb39b
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/fs.hpp
@@ -0,0 +1,391 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_FS_HPP_)
+#define _ATF_CXX_FS_HPP_
+
+extern "C" {
+#include <sys/types.h>
+}
+
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <stdexcept>
+#include <string>
+
+extern "C" {
+#include "../../atf-c/detail/fs.h"
+}
+
+namespace atf {
+
+namespace io {
+class systembuf;
+} // namespace io
+
+namespace fs {
+
+// ------------------------------------------------------------------------
+// The "path" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief A class to represent a path to a file.
+//!
+//! The path class represents the route to a file or directory in the
+//! file system. All file manipulation operations use this class to
+//! represent their arguments as it takes care of normalizing user-provided
+//! strings and ensures they are valid.
+//!
+//! It is important to note that the file pointed to by a path need not
+//! exist.
+//!
+class path {
+ //!
+ //! \brief Internal representation of a path.
+ //!
+ atf_fs_path_t m_path;
+
+public:
+ //! \brief Constructs a new path from a user-provided string.
+ //!
+ //! This constructor takes a string, either provided by the program's
+ //! code or by the user and constructs a new path object. The string
+ //! is normalized to not contain multiple delimiters together and to
+ //! remove any trailing one.
+ //!
+ //! The input string cannot be empty.
+ //!
+ explicit path(const std::string&);
+
+ //!
+ //! \brief Copy constructor.
+ //!
+ path(const path&);
+
+ //!
+ //! \brief Copy constructor.
+ //!
+ path(const atf_fs_path_t *);
+
+ //!
+ //! \brief Destructor for the path class.
+ //!
+ ~path(void);
+
+ //!
+ //! \brief Returns a pointer to a C-style string representing this path.
+ //!
+ const char* c_str(void) const;
+
+ //!
+ //! \brief Returns a pointer to the implementation data.
+ //!
+ const atf_fs_path_t* c_path(void) const;
+
+ //!
+ //! \brief Returns a string representing this path.
+ //! XXX Really needed?
+ //!
+ std::string str(void) const;
+
+ //!
+ //! \brief Returns the branch path of this path.
+ //!
+ //! Calculates and returns the branch path of this path. In other
+ //! words, it returns what the standard ::dirname function would return.
+ //!
+ path branch_path(void) const;
+
+ //!
+ //! \brief Returns the leaf name of this path.
+ //!
+ //! Calculates and returns the leaf name of this path. In other words,
+ //! it returns what the standard ::basename function would return.
+ //!
+ std::string leaf_name(void) const;
+
+ //!
+ //! \brief Checks whether this path is absolute or not.
+ //!
+ //! Returns a boolean indicating if this is an absolute path or not;
+ //! i.e. if it starts with a slash.
+ //!
+ bool is_absolute(void) const;
+
+ //!
+ //! \brief Checks whether this path points to the root directory or not.
+ //!
+ //! Returns a boolean indicating if this is path points to the root
+ //! directory or not. The checks made by this are extremely simple (so
+ //! the results cannot always be trusted) but they are enough for our
+ //! modest sanity-checking needs. I.e. "/../" could return false.
+ //!
+ bool is_root(void) const;
+
+ //!
+ //! \brief Converts the path to be absolute.
+ //!
+ //! \pre The path was not absolute.
+ //!
+ path to_absolute(void) const;
+
+ //!
+ //! \brief Assignment operator.
+ //!
+ path& operator=(const path&);
+
+ //!
+ //! \brief Checks if two paths are equal.
+ //!
+ bool operator==(const path&) const;
+
+ //!
+ //! \brief Checks if two paths are different.
+ //!
+ bool operator!=(const path&) const;
+
+ //!
+ //! \brief Concatenates a path with a string.
+ //!
+ //! Constructs a new path object that is the concatenation of the
+ //! left-hand path with the right-hand string. The string is normalized
+ //! before the concatenation, and a path delimiter is introduced between
+ //! the two components if needed.
+ //!
+ path operator/(const std::string&) const;
+
+ //!
+ //! \brief Concatenates a path with another path.
+ //!
+ //! Constructs a new path object that is the concatenation of the
+ //! left-hand path with the right-hand one. A path delimiter is
+ //! introduced between the two components if needed.
+ //!
+ path operator/(const path&) const;
+
+ //!
+ //! \brief Checks if a path has to be sorted before another one
+ //! lexicographically.
+ //!
+ bool operator<(const path&) const;
+};
+
+// ------------------------------------------------------------------------
+// The "file_info" class.
+// ------------------------------------------------------------------------
+
+class directory;
+
+//!
+//! \brief A class that contains information about a file.
+//!
+//! The file_info class holds information about an specific file that
+//! exists in the file system.
+//!
+class file_info {
+ atf_fs_stat_t m_stat;
+
+public:
+ //!
+ //! \brief The file's type.
+ //!
+ static const int blk_type;
+ static const int chr_type;
+ static const int dir_type;
+ static const int fifo_type;
+ static const int lnk_type;
+ static const int reg_type;
+ static const int sock_type;
+ static const int wht_type;
+
+ //!
+ //! \brief Constructs a new file_info based on a given file.
+ //!
+ //! This constructor creates a new file_info object and fills it with
+ //! the data returned by ::stat when run on the given file, which must
+ //! exist.
+ //!
+ explicit file_info(const path&);
+
+ //!
+ //! \brief The copy constructor.
+ //!
+ file_info(const file_info&);
+
+ //!
+ //! \brief The destructor.
+ //!
+ ~file_info(void);
+
+ //!
+ //! \brief Returns the device containing the file.
+ //!
+ dev_t get_device(void) const;
+
+ //!
+ //! \brief Returns the file's inode.
+ //!
+ ino_t get_inode(void) const;
+
+ //!
+ //! \brief Returns the file's permissions.
+ //!
+ mode_t get_mode(void) const;
+
+ //!
+ //! \brief Returns the file's size.
+ //!
+ off_t get_size(void) const;
+
+ //!
+ //! \brief Returns the file's type.
+ //!
+ int get_type(void) const;
+
+ //!
+ //! \brief Returns whether the file is readable by its owner or not.
+ //!
+ bool is_owner_readable(void) const;
+
+ //!
+ //! \brief Returns whether the file is writable by its owner or not.
+ //!
+ bool is_owner_writable(void) const;
+
+ //!
+ //! \brief Returns whether the file is executable by its owner or not.
+ //!
+ bool is_owner_executable(void) const;
+
+ //!
+ //! \brief Returns whether the file is readable by the users belonging
+ //! to its group or not.
+ //!
+ bool is_group_readable(void) const;
+
+ //!
+ //! \brief Returns whether the file is writable the users belonging to
+ //! its group or not.
+ //!
+ bool is_group_writable(void) const;
+
+ //!
+ //! \brief Returns whether the file is executable by the users
+ //! belonging to its group or not.
+ //!
+ bool is_group_executable(void) const;
+
+ //!
+ //! \brief Returns whether the file is readable by people different
+ //! than the owner and those belonging to the group or not.
+ //!
+ bool is_other_readable(void) const;
+
+ //!
+ //! \brief Returns whether the file is write by people different
+ //! than the owner and those belonging to the group or not.
+ //!
+ bool is_other_writable(void) const;
+
+ //!
+ //! \brief Returns whether the file is executable by people different
+ //! than the owner and those belonging to the group or not.
+ //!
+ bool is_other_executable(void) const;
+};
+
+// ------------------------------------------------------------------------
+// The "directory" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief A class representing a file system directory.
+//!
+//! The directory class represents a group of files in the file system and
+//! corresponds to exactly one directory.
+//!
+class directory : public std::map< std::string, file_info > {
+public:
+ //!
+ //! \brief Constructs a new directory.
+ //!
+ //! Constructs a new directory object representing the given path.
+ //! The directory must exist at creation time as the contents of the
+ //! class are gathered from it.
+ //!
+ directory(const path&);
+
+ //!
+ //! \brief Returns the file names of the files in the directory.
+ //!
+ //! Returns the leaf names of all files contained in the directory.
+ //! I.e. the keys of the directory map.
+ //!
+ std::set< std::string > names(void) const;
+};
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief Checks if the given path exists.
+//!
+bool exists(const path&);
+
+//!
+//! \brief Looks for the given program in the PATH.
+//!
+//! Given a program name (without slashes) looks for it in the path and
+//! returns its full path name if found, otherwise an empty path.
+//!
+bool have_prog_in_path(const std::string&);
+
+//!
+//! \brief Checks if the given path exists, is accessible and is executable.
+//!
+bool is_executable(const path&);
+
+//!
+//! \brief Removes a given file.
+//!
+void remove(const path&);
+
+//!
+//! \brief Removes an empty directory.
+//!
+void rmdir(const path&);
+
+} // namespace fs
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_FS_HPP_)
diff --git a/contrib/atf/atf-c++/detail/fs_test.cpp b/contrib/atf/atf-c++/detail/fs_test.cpp
new file mode 100644
index 0000000..6cf9bf6
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/fs_test.cpp
@@ -0,0 +1,545 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/stat.h>
+}
+
+#include <fstream>
+#include <cerrno>
+#include <cstdio>
+
+#include "../macros.hpp"
+
+#include "exceptions.hpp"
+#include "fs.hpp"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+static
+void
+create_files(void)
+{
+ ::mkdir("files", 0755);
+ ::mkdir("files/dir", 0755);
+
+ std::ofstream os("files/reg");
+ os.close();
+
+ // TODO: Should create all other file types (blk, chr, fifo, lnk, sock)
+ // and test for them... but the underlying file system may not support
+ // most of these. Specially as we are working on /tmp, which can be
+ // mounted with flags such as "nodev". See how to deal with this
+ // situation.
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the "path" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(path_normalize);
+ATF_TEST_CASE_HEAD(path_normalize)
+{
+ set_md_var("descr", "Tests the path's normalization");
+}
+ATF_TEST_CASE_BODY(path_normalize)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE_EQ(path(".").str(), ".");
+ ATF_REQUIRE_EQ(path("..").str(), "..");
+
+ ATF_REQUIRE_EQ(path("foo").str(), "foo");
+ ATF_REQUIRE_EQ(path("foo/bar").str(), "foo/bar");
+ ATF_REQUIRE_EQ(path("foo/bar/").str(), "foo/bar");
+
+ ATF_REQUIRE_EQ(path("/foo").str(), "/foo");
+ ATF_REQUIRE_EQ(path("/foo/bar").str(), "/foo/bar");
+ ATF_REQUIRE_EQ(path("/foo/bar/").str(), "/foo/bar");
+
+ ATF_REQUIRE_EQ(path("///foo").str(), "/foo");
+ ATF_REQUIRE_EQ(path("///foo///bar").str(), "/foo/bar");
+ ATF_REQUIRE_EQ(path("///foo///bar///").str(), "/foo/bar");
+}
+
+ATF_TEST_CASE(path_is_absolute);
+ATF_TEST_CASE_HEAD(path_is_absolute)
+{
+ set_md_var("descr", "Tests the path::is_absolute function");
+}
+ATF_TEST_CASE_BODY(path_is_absolute)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE( path("/").is_absolute());
+ ATF_REQUIRE( path("////").is_absolute());
+ ATF_REQUIRE( path("////a").is_absolute());
+ ATF_REQUIRE( path("//a//").is_absolute());
+ ATF_REQUIRE(!path("a////").is_absolute());
+ ATF_REQUIRE(!path("../foo").is_absolute());
+}
+
+ATF_TEST_CASE(path_is_root);
+ATF_TEST_CASE_HEAD(path_is_root)
+{
+ set_md_var("descr", "Tests the path::is_root function");
+}
+ATF_TEST_CASE_BODY(path_is_root)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE( path("/").is_root());
+ ATF_REQUIRE( path("////").is_root());
+ ATF_REQUIRE(!path("////a").is_root());
+ ATF_REQUIRE(!path("//a//").is_root());
+ ATF_REQUIRE(!path("a////").is_root());
+ ATF_REQUIRE(!path("../foo").is_root());
+}
+
+ATF_TEST_CASE(path_branch_path);
+ATF_TEST_CASE_HEAD(path_branch_path)
+{
+ set_md_var("descr", "Tests the path::branch_path function");
+}
+ATF_TEST_CASE_BODY(path_branch_path)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE_EQ(path(".").branch_path().str(), ".");
+ ATF_REQUIRE_EQ(path("foo").branch_path().str(), ".");
+ ATF_REQUIRE_EQ(path("foo/bar").branch_path().str(), "foo");
+ ATF_REQUIRE_EQ(path("/foo").branch_path().str(), "/");
+ ATF_REQUIRE_EQ(path("/foo/bar").branch_path().str(), "/foo");
+}
+
+ATF_TEST_CASE(path_leaf_name);
+ATF_TEST_CASE_HEAD(path_leaf_name)
+{
+ set_md_var("descr", "Tests the path::leaf_name function");
+}
+ATF_TEST_CASE_BODY(path_leaf_name)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE_EQ(path(".").leaf_name(), ".");
+ ATF_REQUIRE_EQ(path("foo").leaf_name(), "foo");
+ ATF_REQUIRE_EQ(path("foo/bar").leaf_name(), "bar");
+ ATF_REQUIRE_EQ(path("/foo").leaf_name(), "foo");
+ ATF_REQUIRE_EQ(path("/foo/bar").leaf_name(), "bar");
+}
+
+ATF_TEST_CASE(path_compare_equal);
+ATF_TEST_CASE_HEAD(path_compare_equal)
+{
+ set_md_var("descr", "Tests the comparison for equality between paths");
+}
+ATF_TEST_CASE_BODY(path_compare_equal)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE(path("/") == path("///"));
+ ATF_REQUIRE(path("/a") == path("///a"));
+ ATF_REQUIRE(path("/a") == path("///a///"));
+
+ ATF_REQUIRE(path("a/b/c") == path("a//b//c"));
+ ATF_REQUIRE(path("a/b/c") == path("a//b//c///"));
+}
+
+ATF_TEST_CASE(path_compare_different);
+ATF_TEST_CASE_HEAD(path_compare_different)
+{
+ set_md_var("descr", "Tests the comparison for difference between paths");
+}
+ATF_TEST_CASE_BODY(path_compare_different)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE(path("/") != path("//a/"));
+ ATF_REQUIRE(path("/a") != path("a///"));
+
+ ATF_REQUIRE(path("a/b/c") != path("a/b"));
+ ATF_REQUIRE(path("a/b/c") != path("a//b"));
+ ATF_REQUIRE(path("a/b/c") != path("/a/b/c"));
+ ATF_REQUIRE(path("a/b/c") != path("/a//b//c"));
+}
+
+ATF_TEST_CASE(path_concat);
+ATF_TEST_CASE_HEAD(path_concat)
+{
+ set_md_var("descr", "Tests the concatenation of multiple paths");
+}
+ATF_TEST_CASE_BODY(path_concat)
+{
+ using atf::fs::path;
+
+ ATF_REQUIRE_EQ((path("foo") / "bar").str(), "foo/bar");
+ ATF_REQUIRE_EQ((path("foo/") / "/bar").str(), "foo/bar");
+ ATF_REQUIRE_EQ((path("foo/") / "/bar/baz").str(), "foo/bar/baz");
+ ATF_REQUIRE_EQ((path("foo/") / "///bar///baz").str(), "foo/bar/baz");
+}
+
+ATF_TEST_CASE(path_to_absolute);
+ATF_TEST_CASE_HEAD(path_to_absolute)
+{
+ set_md_var("descr", "Tests the conversion of a relative path to an "
+ "absolute one");
+}
+ATF_TEST_CASE_BODY(path_to_absolute)
+{
+ using atf::fs::file_info;
+ using atf::fs::path;
+
+ create_files();
+
+ {
+ const path p(".");
+ path pa = p.to_absolute();
+ ATF_REQUIRE(pa.is_absolute());
+
+ file_info fi(p);
+ file_info fia(pa);
+ ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
+ ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
+ }
+
+ {
+ const path p("files/reg");
+ path pa = p.to_absolute();
+ ATF_REQUIRE(pa.is_absolute());
+
+ file_info fi(p);
+ file_info fia(pa);
+ ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
+ ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
+ }
+}
+
+ATF_TEST_CASE(path_op_less);
+ATF_TEST_CASE_HEAD(path_op_less)
+{
+ set_md_var("descr", "Tests that the path's less-than operator works");
+}
+ATF_TEST_CASE_BODY(path_op_less)
+{
+ using atf::fs::path;
+
+ create_files();
+
+ ATF_REQUIRE(!(path("aaa") < path("aaa")));
+
+ ATF_REQUIRE( path("aab") < path("abc"));
+ ATF_REQUIRE(!(path("abc") < path("aab")));
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the "directory" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(directory_read);
+ATF_TEST_CASE_HEAD(directory_read)
+{
+ set_md_var("descr", "Tests the directory class creation, which reads "
+ "the contents of a directory");
+}
+ATF_TEST_CASE_BODY(directory_read)
+{
+ using atf::fs::directory;
+ using atf::fs::path;
+
+ create_files();
+
+ directory d(path("files"));
+ ATF_REQUIRE_EQ(d.size(), 4);
+ ATF_REQUIRE(d.find(".") != d.end());
+ ATF_REQUIRE(d.find("..") != d.end());
+ ATF_REQUIRE(d.find("dir") != d.end());
+ ATF_REQUIRE(d.find("reg") != d.end());
+}
+
+ATF_TEST_CASE(directory_file_info);
+ATF_TEST_CASE_HEAD(directory_file_info)
+{
+ set_md_var("descr", "Tests that the file_info objects attached to the "
+ "directory are valid");
+}
+ATF_TEST_CASE_BODY(directory_file_info)
+{
+ using atf::fs::directory;
+ using atf::fs::file_info;
+ using atf::fs::path;
+
+ create_files();
+
+ directory d(path("files"));
+
+ {
+ directory::const_iterator iter = d.find("dir");
+ ATF_REQUIRE(iter != d.end());
+ const file_info& fi = (*iter).second;
+ ATF_REQUIRE(fi.get_type() == file_info::dir_type);
+ }
+
+ {
+ directory::const_iterator iter = d.find("reg");
+ ATF_REQUIRE(iter != d.end());
+ const file_info& fi = (*iter).second;
+ ATF_REQUIRE(fi.get_type() == file_info::reg_type);
+ }
+}
+
+ATF_TEST_CASE(directory_names);
+ATF_TEST_CASE_HEAD(directory_names)
+{
+ set_md_var("descr", "Tests the directory's names method");
+}
+ATF_TEST_CASE_BODY(directory_names)
+{
+ using atf::fs::directory;
+ using atf::fs::path;
+
+ create_files();
+
+ directory d(path("files"));
+ std::set< std::string > ns = d.names();
+ ATF_REQUIRE_EQ(ns.size(), 4);
+ ATF_REQUIRE(ns.find(".") != ns.end());
+ ATF_REQUIRE(ns.find("..") != ns.end());
+ ATF_REQUIRE(ns.find("dir") != ns.end());
+ ATF_REQUIRE(ns.find("reg") != ns.end());
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the "file_info" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(file_info_stat);
+ATF_TEST_CASE_HEAD(file_info_stat)
+{
+ set_md_var("descr", "Tests the file_info creation and its basic contents");
+}
+ATF_TEST_CASE_BODY(file_info_stat)
+{
+ using atf::fs::file_info;
+ using atf::fs::path;
+
+ create_files();
+
+ {
+ path p("files/dir");
+ file_info fi(p);
+ ATF_REQUIRE(fi.get_type() == file_info::dir_type);
+ }
+
+ {
+ path p("files/reg");
+ file_info fi(p);
+ ATF_REQUIRE(fi.get_type() == file_info::reg_type);
+ }
+}
+
+ATF_TEST_CASE(file_info_perms);
+ATF_TEST_CASE_HEAD(file_info_perms)
+{
+ set_md_var("descr", "Tests the file_info methods to get the file's "
+ "permissions");
+}
+ATF_TEST_CASE_BODY(file_info_perms)
+{
+ using atf::fs::file_info;
+ using atf::fs::path;
+
+ path p("file");
+
+ std::ofstream os(p.c_str());
+ os.close();
+
+#define perms(ur, uw, ux, gr, gw, gx, othr, othw, othx) \
+ { \
+ file_info fi(p); \
+ ATF_REQUIRE(fi.is_owner_readable() == ur); \
+ ATF_REQUIRE(fi.is_owner_writable() == uw); \
+ ATF_REQUIRE(fi.is_owner_executable() == ux); \
+ ATF_REQUIRE(fi.is_group_readable() == gr); \
+ ATF_REQUIRE(fi.is_group_writable() == gw); \
+ ATF_REQUIRE(fi.is_group_executable() == gx); \
+ ATF_REQUIRE(fi.is_other_readable() == othr); \
+ ATF_REQUIRE(fi.is_other_writable() == othw); \
+ ATF_REQUIRE(fi.is_other_executable() == othx); \
+ }
+
+ ::chmod(p.c_str(), 0000);
+ perms(false, false, false, false, false, false, false, false, false);
+
+ ::chmod(p.c_str(), 0001);
+ perms(false, false, false, false, false, false, false, false, true);
+
+ ::chmod(p.c_str(), 0010);
+ perms(false, false, false, false, false, true, false, false, false);
+
+ ::chmod(p.c_str(), 0100);
+ perms(false, false, true, false, false, false, false, false, false);
+
+ ::chmod(p.c_str(), 0002);
+ perms(false, false, false, false, false, false, false, true, false);
+
+ ::chmod(p.c_str(), 0020);
+ perms(false, false, false, false, true, false, false, false, false);
+
+ ::chmod(p.c_str(), 0200);
+ perms(false, true, false, false, false, false, false, false, false);
+
+ ::chmod(p.c_str(), 0004);
+ perms(false, false, false, false, false, false, true, false, false);
+
+ ::chmod(p.c_str(), 0040);
+ perms(false, false, false, true, false, false, false, false, false);
+
+ ::chmod(p.c_str(), 0400);
+ perms(true, false, false, false, false, false, false, false, false);
+
+ ::chmod(p.c_str(), 0644);
+ perms(true, true, false, true, false, false, true, false, false);
+
+ ::chmod(p.c_str(), 0755);
+ perms(true, true, true, true, false, true, true, false, true);
+
+ ::chmod(p.c_str(), 0777);
+ perms(true, true, true, true, true, true, true, true, true);
+
+#undef perms
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(exists);
+ATF_TEST_CASE_HEAD(exists)
+{
+ set_md_var("descr", "Tests the exists function");
+}
+ATF_TEST_CASE_BODY(exists)
+{
+ using atf::fs::exists;
+ using atf::fs::path;
+
+ create_files();
+
+ ATF_REQUIRE( exists(path("files")));
+ ATF_REQUIRE(!exists(path("file")));
+ ATF_REQUIRE(!exists(path("files2")));
+
+ ATF_REQUIRE( exists(path("files/.")));
+ ATF_REQUIRE( exists(path("files/..")));
+ ATF_REQUIRE( exists(path("files/dir")));
+ ATF_REQUIRE( exists(path("files/reg")));
+ ATF_REQUIRE(!exists(path("files/foo")));
+}
+
+ATF_TEST_CASE(is_executable);
+ATF_TEST_CASE_HEAD(is_executable)
+{
+ set_md_var("descr", "Tests the is_executable function");
+}
+ATF_TEST_CASE_BODY(is_executable)
+{
+ using atf::fs::is_executable;
+ using atf::fs::path;
+
+ create_files();
+
+ ATF_REQUIRE( is_executable(path("files")));
+ ATF_REQUIRE( is_executable(path("files/.")));
+ ATF_REQUIRE( is_executable(path("files/..")));
+ ATF_REQUIRE( is_executable(path("files/dir")));
+
+ ATF_REQUIRE(!is_executable(path("non-existent")));
+
+ ATF_REQUIRE(!is_executable(path("files/reg")));
+ ATF_REQUIRE(::chmod("files/reg", 0755) != -1);
+ ATF_REQUIRE( is_executable(path("files/reg")));
+}
+
+ATF_TEST_CASE(remove);
+ATF_TEST_CASE_HEAD(remove)
+{
+ set_md_var("descr", "Tests the remove function");
+}
+ATF_TEST_CASE_BODY(remove)
+{
+ using atf::fs::exists;
+ using atf::fs::path;
+ using atf::fs::remove;
+
+ create_files();
+
+ ATF_REQUIRE( exists(path("files/reg")));
+ remove(path("files/reg"));
+ ATF_REQUIRE(!exists(path("files/reg")));
+
+ ATF_REQUIRE( exists(path("files/dir")));
+ ATF_REQUIRE_THROW(atf::system_error, remove(path("files/dir")));
+ ATF_REQUIRE( exists(path("files/dir")));
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the tests for the "path" class.
+ ATF_ADD_TEST_CASE(tcs, path_normalize);
+ ATF_ADD_TEST_CASE(tcs, path_is_absolute);
+ ATF_ADD_TEST_CASE(tcs, path_is_root);
+ ATF_ADD_TEST_CASE(tcs, path_branch_path);
+ ATF_ADD_TEST_CASE(tcs, path_leaf_name);
+ ATF_ADD_TEST_CASE(tcs, path_compare_equal);
+ ATF_ADD_TEST_CASE(tcs, path_compare_different);
+ ATF_ADD_TEST_CASE(tcs, path_concat);
+ ATF_ADD_TEST_CASE(tcs, path_to_absolute);
+ ATF_ADD_TEST_CASE(tcs, path_op_less);
+
+ // Add the tests for the "file_info" class.
+ ATF_ADD_TEST_CASE(tcs, file_info_stat);
+ ATF_ADD_TEST_CASE(tcs, file_info_perms);
+
+ // Add the tests for the "directory" class.
+ ATF_ADD_TEST_CASE(tcs, directory_read);
+ ATF_ADD_TEST_CASE(tcs, directory_names);
+ ATF_ADD_TEST_CASE(tcs, directory_file_info);
+
+ // Add the tests for the free functions.
+ ATF_ADD_TEST_CASE(tcs, exists);
+ ATF_ADD_TEST_CASE(tcs, is_executable);
+ ATF_ADD_TEST_CASE(tcs, remove);
+}
diff --git a/contrib/atf/atf-c++/detail/parser.cpp b/contrib/atf/atf-c++/detail/parser.cpp
new file mode 100644
index 0000000..7e7f680
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/parser.cpp
@@ -0,0 +1,384 @@
+//
+// 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.
+//
+
+#include <sstream>
+
+#include "parser.hpp"
+#include "sanity.hpp"
+#include "text.hpp"
+
+namespace impl = atf::parser;
+#define IMPL_NAME "atf::parser"
+
+// ------------------------------------------------------------------------
+// The "parse_error" class.
+// ------------------------------------------------------------------------
+
+impl::parse_error::parse_error(size_t line, std::string msg) :
+ std::runtime_error(msg),
+ std::pair< size_t, std::string >(line, msg)
+{
+}
+
+impl::parse_error::~parse_error(void)
+ throw()
+{
+}
+
+const char*
+impl::parse_error::what(void)
+ const throw()
+{
+ try {
+ std::ostringstream oss;
+ oss << "LONELY PARSE ERROR: " << first << ": " << second;
+ m_msg = oss.str();
+ return m_msg.c_str();
+ } catch (...) {
+ return "Could not format message for parsing error.";
+ }
+}
+
+impl::parse_error::operator std::string(void)
+ const
+{
+ return atf::text::to_string(first) + ": " + second;
+}
+
+// ------------------------------------------------------------------------
+// The "parse_errors" class.
+// ------------------------------------------------------------------------
+
+impl::parse_errors::parse_errors(void) :
+ std::runtime_error("No parsing errors yet")
+{
+ m_msg.clear();
+}
+
+impl::parse_errors::~parse_errors(void)
+ throw()
+{
+}
+
+const char*
+impl::parse_errors::what(void)
+ const throw()
+{
+ try {
+ m_msg = atf::text::join(*this, "\n");
+ return m_msg.c_str();
+ } catch (...) {
+ return "Could not format messages for parsing errors.";
+ }
+}
+
+// ------------------------------------------------------------------------
+// The "format_error" class.
+// ------------------------------------------------------------------------
+
+impl::format_error::format_error(const std::string& w) :
+ std::runtime_error(w.c_str())
+{
+}
+
+// ------------------------------------------------------------------------
+// The "token" class.
+// ------------------------------------------------------------------------
+
+impl::token::token(void) :
+ m_inited(false)
+{
+}
+
+impl::token::token(size_t p_line,
+ const token_type& p_type,
+ const std::string& p_text) :
+ m_inited(true),
+ m_line(p_line),
+ m_type(p_type),
+ m_text(p_text)
+{
+}
+
+size_t
+impl::token::lineno(void)
+ const
+{
+ return m_line;
+}
+
+const impl::token_type&
+impl::token::type(void)
+ const
+{
+ return m_type;
+}
+
+const std::string&
+impl::token::text(void)
+ const
+{
+ return m_text;
+}
+
+impl::token::operator bool(void)
+ const
+{
+ return m_inited;
+}
+
+bool
+impl::token::operator!(void)
+ const
+{
+ return !m_inited;
+}
+
+// ------------------------------------------------------------------------
+// The "header_entry" class.
+// ------------------------------------------------------------------------
+
+impl::header_entry::header_entry(void)
+{
+}
+
+impl::header_entry::header_entry(const std::string& n, const std::string& v,
+ attrs_map as) :
+ m_name(n),
+ m_value(v),
+ m_attrs(as)
+{
+}
+
+const std::string&
+impl::header_entry::name(void) const
+{
+ return m_name;
+}
+
+const std::string&
+impl::header_entry::value(void) const
+{
+ return m_value;
+}
+
+const impl::attrs_map&
+impl::header_entry::attrs(void) const
+{
+ return m_attrs;
+}
+
+bool
+impl::header_entry::has_attr(const std::string& n) const
+{
+ return m_attrs.find(n) != m_attrs.end();
+}
+
+const std::string&
+impl::header_entry::get_attr(const std::string& n) const
+{
+ attrs_map::const_iterator iter = m_attrs.find(n);
+ PRE(iter != m_attrs.end());
+ return (*iter).second;
+}
+
+// ------------------------------------------------------------------------
+// The header tokenizer.
+// ------------------------------------------------------------------------
+
+namespace header {
+
+static const impl::token_type eof_type = 0;
+static const impl::token_type nl_type = 1;
+static const impl::token_type text_type = 2;
+static const impl::token_type colon_type = 3;
+static const impl::token_type semicolon_type = 4;
+static const impl::token_type dblquote_type = 5;
+static const impl::token_type equal_type = 6;
+
+class tokenizer : public impl::tokenizer< std::istream > {
+public:
+ tokenizer(std::istream& is, size_t curline) :
+ impl::tokenizer< std::istream >
+ (is, true, eof_type, nl_type, text_type, curline)
+ {
+ add_delim(';', semicolon_type);
+ add_delim(':', colon_type);
+ add_delim('=', equal_type);
+ add_quote('"', dblquote_type);
+ }
+};
+
+static
+impl::parser< header::tokenizer >&
+read(impl::parser< header::tokenizer >& p, impl::header_entry& he)
+{
+ using namespace header;
+
+ impl::token t = p.expect(text_type, nl_type, "a header name");
+ if (t.type() == nl_type) {
+ he = impl::header_entry();
+ return p;
+ }
+ std::string hdr_name = t.text();
+
+ t = p.expect(colon_type, "`:'");
+
+ t = p.expect(text_type, "a textual value");
+ std::string hdr_value = t.text();
+
+ impl::attrs_map attrs;
+
+ for (;;) {
+ t = p.expect(eof_type, semicolon_type, nl_type,
+ "eof, `;' or new line");
+ if (t.type() == eof_type || t.type() == nl_type)
+ break;
+
+ t = p.expect(text_type, "an attribute name");
+ std::string attr_name = t.text();
+
+ t = p.expect(equal_type, "`='");
+
+ t = p.expect(text_type, "word or quoted string");
+ std::string attr_value = t.text();
+ attrs[attr_name] = attr_value;
+ }
+
+ he = impl::header_entry(hdr_name, hdr_value, attrs);
+
+ return p;
+}
+
+static
+std::ostream&
+write(std::ostream& os, const impl::header_entry& he)
+{
+ std::string line = he.name() + ": " + he.value();
+ impl::attrs_map as = he.attrs();
+ for (impl::attrs_map::const_iterator iter = as.begin(); iter != as.end();
+ iter++) {
+ PRE((*iter).second.find('\"') == std::string::npos);
+ line += "; " + (*iter).first + "=\"" + (*iter).second + "\"";
+ }
+
+ os << line << "\n";
+
+ return os;
+}
+
+} // namespace header
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+std::pair< size_t, impl::headers_map >
+impl::read_headers(std::istream& is, size_t curline)
+{
+ using impl::format_error;
+
+ headers_map hm;
+
+ //
+ // Grammar
+ //
+ // header = entry+ nl
+ // entry = line nl
+ // line = text colon text
+ // (semicolon (text equal (text | dblquote string dblquote)))*
+ // string = quoted_string
+ //
+
+ header::tokenizer tkz(is, curline);
+ impl::parser< header::tokenizer > p(tkz);
+
+ bool first = true;
+ for (;;) {
+ try {
+ header_entry he;
+ if (!header::read(p, he).good() || he.name().empty())
+ break;
+
+ if (first && he.name() != "Content-Type")
+ throw format_error("Could not determine content type");
+ else
+ first = false;
+
+ hm[he.name()] = he;
+ } catch (const impl::parse_error& pe) {
+ p.add_error(pe);
+ p.reset(header::nl_type);
+ }
+ }
+
+ if (!is.good())
+ throw format_error("Unexpected end of stream");
+
+ return std::pair< size_t, headers_map >(tkz.lineno(), hm);
+}
+
+void
+impl::write_headers(const impl::headers_map& hm, std::ostream& os)
+{
+ PRE(!hm.empty());
+ headers_map::const_iterator ct = hm.find("Content-Type");
+ PRE(ct != hm.end());
+ header::write(os, (*ct).second);
+ for (headers_map::const_iterator iter = hm.begin(); iter != hm.end();
+ iter++) {
+ if ((*iter).first != "Content-Type")
+ header::write(os, (*iter).second);
+ }
+ os << "\n";
+}
+
+void
+impl::validate_content_type(const impl::headers_map& hm, const std::string& fmt,
+ int version)
+{
+ using impl::format_error;
+
+ headers_map::const_iterator iter = hm.find("Content-Type");
+ if (iter == hm.end())
+ throw format_error("Could not determine content type");
+
+ const header_entry& he = (*iter).second;
+ if (he.value() != fmt)
+ throw format_error("Mismatched content type: expected `" + fmt +
+ "' but got `" + he.value() + "'");
+
+ if (!he.has_attr("version"))
+ throw format_error("Could not determine version");
+ const std::string& vstr = atf::text::to_string(version);
+ if (he.get_attr("version") != vstr)
+ throw format_error("Mismatched version: expected `" +
+ vstr + "' but got `" +
+ he.get_attr("version") + "'");
+}
diff --git a/contrib/atf/atf-c++/detail/parser.hpp b/contrib/atf/atf-c++/detail/parser.hpp
new file mode 100644
index 0000000..f1595f5
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/parser.hpp
@@ -0,0 +1,607 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_PARSER_HPP_)
+#define _ATF_CXX_PARSER_HPP_
+
+#include <istream>
+#include <map>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace atf {
+namespace parser {
+
+// ------------------------------------------------------------------------
+// The "parse_error" class.
+// ------------------------------------------------------------------------
+
+class parse_error : public std::runtime_error,
+ public std::pair< size_t, std::string > {
+ mutable std::string m_msg;
+
+public:
+ parse_error(size_t, std::string);
+ ~parse_error(void) throw();
+
+ const char* what(void) const throw();
+
+ operator std::string(void) const;
+};
+
+// ------------------------------------------------------------------------
+// The "parse_errors" class.
+// ------------------------------------------------------------------------
+
+class parse_errors : public std::runtime_error,
+ public std::vector< parse_error > {
+ std::vector< parse_error > m_errors;
+ mutable std::string m_msg;
+
+public:
+ parse_errors(void);
+ ~parse_errors(void) throw();
+
+ const char* what(void) const throw();
+};
+
+// ------------------------------------------------------------------------
+// The "format_error" class.
+// ------------------------------------------------------------------------
+
+class format_error : public std::runtime_error {
+public:
+ format_error(const std::string&);
+};
+
+// ------------------------------------------------------------------------
+// The "token" class.
+// ------------------------------------------------------------------------
+
+typedef int token_type;
+
+//!
+//! \brief Representation of a read token.
+//!
+//! A pair that contains the information of a token read from a stream.
+//! It contains the token's type and its associated data, if any.
+//!
+struct token {
+ bool m_inited;
+ size_t m_line;
+ token_type m_type;
+ std::string m_text;
+
+public:
+ token(void);
+ token(size_t, const token_type&, const std::string& = "");
+
+ size_t lineno(void) const;
+ const token_type& type(void) const;
+ const std::string& text(void) const;
+
+ operator bool(void) const;
+ bool operator!(void) const;
+};
+
+// ------------------------------------------------------------------------
+// The "tokenizer" class.
+// ------------------------------------------------------------------------
+
+//!
+//! \brief A stream tokenizer.
+//!
+//! This template implements an extremely simple, line-oriented stream
+//! tokenizer. It is only able to recognize one character-long delimiters,
+//! random-length keywords, skip whitespace and, anything that does not
+//! match these rules is supposed to be a word.
+//!
+//! Parameter IS: The input stream's type.
+//!
+template< class IS >
+class tokenizer {
+ IS& m_is;
+ size_t m_lineno;
+ token m_la;
+
+ bool m_skipws;
+ token_type m_eof_type, m_nl_type, m_text_type;
+
+ std::map< char, token_type > m_delims_map;
+ std::string m_delims_str;
+
+ char m_quotech;
+ token_type m_quotetype;
+
+ std::map< std::string, token_type > m_keywords_map;
+
+ token_type alloc_type(void);
+
+ template< class TKZ >
+ friend
+ class parser;
+
+public:
+ tokenizer(IS&, bool, const token_type&, const token_type&,
+ const token_type&, size_t = 1);
+
+ size_t lineno(void) const;
+
+ void add_delim(char, const token_type&);
+ void add_keyword(const std::string&, const token_type&);
+ void add_quote(char, const token_type&);
+
+ token next(void);
+ std::string rest_of_line(void);
+};
+
+template< class IS >
+tokenizer< IS >::tokenizer(IS& p_is,
+ bool p_skipws,
+ const token_type& p_eof_type,
+ const token_type& p_nl_type,
+ const token_type& p_text_type,
+ size_t p_lineno) :
+ m_is(p_is),
+ m_lineno(p_lineno),
+ m_skipws(p_skipws),
+ m_eof_type(p_eof_type),
+ m_nl_type(p_nl_type),
+ m_text_type(p_text_type),
+ m_quotech(-1)
+{
+}
+
+template< class IS >
+size_t
+tokenizer< IS >::lineno(void)
+ const
+{
+ return m_lineno;
+}
+
+template< class IS >
+void
+tokenizer< IS >::add_delim(char delim, const token_type& type)
+{
+ m_delims_map[delim] = type;
+ m_delims_str += delim;
+}
+
+template< class IS >
+void
+tokenizer< IS >::add_keyword(const std::string& keyword,
+ const token_type& type)
+{
+ m_keywords_map[keyword] = type;
+}
+
+template< class IS >
+void
+tokenizer< IS >::add_quote(char ch, const token_type& type)
+{
+ m_quotech = ch;
+ m_quotetype = type;
+}
+
+template< class IS >
+token
+tokenizer< IS >::next(void)
+{
+ if (m_la) {
+ token t = m_la;
+ m_la = token();
+ if (t.type() == m_nl_type)
+ m_lineno++;
+ return t;
+ }
+
+ char ch;
+ std::string text;
+
+ bool done = false, quoted = false;
+ token t(m_lineno, m_eof_type, "<<EOF>>");
+ while (!done && m_is.get(ch).good()) {
+ if (ch == m_quotech) {
+ if (text.empty()) {
+ bool escaped = false;
+ while (!done && m_is.get(ch).good()) {
+ if (!escaped) {
+ if (ch == '\\')
+ escaped = true;
+ else if (ch == '\n') {
+ m_la = token(m_lineno, m_nl_type, "<<NEWLINE>>");
+ throw parse_error(t.lineno(),
+ "Missing double quotes before "
+ "end of line");
+ } else if (ch == m_quotech)
+ done = true;
+ else
+ text += ch;
+ } else {
+ text += ch;
+ escaped = false;
+ }
+ }
+ if (!m_is.good())
+ throw parse_error(t.lineno(),
+ "Missing double quotes before "
+ "end of file");
+ t = token(m_lineno, m_text_type, text);
+ quoted = true;
+ } else {
+ m_is.unget();
+ done = true;
+ }
+ } else {
+ typename std::map< char, token_type >::const_iterator idelim;
+ idelim = m_delims_map.find(ch);
+ if (idelim != m_delims_map.end()) {
+ done = true;
+ if (text.empty())
+ t = token(m_lineno, (*idelim).second,
+ std::string("") + ch);
+ else
+ m_is.unget();
+ } else if (ch == '\n') {
+ done = true;
+ if (text.empty())
+ t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
+ else
+ m_is.unget();
+ } else if (m_skipws && (ch == ' ' || ch == '\t')) {
+ if (!text.empty())
+ done = true;
+ } else
+ text += ch;
+ }
+ }
+
+ if (!quoted && !text.empty()) {
+ typename std::map< std::string, token_type >::const_iterator ikw;
+ ikw = m_keywords_map.find(text);
+ if (ikw != m_keywords_map.end())
+ t = token(m_lineno, (*ikw).second, text);
+ else
+ t = token(m_lineno, m_text_type, text);
+ }
+
+ if (t.type() == m_nl_type)
+ m_lineno++;
+
+ return t;
+}
+
+template< class IS >
+std::string
+tokenizer< IS >::rest_of_line(void)
+{
+ std::string str;
+ while (m_is.good() && m_is.peek() != '\n')
+ str += m_is.get();
+ return str;
+}
+
+// ------------------------------------------------------------------------
+// The "parser" class.
+// ------------------------------------------------------------------------
+
+template< class TKZ >
+class parser {
+ TKZ& m_tkz;
+ token m_last;
+ parse_errors m_errors;
+ bool m_thrown;
+
+public:
+ parser(TKZ& tkz);
+ ~parser(void);
+
+ bool good(void) const;
+ void add_error(const parse_error&);
+ bool has_errors(void) const;
+
+ token next(void);
+ std::string rest_of_line(void);
+ token reset(const token_type&);
+
+ token
+ expect(const token_type&,
+ const std::string&);
+
+ token
+ expect(const token_type&,
+ const token_type&,
+ const std::string&);
+
+ token
+ expect(const token_type&,
+ const token_type&,
+ const token_type&,
+ const std::string&);
+
+ token
+ expect(const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const std::string&);
+
+ token
+ expect(const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const std::string&);
+
+ token
+ expect(const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const token_type&,
+ const std::string&);
+};
+
+template< class TKZ >
+parser< TKZ >::parser(TKZ& tkz) :
+ m_tkz(tkz),
+ m_thrown(false)
+{
+}
+
+template< class TKZ >
+parser< TKZ >::~parser(void)
+{
+ if (!m_errors.empty() && !m_thrown)
+ throw m_errors;
+}
+
+template< class TKZ >
+bool
+parser< TKZ >::good(void)
+ const
+{
+ return m_tkz.m_is.good();
+}
+
+template< class TKZ >
+void
+parser< TKZ >::add_error(const parse_error& pe)
+{
+ m_errors.push_back(pe);
+}
+
+template< class TKZ >
+bool
+parser< TKZ >::has_errors(void)
+ const
+{
+ return !m_errors.empty();
+}
+
+template< class TKZ >
+token
+parser< TKZ >::next(void)
+{
+ token t = m_tkz.next();
+
+ m_last = t;
+
+ if (t.type() == m_tkz.m_eof_type) {
+ if (!m_errors.empty()) {
+ m_thrown = true;
+ throw m_errors;
+ }
+ }
+
+ return t;
+}
+
+template< class TKZ >
+std::string
+parser< TKZ >::rest_of_line(void)
+{
+ return m_tkz.rest_of_line();
+}
+
+template< class TKZ >
+token
+parser< TKZ >::reset(const token_type& stop)
+{
+ token t = m_last;
+
+ while (t.type() != m_tkz.m_eof_type && t.type() != stop)
+ t = next();
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const token_type& t2,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1 && t.type() != t2)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const token_type& t2,
+ const token_type& t3,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1 && t.type() != t2 && t.type() != t3)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const token_type& t2,
+ const token_type& t3,
+ const token_type& t4,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
+ t.type() != t4)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const token_type& t2,
+ const token_type& t3,
+ const token_type& t4,
+ const token_type& t5,
+ const token_type& t6,
+ const token_type& t7,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
+ t.type() != t4 && t.type() != t5 && t.type() != t6 &&
+ t.type() != t7)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+template< class TKZ >
+token
+parser< TKZ >::expect(const token_type& t1,
+ const token_type& t2,
+ const token_type& t3,
+ const token_type& t4,
+ const token_type& t5,
+ const token_type& t6,
+ const token_type& t7,
+ const token_type& t8,
+ const std::string& textual)
+{
+ token t = next();
+
+ if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
+ t.type() != t4 && t.type() != t5 && t.type() != t6 &&
+ t.type() != t7 && t.type() != t8)
+ throw parse_error(t.lineno(),
+ "Unexpected token `" + t.text() +
+ "'; expected " + textual);
+
+ return t;
+}
+
+#define ATF_PARSER_CALLBACK(parser, func) \
+ do { \
+ if (!(parser).has_errors()) \
+ func; \
+ } while (false)
+
+// ------------------------------------------------------------------------
+// Header parsing.
+// ------------------------------------------------------------------------
+
+typedef std::map< std::string, std::string > attrs_map;
+
+class header_entry {
+ std::string m_name;
+ std::string m_value;
+ attrs_map m_attrs;
+
+public:
+ header_entry(void);
+ header_entry(const std::string&, const std::string&,
+ attrs_map = attrs_map());
+
+ const std::string& name(void) const;
+ const std::string& value(void) const;
+ const attrs_map& attrs(void) const;
+ bool has_attr(const std::string&) const;
+ const std::string& get_attr(const std::string&) const;
+};
+
+typedef std::map< std::string, header_entry > headers_map;
+
+std::pair< size_t, headers_map > read_headers(std::istream&, size_t);
+void write_headers(const headers_map&, std::ostream&);
+void validate_content_type(const headers_map&, const std::string&, int);
+
+} // namespace parser
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_PARSER_HPP_)
diff --git a/contrib/atf/atf-c++/detail/parser_test.cpp b/contrib/atf/atf-c++/detail/parser_test.cpp
new file mode 100644
index 0000000..491c014
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/parser_test.cpp
@@ -0,0 +1,1043 @@
+//
+// 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.
+//
+
+#include <sstream>
+
+#include "../macros.hpp"
+
+#include "parser.hpp"
+#include "test_helpers.hpp"
+
+// ------------------------------------------------------------------------
+// Tests for the "parse_error" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(parse_error_to_string);
+ATF_TEST_CASE_HEAD(parse_error_to_string)
+{
+ set_md_var("descr", "Tests the parse_error conversion to strings");
+}
+ATF_TEST_CASE_BODY(parse_error_to_string)
+{
+ using atf::parser::parse_error;
+
+ const parse_error e(123, "This is the message");
+ ATF_REQUIRE_EQ("123: This is the message", std::string(e));
+}
+
+// ------------------------------------------------------------------------
+// Tests for the "parse_errors" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(parse_errors_what);
+ATF_TEST_CASE_HEAD(parse_errors_what)
+{
+ set_md_var("descr", "Tests the parse_errors description");
+}
+ATF_TEST_CASE_BODY(parse_errors_what)
+{
+ using atf::parser::parse_error;
+ using atf::parser::parse_errors;
+
+ parse_errors es;
+ es.push_back(parse_error(2, "Second error"));
+ es.push_back(parse_error(1, "First error"));
+
+ ATF_REQUIRE_EQ("2: Second error\n1: First error", std::string(es.what()));
+}
+
+// ------------------------------------------------------------------------
+// Tests for the "token" class.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(token_getters);
+ATF_TEST_CASE_HEAD(token_getters)
+{
+ set_md_var("descr", "Tests the token getters");
+}
+ATF_TEST_CASE_BODY(token_getters)
+{
+ using atf::parser::token;
+
+ {
+ token t(10, 0);
+ ATF_REQUIRE_EQ(t.lineno(), 10);
+ ATF_REQUIRE_EQ(t.type(), 0);
+ ATF_REQUIRE(t.text().empty());
+ }
+
+ {
+ token t(10, 0, "foo");
+ ATF_REQUIRE_EQ(t.lineno(), 10);
+ ATF_REQUIRE_EQ(t.type(), 0);
+ ATF_REQUIRE_EQ(t.text(), "foo");
+ }
+
+ {
+ token t(20, 1);
+ ATF_REQUIRE_EQ(t.lineno(), 20);
+ ATF_REQUIRE_EQ(t.type(), 1);
+ ATF_REQUIRE(t.text().empty());
+ }
+
+ {
+ token t(20, 1, "bar");
+ ATF_REQUIRE_EQ(t.lineno(), 20);
+ ATF_REQUIRE_EQ(t.type(), 1);
+ ATF_REQUIRE_EQ(t.text(), "bar");
+ }
+}
+
+// ------------------------------------------------------------------------
+// Tests for the "tokenizer" class.
+// ------------------------------------------------------------------------
+
+#define EXPECT(tkz, ttype, ttext) \
+ do { \
+ atf::parser::token t = tkz.next(); \
+ ATF_REQUIRE(t.type() == ttype); \
+ ATF_REQUIRE_EQ(t.text(), ttext); \
+ } while (false);
+
+namespace minimal {
+
+ static const atf::parser::token_type eof_type = 0;
+ static const atf::parser::token_type nl_type = 1;
+ static const atf::parser::token_type word_type = 2;
+
+ class tokenizer : public atf::parser::tokenizer< std::istream > {
+ public:
+ tokenizer(std::istream& is, bool skipws) :
+ atf::parser::tokenizer< std::istream >
+ (is, skipws, eof_type, nl_type, word_type)
+ {
+ }
+ };
+
+}
+
+namespace delims {
+
+ static const atf::parser::token_type eof_type = 0;
+ static const atf::parser::token_type nl_type = 1;
+ static const atf::parser::token_type word_type = 2;
+ static const atf::parser::token_type plus_type = 3;
+ static const atf::parser::token_type minus_type = 4;
+ static const atf::parser::token_type equal_type = 5;
+
+ class tokenizer : public atf::parser::tokenizer< std::istream > {
+ public:
+ tokenizer(std::istream& is, bool skipws) :
+ atf::parser::tokenizer< std::istream >
+ (is, skipws, eof_type, nl_type, word_type)
+ {
+ add_delim('+', plus_type);
+ add_delim('-', minus_type);
+ add_delim('=', equal_type);
+ }
+ };
+
+}
+
+namespace keywords {
+
+ static const atf::parser::token_type eof_type = 0;
+ static const atf::parser::token_type nl_type = 1;
+ static const atf::parser::token_type word_type = 2;
+ static const atf::parser::token_type var_type = 3;
+ static const atf::parser::token_type loop_type = 4;
+ static const atf::parser::token_type endloop_type = 5;
+
+ class tokenizer : public atf::parser::tokenizer< std::istream > {
+ public:
+ tokenizer(std::istream& is, bool skipws) :
+ atf::parser::tokenizer< std::istream >
+ (is, skipws, eof_type, nl_type, word_type)
+ {
+ add_keyword("var", var_type);
+ add_keyword("loop", loop_type);
+ add_keyword("endloop", endloop_type);
+ }
+ };
+
+}
+
+namespace quotes {
+
+ static const atf::parser::token_type eof_type = 0;
+ static const atf::parser::token_type nl_type = 1;
+ static const atf::parser::token_type word_type = 2;
+ static const atf::parser::token_type dblquote_type = 3;
+
+ class tokenizer : public atf::parser::tokenizer< std::istream > {
+ public:
+ tokenizer(std::istream& is, bool skipws) :
+ atf::parser::tokenizer< std::istream >
+ (is, skipws, eof_type, nl_type, word_type)
+ {
+ add_quote('"', dblquote_type);
+ }
+ };
+
+}
+
+ATF_TEST_CASE(tokenizer_minimal_nows);
+ATF_TEST_CASE_HEAD(tokenizer_minimal_nows)
+{
+ set_md_var("descr", "Tests the tokenizer class using a minimal parser "
+ "and not skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_minimal_nows)
+{
+ using namespace minimal;
+
+ {
+ std::istringstream iss("");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\n");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\n\n\n");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "line 1");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\n");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "line 1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\nline 2");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "line 1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line 2");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\nline 2\nline 3\n");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "line 1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line 2");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line 3");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_minimal_ws);
+ATF_TEST_CASE_HEAD(tokenizer_minimal_ws)
+{
+ set_md_var("descr", "Tests the tokenizer class using a minimal parser "
+ "and skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_minimal_ws)
+{
+ using namespace minimal;
+
+ {
+ std::istringstream iss("");
+ minimal::tokenizer mt(iss, true);
+
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" \t ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\n");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" \t \n \t ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\n\n\n");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" \tline\t 1\t");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\n");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\nline 2");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "2");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("line 1\nline 2\nline 3\n");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "2");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "3");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" \t line \t 1\n\tline\t2\n line 3 \n");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "1");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "2");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, word_type, "line");
+ EXPECT(mt, word_type, "3");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_delims_nows);
+ATF_TEST_CASE_HEAD(tokenizer_delims_nows)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with some "
+ "additional delimiters and not skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_delims_nows)
+{
+ using namespace delims;
+
+ {
+ std::istringstream iss("+-=");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, minus_type, "-");
+ EXPECT(mt, equal_type, "=");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("+++");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\n+\n++\n");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("foo+bar=baz");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "foo");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, word_type, "bar");
+ EXPECT(mt, equal_type, "=");
+ EXPECT(mt, word_type, "baz");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" foo\t+\tbar = baz ");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, " foo\t");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, word_type, "\tbar ");
+ EXPECT(mt, equal_type, "=");
+ EXPECT(mt, word_type, " baz ");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_delims_ws);
+ATF_TEST_CASE_HEAD(tokenizer_delims_ws)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with some "
+ "additional delimiters and skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_delims_ws)
+{
+ using namespace delims;
+
+ {
+ std::istringstream iss(" foo\t+\tbar = baz ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "foo");
+ EXPECT(mt, plus_type, "+");
+ EXPECT(mt, word_type, "bar");
+ EXPECT(mt, equal_type, "=");
+ EXPECT(mt, word_type, "baz");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_keywords_nows);
+ATF_TEST_CASE_HEAD(tokenizer_keywords_nows)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with some "
+ "additional keywords and not skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_keywords_nows)
+{
+ using namespace keywords;
+
+ {
+ std::istringstream iss("var");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, var_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("va");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "va");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("vara");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "vara");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("var ");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "var ");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("var\nloop\nendloop");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, var_type, "var");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, loop_type, "loop");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, endloop_type, "endloop");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_keywords_ws);
+ATF_TEST_CASE_HEAD(tokenizer_keywords_ws)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with some "
+ "additional keywords and not skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_keywords_ws)
+{
+ using namespace keywords;
+
+ {
+ std::istringstream iss("var ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, var_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" var \n\tloop\t\n \tendloop \t");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, var_type, "var");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, loop_type, "loop");
+ EXPECT(mt, nl_type, "<<NEWLINE>>");
+ EXPECT(mt, endloop_type, "endloop");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("var loop endloop");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, var_type, "var");
+ EXPECT(mt, loop_type, "loop");
+ EXPECT(mt, endloop_type, "endloop");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_quotes_nows);
+ATF_TEST_CASE_HEAD(tokenizer_quotes_nows)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with "
+ "quoted strings and not skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_quotes_nows)
+{
+ using namespace quotes;
+
+ {
+ std::istringstream iss("var");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("\"var\"");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("var1\"var2\"");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "var1");
+ EXPECT(mt, word_type, "var2");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss("var1\" var2 \"");
+ tokenizer mt(iss, false);
+
+ EXPECT(mt, word_type, "var1");
+ EXPECT(mt, word_type, " var2 ");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+ATF_TEST_CASE(tokenizer_quotes_ws);
+ATF_TEST_CASE_HEAD(tokenizer_quotes_ws)
+{
+ set_md_var("descr", "Tests the tokenizer class using a parser with "
+ "quoted strings and skipping whitespace");
+}
+ATF_TEST_CASE_BODY(tokenizer_quotes_ws)
+{
+ using namespace quotes;
+
+ {
+ std::istringstream iss(" var ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" \"var\" ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "var");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" var1 \"var2\" ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "var1");
+ EXPECT(mt, word_type, "var2");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+
+ {
+ std::istringstream iss(" var1 \" var2 \" ");
+ tokenizer mt(iss, true);
+
+ EXPECT(mt, word_type, "var1");
+ EXPECT(mt, word_type, " var2 ");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ EXPECT(mt, eof_type, "<<EOF>>");
+ }
+}
+
+// ------------------------------------------------------------------------
+// Tests for the headers parser.
+// ------------------------------------------------------------------------
+
+class header_reader {
+ std::istream& m_is;
+
+public:
+ header_reader(std::istream& is) :
+ m_is(is)
+ {
+ }
+
+ void
+ read(void)
+ {
+ std::pair< size_t, atf::parser::headers_map > hml =
+ atf::parser::read_headers(m_is, 1);
+ atf::parser::validate_content_type(hml.second,
+ "application/X-atf-headers-test", 1234);
+ }
+
+ std::vector< std::string > m_calls;
+};
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_1);
+ATF_TEST_CASE_BODY(headers_1)
+{
+ const char* input =
+ ""
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<EOF>>'; expected a header name",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_2);
+ATF_TEST_CASE_BODY(headers_2)
+{
+ const char* input =
+ "Content-Type\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<NEWLINE>>'; expected `:'",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_3);
+ATF_TEST_CASE_BODY(headers_3)
+{
+ const char* input =
+ "Content-Type:\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<NEWLINE>>'; expected a textual value",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_4);
+ATF_TEST_CASE_BODY(headers_4)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "2: Unexpected token `<<EOF>>'; expected a header name",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_5);
+ATF_TEST_CASE_BODY(headers_5)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test;\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<NEWLINE>>'; expected an attribute name",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_6);
+ATF_TEST_CASE_BODY(headers_6)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<NEWLINE>>'; expected `='",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_7);
+ATF_TEST_CASE_BODY(headers_7)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_8);
+ATF_TEST_CASE_BODY(headers_8)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=\"1234\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Missing double quotes before end of line",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_9);
+ATF_TEST_CASE_BODY(headers_9)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=1234\"\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "1: Missing double quotes before end of line",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_10);
+ATF_TEST_CASE_BODY(headers_10)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=1234\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "2: Unexpected token `<<EOF>>'; expected a header name",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_11);
+ATF_TEST_CASE_BODY(headers_11)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=\"1234\"\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "2: Unexpected token `<<EOF>>'; expected a header name",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(headers_12);
+ATF_TEST_CASE_BODY(headers_12)
+{
+ const char* input =
+ "Content-Type: application/X-atf-headers-test; version=\"1234\"\n"
+ "a b\n"
+ "a-b:\n"
+ "a-b: foo;\n"
+ "a-b: foo; var\n"
+ "a-b: foo; var=\n"
+ "a-b: foo; var=\"a\n"
+ "a-b: foo; var=a\"\n"
+ "a-b: foo; var=\"a\";\n"
+ "a-b: foo; var=\"a\"; second\n"
+ "a-b: foo; var=\"a\"; second=\n"
+ "a-b: foo; var=\"a\"; second=\"b\n"
+ "a-b: foo; var=\"a\"; second=b\"\n"
+ "a-b: foo; var=\"a\"; second=\"b\"\n"
+ ;
+
+ const char* exp_calls[] = {
+ NULL
+ };
+
+ const char* exp_errors[] = {
+ "2: Unexpected token `b'; expected `:'",
+ "3: Unexpected token `<<NEWLINE>>'; expected a textual value",
+ "4: Unexpected token `<<NEWLINE>>'; expected an attribute name",
+ "5: Unexpected token `<<NEWLINE>>'; expected `='",
+ "6: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
+ "7: Missing double quotes before end of line",
+ "8: Missing double quotes before end of line",
+ "9: Unexpected token `<<NEWLINE>>'; expected an attribute name",
+ "10: Unexpected token `<<NEWLINE>>'; expected `='",
+ "11: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
+ "12: Missing double quotes before end of line",
+ "13: Missing double quotes before end of line",
+ NULL
+ };
+
+ do_parser_test< header_reader >(input, exp_calls, exp_errors);
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add test cases for the "parse_error" class.
+ ATF_ADD_TEST_CASE(tcs, parse_error_to_string);
+
+ // Add test cases for the "parse_errors" class.
+ ATF_ADD_TEST_CASE(tcs, parse_errors_what);
+
+ // Add test cases for the "token" class.
+ ATF_ADD_TEST_CASE(tcs, token_getters);
+
+ // Add test cases for the "tokenizer" class.
+ ATF_ADD_TEST_CASE(tcs, tokenizer_minimal_nows);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_minimal_ws);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_delims_nows);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_delims_ws);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_keywords_nows);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_keywords_ws);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_quotes_nows);
+ ATF_ADD_TEST_CASE(tcs, tokenizer_quotes_ws);
+
+ // Add the tests for the headers parser.
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, headers_1);
+ ATF_ADD_TEST_CASE(tcs, headers_2);
+ ATF_ADD_TEST_CASE(tcs, headers_3);
+ ATF_ADD_TEST_CASE(tcs, headers_4);
+ ATF_ADD_TEST_CASE(tcs, headers_5);
+ ATF_ADD_TEST_CASE(tcs, headers_6);
+ ATF_ADD_TEST_CASE(tcs, headers_7);
+ ATF_ADD_TEST_CASE(tcs, headers_8);
+ ATF_ADD_TEST_CASE(tcs, headers_9);
+ ATF_ADD_TEST_CASE(tcs, headers_10);
+ ATF_ADD_TEST_CASE(tcs, headers_11);
+ ATF_ADD_TEST_CASE(tcs, headers_12);
+}
diff --git a/contrib/atf/atf-c++/detail/process.cpp b/contrib/atf/atf-c++/detail/process.cpp
new file mode 100644
index 0000000..deb1158
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/process.cpp
@@ -0,0 +1,355 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2008 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.
+//
+
+extern "C" {
+#include <signal.h>
+
+#include "../../atf-c/error.h"
+
+#include "../../atf-c/detail/process.h"
+}
+
+#include <iostream>
+
+#include "exceptions.hpp"
+#include "process.hpp"
+#include "sanity.hpp"
+
+namespace detail = atf::process::detail;
+namespace impl = atf::process;
+#define IMPL_NAME "atf::process"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+template< class C >
+atf::utils::auto_array< const char* >
+collection_to_argv(const C& c)
+{
+ atf::utils::auto_array< const char* > argv(new const char*[c.size() + 1]);
+
+ std::size_t pos = 0;
+ for (typename C::const_iterator iter = c.begin(); iter != c.end();
+ iter++) {
+ argv[pos] = (*iter).c_str();
+ pos++;
+ }
+ INV(pos == c.size());
+ argv[pos] = NULL;
+
+ return argv;
+}
+
+template< class C >
+C
+argv_to_collection(const char* const* argv)
+{
+ C c;
+
+ for (const char* const* iter = argv; *iter != NULL; iter++)
+ c.push_back(std::string(*iter));
+
+ return c;
+}
+
+// ------------------------------------------------------------------------
+// The "argv_array" type.
+// ------------------------------------------------------------------------
+
+impl::argv_array::argv_array(void) :
+ m_exec_argv(collection_to_argv(m_args))
+{
+}
+
+impl::argv_array::argv_array(const char* arg1, ...)
+{
+ m_args.push_back(arg1);
+
+ {
+ va_list ap;
+ const char* nextarg;
+
+ va_start(ap, arg1);
+ while ((nextarg = va_arg(ap, const char*)) != NULL)
+ m_args.push_back(nextarg);
+ va_end(ap);
+ }
+
+ ctor_init_exec_argv();
+}
+
+impl::argv_array::argv_array(const char* const* ca) :
+ m_args(argv_to_collection< args_vector >(ca)),
+ m_exec_argv(collection_to_argv(m_args))
+{
+}
+
+impl::argv_array::argv_array(const argv_array& a) :
+ m_args(a.m_args),
+ m_exec_argv(collection_to_argv(m_args))
+{
+}
+
+void
+impl::argv_array::ctor_init_exec_argv(void)
+{
+ m_exec_argv = collection_to_argv(m_args);
+}
+
+const char* const*
+impl::argv_array::exec_argv(void)
+ const
+{
+ return m_exec_argv.get();
+}
+
+impl::argv_array::size_type
+impl::argv_array::size(void)
+ const
+{
+ return m_args.size();
+}
+
+const char*
+impl::argv_array::operator[](int idx)
+ const
+{
+ return m_args[idx].c_str();
+}
+
+impl::argv_array::const_iterator
+impl::argv_array::begin(void)
+ const
+{
+ return m_args.begin();
+}
+
+impl::argv_array::const_iterator
+impl::argv_array::end(void)
+ const
+{
+ return m_args.end();
+}
+
+impl::argv_array&
+impl::argv_array::operator=(const argv_array& a)
+{
+ if (this != &a) {
+ m_args = a.m_args;
+ m_exec_argv = collection_to_argv(m_args);
+ }
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+// The "stream" types.
+// ------------------------------------------------------------------------
+
+impl::basic_stream::basic_stream(void) :
+ m_inited(false)
+{
+}
+
+impl::basic_stream::~basic_stream(void)
+{
+ if (m_inited)
+ atf_process_stream_fini(&m_sb);
+}
+
+const atf_process_stream_t*
+impl::basic_stream::get_sb(void)
+ const
+{
+ INV(m_inited);
+ return &m_sb;
+}
+
+impl::stream_capture::stream_capture(void)
+{
+ atf_error_t err = atf_process_stream_init_capture(&m_sb);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ m_inited = true;
+}
+
+impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
+{
+ atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ m_inited = true;
+}
+
+impl::stream_inherit::stream_inherit(void)
+{
+ atf_error_t err = atf_process_stream_init_inherit(&m_sb);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ m_inited = true;
+}
+
+impl::stream_redirect_fd::stream_redirect_fd(const int fd)
+{
+ atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ m_inited = true;
+}
+
+impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
+{
+ atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+ m_inited = true;
+}
+
+// ------------------------------------------------------------------------
+// The "status" type.
+// ------------------------------------------------------------------------
+
+impl::status::status(atf_process_status_t& s) :
+ m_status(s)
+{
+}
+
+impl::status::~status(void)
+{
+ atf_process_status_fini(&m_status);
+}
+
+bool
+impl::status::exited(void)
+ const
+{
+ return atf_process_status_exited(&m_status);
+}
+
+int
+impl::status::exitstatus(void)
+ const
+{
+ return atf_process_status_exitstatus(&m_status);
+}
+
+bool
+impl::status::signaled(void)
+ const
+{
+ return atf_process_status_signaled(&m_status);
+}
+
+int
+impl::status::termsig(void)
+ const
+{
+ return atf_process_status_termsig(&m_status);
+}
+
+bool
+impl::status::coredump(void)
+ const
+{
+ return atf_process_status_coredump(&m_status);
+}
+
+// ------------------------------------------------------------------------
+// The "child" type.
+// ------------------------------------------------------------------------
+
+impl::child::child(atf_process_child_t& c) :
+ m_child(c),
+ m_waited(false)
+{
+}
+
+impl::child::~child(void)
+{
+ if (!m_waited) {
+ ::kill(atf_process_child_pid(&m_child), SIGTERM);
+
+ atf_process_status_t s;
+ atf_error_t err = atf_process_child_wait(&m_child, &s);
+ INV(!atf_is_error(err));
+ atf_process_status_fini(&s);
+ }
+}
+
+impl::status
+impl::child::wait(void)
+{
+ atf_process_status_t s;
+
+ atf_error_t err = atf_process_child_wait(&m_child, &s);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ m_waited = true;
+ return status(s);
+}
+
+pid_t
+impl::child::pid(void)
+ const
+{
+ return atf_process_child_pid(&m_child);
+}
+
+int
+impl::child::stdout_fd(void)
+{
+ return atf_process_child_stdout(&m_child);
+}
+
+int
+impl::child::stderr_fd(void)
+{
+ return atf_process_child_stderr(&m_child);
+}
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+void
+detail::flush_streams(void)
+{
+ // This is a weird hack to ensure that the output of the parent process
+ // is flushed before executing a child which prevents, for example, the
+ // output of the atf-run hooks to appear before the output of atf-run
+ // itself.
+ //
+ // TODO: This should only be executed when inheriting the stdout or
+ // stderr file descriptors. However, the flushing is specific to the
+ // iostreams, so we cannot do it from the C library where all the process
+ // logic is performed. Come up with a better design.
+ std::cout.flush();
+ std::cerr.flush();
+}
diff --git a/contrib/atf/atf-c++/detail/process.hpp b/contrib/atf/atf-c++/detail/process.hpp
new file mode 100644
index 0000000..6e33e00
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/process.hpp
@@ -0,0 +1,280 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2008 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.
+//
+
+#if !defined(_ATF_CXX_PROCESS_HPP_)
+#define _ATF_CXX_PROCESS_HPP_
+
+extern "C" {
+#include <sys/types.h>
+
+#include "../../atf-c/error.h"
+
+#include "../../atf-c/detail/process.h"
+}
+
+#include <string>
+#include <vector>
+
+#include "exceptions.hpp"
+#include "fs.hpp"
+
+#include "../utils.hpp"
+
+namespace atf {
+namespace process {
+
+class child;
+class status;
+
+// ------------------------------------------------------------------------
+// The "argv_array" type.
+// ------------------------------------------------------------------------
+
+class argv_array {
+ typedef std::vector< std::string > args_vector;
+ args_vector m_args;
+
+ // TODO: This is immutable, so we should be able to use
+ // std::tr1::shared_array instead when it becomes widely available.
+ // The reason would be to remove all copy constructors and assignment
+ // operators from this class.
+ utils::auto_array< const char* > m_exec_argv;
+ void ctor_init_exec_argv(void);
+
+public:
+ typedef args_vector::const_iterator const_iterator;
+ typedef args_vector::size_type size_type;
+
+ argv_array(void);
+ argv_array(const char*, ...);
+ explicit argv_array(const char* const*);
+ template< class C > explicit argv_array(const C&);
+ argv_array(const argv_array&);
+
+ const char* const* exec_argv(void) const;
+ size_type size(void) const;
+ const char* operator[](int) const;
+
+ const_iterator begin(void) const;
+ const_iterator end(void) const;
+
+ argv_array& operator=(const argv_array&);
+};
+
+template< class C >
+argv_array::argv_array(const C& c)
+{
+ for (typename C::const_iterator iter = c.begin(); iter != c.end();
+ iter++)
+ m_args.push_back(*iter);
+ ctor_init_exec_argv();
+}
+
+// ------------------------------------------------------------------------
+// The "stream" types.
+// ------------------------------------------------------------------------
+
+class basic_stream {
+protected:
+ atf_process_stream_t m_sb;
+ bool m_inited;
+
+ const atf_process_stream_t* get_sb(void) const;
+
+public:
+ basic_stream(void);
+ ~basic_stream(void);
+};
+
+class stream_capture : basic_stream {
+ // Allow access to the getters.
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+public:
+ stream_capture(void);
+};
+
+class stream_connect : basic_stream {
+ // Allow access to the getters.
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+public:
+ stream_connect(const int, const int);
+};
+
+class stream_inherit : basic_stream {
+ // Allow access to the getters.
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+public:
+ stream_inherit(void);
+};
+
+class stream_redirect_fd : basic_stream {
+ // Allow access to the getters.
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+public:
+ stream_redirect_fd(const int);
+};
+
+class stream_redirect_path : basic_stream {
+ // Allow access to the getters.
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+public:
+ stream_redirect_path(const fs::path&);
+};
+
+// ------------------------------------------------------------------------
+// The "status" type.
+// ------------------------------------------------------------------------
+
+class status {
+ atf_process_status_t m_status;
+
+ friend class child;
+ template< class OutStream, class ErrStream > friend
+ status exec(const atf::fs::path&, const argv_array&,
+ const OutStream&, const ErrStream&, void (*)(void));
+
+ status(atf_process_status_t&);
+
+public:
+ ~status(void);
+
+ bool exited(void) const;
+ int exitstatus(void) const;
+
+ bool signaled(void) const;
+ int termsig(void) const;
+ bool coredump(void) const;
+};
+
+// ------------------------------------------------------------------------
+// The "child" type.
+// ------------------------------------------------------------------------
+
+class child {
+ atf_process_child_t m_child;
+ bool m_waited;
+
+ template< class OutStream, class ErrStream > friend
+ child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
+
+ child(atf_process_child_t& c);
+
+public:
+ ~child(void);
+
+ status wait(void);
+
+ pid_t pid(void) const;
+ int stdout_fd(void);
+ int stderr_fd(void);
+};
+
+// ------------------------------------------------------------------------
+// Free functions.
+// ------------------------------------------------------------------------
+
+namespace detail {
+void flush_streams(void);
+} // namespace detail
+
+// TODO: The void* cookie can probably be templatized, thus also allowing
+// const data structures.
+template< class OutStream, class ErrStream >
+child
+fork(void (*start)(void*), const OutStream& outsb,
+ const ErrStream& errsb, void* v)
+{
+ atf_process_child_t c;
+
+ detail::flush_streams();
+ atf_error_t err = atf_process_fork(&c, start, outsb.get_sb(),
+ errsb.get_sb(), v);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return child(c);
+}
+
+template< class OutStream, class ErrStream >
+status
+exec(const atf::fs::path& prog, const argv_array& argv,
+ const OutStream& outsb, const ErrStream& errsb,
+ void (*prehook)(void))
+{
+ atf_process_status_t s;
+
+ detail::flush_streams();
+ atf_error_t err = atf_process_exec_array(&s, prog.c_path(),
+ argv.exec_argv(),
+ outsb.get_sb(),
+ errsb.get_sb(),
+ prehook);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return status(s);
+}
+
+template< class OutStream, class ErrStream >
+status
+exec(const atf::fs::path& prog, const argv_array& argv,
+ const OutStream& outsb, const ErrStream& errsb)
+{
+ return exec(prog, argv, outsb, errsb, NULL);
+}
+
+} // namespace process
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_PROCESS_HPP_)
diff --git a/contrib/atf/atf-c++/detail/process_test.cpp b/contrib/atf/atf-c++/detail/process_test.cpp
new file mode 100644
index 0000000..d13ab94
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/process_test.cpp
@@ -0,0 +1,357 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2008 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 <cstdlib>
+#include <cstring>
+
+#include "../macros.hpp"
+
+#include "process.hpp"
+#include "test_helpers.hpp"
+
+// TODO: Testing the fork function is a huge task and I'm afraid of
+// copy/pasting tons of stuff from the C version. I'd rather not do that
+// until some code can be shared, which cannot happen until the C++ binding
+// is cleaned by a fair amount. Instead... just rely (at the moment) on
+// the system tests for the tools using this module.
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+static
+std::size_t
+array_size(const char* const* array)
+{
+ std::size_t size = 0;
+
+ for (const char* const* ptr = array; *ptr != NULL; ptr++)
+ size++;
+
+ return size;
+}
+
+static
+atf::process::status
+exec_process_helpers(const atf::tests::tc& tc, const char* helper_name)
+{
+ using atf::process::exec;
+
+ std::vector< std::string > argv;
+ argv.push_back(get_process_helpers_path(tc).leaf_name());
+ argv.push_back(helper_name);
+
+ return exec(get_process_helpers_path(tc),
+ atf::process::argv_array(argv),
+ atf::process::stream_inherit(),
+ atf::process::stream_inherit());
+}
+
+// ------------------------------------------------------------------------
+// Tests for the "argv_array" type.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(argv_array_init_carray);
+ATF_TEST_CASE_HEAD(argv_array_init_carray)
+{
+ set_md_var("descr", "Tests that argv_array is correctly constructed "
+ "from a C-style array of strings");
+}
+ATF_TEST_CASE_BODY(argv_array_init_carray)
+{
+ {
+ const char* const carray[] = { NULL };
+ atf::process::argv_array argv(carray);
+
+ ATF_REQUIRE_EQ(argv.size(), 0);
+ }
+
+ {
+ const char* const carray[] = { "arg0", NULL };
+ atf::process::argv_array argv(carray);
+
+ ATF_REQUIRE_EQ(argv.size(), 1);
+ ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
+ }
+
+ {
+ const char* const carray[] = { "arg0", "arg1", "arg2", NULL };
+ atf::process::argv_array argv(carray);
+
+ ATF_REQUIRE_EQ(argv.size(), 3);
+ ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
+ ATF_REQUIRE(std::strcmp(argv[1], carray[1]) == 0);
+ ATF_REQUIRE(std::strcmp(argv[2], carray[2]) == 0);
+ }
+}
+
+ATF_TEST_CASE(argv_array_init_col);
+ATF_TEST_CASE_HEAD(argv_array_init_col)
+{
+ set_md_var("descr", "Tests that argv_array is correctly constructed "
+ "from a string collection");
+}
+ATF_TEST_CASE_BODY(argv_array_init_col)
+{
+ {
+ std::vector< std::string > col;
+ atf::process::argv_array argv(col);
+
+ ATF_REQUIRE_EQ(argv.size(), 0);
+ }
+
+ {
+ std::vector< std::string > col;
+ col.push_back("arg0");
+ atf::process::argv_array argv(col);
+
+ ATF_REQUIRE_EQ(argv.size(), 1);
+ ATF_REQUIRE_EQ(argv[0], col[0]);
+ }
+
+ {
+ std::vector< std::string > col;
+ col.push_back("arg0");
+ col.push_back("arg1");
+ col.push_back("arg2");
+ atf::process::argv_array argv(col);
+
+ ATF_REQUIRE_EQ(argv.size(), 3);
+ ATF_REQUIRE_EQ(argv[0], col[0]);
+ ATF_REQUIRE_EQ(argv[1], col[1]);
+ ATF_REQUIRE_EQ(argv[2], col[2]);
+ }
+}
+
+ATF_TEST_CASE(argv_array_init_empty);
+ATF_TEST_CASE_HEAD(argv_array_init_empty)
+{
+ set_md_var("descr", "Tests that argv_array is correctly constructed "
+ "by the default constructor");
+}
+ATF_TEST_CASE_BODY(argv_array_init_empty)
+{
+ atf::process::argv_array argv;
+
+ ATF_REQUIRE_EQ(argv.size(), 0);
+}
+
+ATF_TEST_CASE(argv_array_init_varargs);
+ATF_TEST_CASE_HEAD(argv_array_init_varargs)
+{
+ set_md_var("descr", "Tests that argv_array is correctly constructed "
+ "from a variable list of arguments");
+}
+ATF_TEST_CASE_BODY(argv_array_init_varargs)
+{
+ {
+ atf::process::argv_array argv("arg0", NULL);
+
+ ATF_REQUIRE_EQ(argv.size(), 1);
+ ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
+ }
+
+ {
+ atf::process::argv_array argv("arg0", "arg1", "arg2", NULL);
+
+ ATF_REQUIRE_EQ(argv.size(), 3);
+ ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
+ ATF_REQUIRE_EQ(argv[1], std::string("arg1"));
+ ATF_REQUIRE_EQ(argv[2], std::string("arg2"));
+ }
+}
+
+ATF_TEST_CASE(argv_array_assign);
+ATF_TEST_CASE_HEAD(argv_array_assign)
+{
+ set_md_var("descr", "Tests that assigning an argv_array works");
+}
+ATF_TEST_CASE_BODY(argv_array_assign)
+{
+ using atf::process::argv_array;
+
+ const char* const carray1[] = { "arg1", NULL };
+ const char* const carray2[] = { "arg1", "arg2", NULL };
+
+ std::auto_ptr< argv_array > argv1(new argv_array(carray1));
+ std::auto_ptr< argv_array > argv2(new argv_array(carray2));
+
+ *argv2 = *argv1;
+ ATF_REQUIRE_EQ(argv2->size(), argv1->size());
+ ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
+
+ ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
+ argv1.release();
+ {
+ const char* const* eargv2 = argv2->exec_argv();
+ ATF_REQUIRE(std::strcmp(eargv2[0], carray1[0]) == 0);
+ ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
+ }
+
+ argv2.release();
+}
+
+ATF_TEST_CASE(argv_array_copy);
+ATF_TEST_CASE_HEAD(argv_array_copy)
+{
+ set_md_var("descr", "Tests that copying an argv_array constructed from "
+ "a C-style array of strings works");
+}
+ATF_TEST_CASE_BODY(argv_array_copy)
+{
+ using atf::process::argv_array;
+
+ const char* const carray[] = { "arg0", NULL };
+
+ std::auto_ptr< argv_array > argv1(new argv_array(carray));
+ std::auto_ptr< argv_array > argv2(new argv_array(*argv1));
+
+ ATF_REQUIRE_EQ(argv2->size(), argv1->size());
+ ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
+
+ ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
+ argv1.release();
+ {
+ const char* const* eargv2 = argv2->exec_argv();
+ ATF_REQUIRE(std::strcmp(eargv2[0], carray[0]) == 0);
+ ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
+ }
+
+ argv2.release();
+}
+
+ATF_TEST_CASE(argv_array_exec_argv);
+ATF_TEST_CASE_HEAD(argv_array_exec_argv)
+{
+ set_md_var("descr", "Tests that the exec argv provided by an argv_array "
+ "is correct");
+}
+ATF_TEST_CASE_BODY(argv_array_exec_argv)
+{
+ using atf::process::argv_array;
+
+ {
+ argv_array argv;
+ const char* const* eargv = argv.exec_argv();
+ ATF_REQUIRE_EQ(array_size(eargv), 0);
+ ATF_REQUIRE_EQ(eargv[0], static_cast< const char* >(NULL));
+ }
+
+ {
+ const char* const carray[] = { "arg0", NULL };
+ argv_array argv(carray);
+ const char* const* eargv = argv.exec_argv();
+ ATF_REQUIRE_EQ(array_size(eargv), 1);
+ ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
+ ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
+ }
+
+ {
+ std::vector< std::string > col;
+ col.push_back("arg0");
+ argv_array argv(col);
+ const char* const* eargv = argv.exec_argv();
+ ATF_REQUIRE_EQ(array_size(eargv), 1);
+ ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
+ ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
+ }
+}
+
+ATF_TEST_CASE(argv_array_iter);
+ATF_TEST_CASE_HEAD(argv_array_iter)
+{
+ set_md_var("descr", "Tests that an argv_array can be iterated");
+}
+ATF_TEST_CASE_BODY(argv_array_iter)
+{
+ using atf::process::argv_array;
+
+ std::vector< std::string > vector;
+ vector.push_back("arg0");
+ vector.push_back("arg1");
+ vector.push_back("arg2");
+
+ argv_array argv(vector);
+ ATF_REQUIRE_EQ(argv.size(), 3);
+ std::vector< std::string >::size_type pos = 0;
+ for (argv_array::const_iterator iter = argv.begin(); iter != argv.end();
+ iter++) {
+ ATF_REQUIRE_EQ(*iter, vector[pos]);
+ pos++;
+ }
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(exec_failure);
+ATF_TEST_CASE_HEAD(exec_failure)
+{
+ set_md_var("descr", "Tests execing a command that reports failure");
+}
+ATF_TEST_CASE_BODY(exec_failure)
+{
+ const atf::process::status s = exec_process_helpers(*this, "exit-failure");
+ ATF_REQUIRE(s.exited());
+ ATF_REQUIRE_EQ(s.exitstatus(), EXIT_FAILURE);
+}
+
+ATF_TEST_CASE(exec_success);
+ATF_TEST_CASE_HEAD(exec_success)
+{
+ set_md_var("descr", "Tests execing a command that reports success");
+}
+ATF_TEST_CASE_BODY(exec_success)
+{
+ const atf::process::status s = exec_process_helpers(*this, "exit-success");
+ ATF_REQUIRE(s.exited());
+ ATF_REQUIRE_EQ(s.exitstatus(), EXIT_SUCCESS);
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the "argv_array" type.
+ ATF_ADD_TEST_CASE(tcs, argv_array_assign);
+ ATF_ADD_TEST_CASE(tcs, argv_array_copy);
+ ATF_ADD_TEST_CASE(tcs, argv_array_exec_argv);
+ ATF_ADD_TEST_CASE(tcs, argv_array_init_carray);
+ ATF_ADD_TEST_CASE(tcs, argv_array_init_col);
+ ATF_ADD_TEST_CASE(tcs, argv_array_init_empty);
+ ATF_ADD_TEST_CASE(tcs, argv_array_init_varargs);
+ ATF_ADD_TEST_CASE(tcs, argv_array_iter);
+
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, exec_failure);
+ ATF_ADD_TEST_CASE(tcs, exec_success);
+}
diff --git a/contrib/atf/atf-c++/detail/sanity.hpp b/contrib/atf/atf-c++/detail/sanity.hpp
new file mode 100644
index 0000000..6021a6e
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/sanity.hpp
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_SANITY_HPP_)
+#define _ATF_CXX_SANITY_HPP_
+
+extern "C" {
+#include "../../atf-c/detail/sanity.h"
+}
+
+#endif // !defined(_ATF_CXX_SANITY_HPP_)
diff --git a/contrib/atf/atf-c++/detail/sanity_test.cpp b/contrib/atf/atf-c++/detail/sanity_test.cpp
new file mode 100644
index 0000000..8d3a07e
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/sanity_test.cpp
@@ -0,0 +1,41 @@
+//
+// 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 "../macros.hpp"
+
+ATF_TEST_CASE_WITHOUT_HEAD(nothing);
+ATF_TEST_CASE_BODY(nothing)
+{
+ // TODO
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, nothing);
+}
diff --git a/contrib/atf/atf-c++/detail/test_helpers.cpp b/contrib/atf/atf-c++/detail/test_helpers.cpp
new file mode 100644
index 0000000..42bd711
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/test_helpers.cpp
@@ -0,0 +1,160 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <regex.h>
+}
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "../check.hpp"
+#include "../config.hpp"
+#include "../macros.hpp"
+
+#include "fs.hpp"
+#include "process.hpp"
+#include "test_helpers.hpp"
+
+void
+build_check_cxx_o_aux(const atf::fs::path& sfile, const char* failmsg,
+ const bool expect_pass)
+{
+ std::vector< std::string > optargs;
+ optargs.push_back("-I" + atf::config::get("atf_includedir"));
+ optargs.push_back("-Wall");
+ optargs.push_back("-Werror");
+
+ const bool result = atf::check::build_cxx_o(
+ sfile.str(), "test.o", atf::process::argv_array(optargs));
+ if ((expect_pass && !result) || (!expect_pass && result))
+ ATF_FAIL(failmsg);
+}
+
+void
+build_check_cxx_o(const atf::tests::tc& tc, const char* sfile,
+ const char* failmsg, const bool expect_pass)
+{
+ const atf::fs::path sfilepath =
+ atf::fs::path(tc.get_config_var("srcdir")) / sfile;
+ build_check_cxx_o_aux(sfilepath, failmsg, expect_pass);
+}
+
+void
+header_check(const char *hdrname)
+{
+ std::ofstream srcfile("test.c");
+ ATF_REQUIRE(srcfile);
+ srcfile << "#include <" << hdrname << ">\n";
+ srcfile.close();
+
+ const std::string failmsg = std::string("Header check failed; ") +
+ hdrname + " is not self-contained";
+ build_check_cxx_o_aux(atf::fs::path("test.c"), failmsg.c_str(), true);
+}
+
+atf::fs::path
+get_process_helpers_path(const atf::tests::tc& tc)
+{
+ return atf::fs::path(tc.get_config_var("srcdir")) /
+ ".." / "atf-c" / "detail" / "process_helpers";
+}
+
+bool
+grep_file(const char* name, const char* regex)
+{
+ std::ifstream is(name);
+ ATF_REQUIRE(is);
+
+ bool found = false;
+
+ std::string line;
+ std::getline(is, line);
+ while (!found && is.good()) {
+ if (grep_string(line, regex))
+ found = true;
+ else
+ std::getline(is, line);
+ }
+
+ return found;
+}
+
+bool
+grep_string(const std::string& str, const char* regex)
+{
+ int res;
+ regex_t preg;
+
+ std::cout << "Looking for '" << regex << "' in '" << str << "'\n";
+ ATF_REQUIRE(::regcomp(&preg, regex, REG_EXTENDED) == 0);
+
+ res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
+ ATF_REQUIRE(res == 0 || res == REG_NOMATCH);
+
+ ::regfree(&preg);
+
+ return res == 0;
+}
+
+void
+test_helpers_detail::check_equal(const char* expected[],
+ const string_vector& actual)
+{
+ const char** expected_iter = expected;
+ string_vector::const_iterator actual_iter = actual.begin();
+
+ bool equals = true;
+ while (equals && *expected_iter != NULL && actual_iter != actual.end()) {
+ if (*expected_iter != *actual_iter) {
+ equals = false;
+ } else {
+ expected_iter++;
+ actual_iter++;
+ }
+ }
+ if (equals && ((*expected_iter == NULL && actual_iter != actual.end()) ||
+ (*expected_iter != NULL && actual_iter == actual.end())))
+ equals = false;
+
+ if (!equals) {
+ std::cerr << "EXPECTED:\n";
+ for (expected_iter = expected; *expected_iter != NULL; expected_iter++)
+ std::cerr << *expected_iter << "\n";
+
+ std::cerr << "ACTUAL:\n";
+ for (actual_iter = actual.begin(); actual_iter != actual.end();
+ actual_iter++)
+ std::cerr << *actual_iter << "\n";
+
+ ATF_FAIL("Expected results differ to actual values");
+ }
+}
diff --git a/contrib/atf/atf-c++/detail/test_helpers.hpp b/contrib/atf/atf-c++/detail/test_helpers.hpp
new file mode 100644
index 0000000..059a0a5
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/test_helpers.hpp
@@ -0,0 +1,166 @@
+//
+// 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.
+//
+
+#if defined(TESTS_ATF_ATF_CXX_TEST_HELPERS_H)
+# error "Cannot include test_helpers.hpp more than once."
+#else
+# define TESTS_ATF_ATF_CXX_TEST_HELPERS_H
+#endif
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+#include <utility>
+
+#include "../macros.hpp"
+#include "../tests.hpp"
+#include "parser.hpp"
+#include "process.hpp"
+#include "text.hpp"
+
+#define HEADER_TC(name, hdrname) \
+ ATF_TEST_CASE(name); \
+ ATF_TEST_CASE_HEAD(name) \
+ { \
+ set_md_var("descr", "Tests that the " hdrname " file can be " \
+ "included on its own, without any prerequisites"); \
+ } \
+ ATF_TEST_CASE_BODY(name) \
+ { \
+ header_check(hdrname); \
+ }
+
+#define BUILD_TC(name, sfile, descr, failmsg) \
+ ATF_TEST_CASE(name); \
+ ATF_TEST_CASE_HEAD(name) \
+ { \
+ set_md_var("descr", descr); \
+ } \
+ ATF_TEST_CASE_BODY(name) \
+ { \
+ build_check_cxx_o(*this, sfile, failmsg, true); \
+ }
+
+#define BUILD_TC_FAIL(name, sfile, descr, failmsg) \
+ ATF_TEST_CASE(name); \
+ ATF_TEST_CASE_HEAD(name) \
+ { \
+ set_md_var("descr", descr); \
+ } \
+ ATF_TEST_CASE_BODY(name) \
+ { \
+ build_check_cxx_o(*this, sfile, failmsg, false); \
+ }
+
+namespace atf {
+namespace tests {
+class tc;
+}
+}
+
+void header_check(const char*);
+void build_check_cxx_o(const atf::tests::tc&, const char*, const char*, bool);
+atf::fs::path get_process_helpers_path(const atf::tests::tc&);
+bool grep_file(const char*, const char*);
+bool grep_string(const std::string&, const char*);
+
+struct run_h_tc_data {
+ const atf::tests::vars_map& m_config;
+
+ run_h_tc_data(const atf::tests::vars_map& config) :
+ m_config(config) {}
+};
+
+template< class TestCase >
+void
+run_h_tc_child(void* v)
+{
+ run_h_tc_data* data = static_cast< run_h_tc_data* >(v);
+
+ TestCase tc;
+ tc.init(data->m_config);
+ tc.run("result");
+ std::exit(EXIT_SUCCESS);
+}
+
+template< class TestCase >
+void
+run_h_tc(atf::tests::vars_map config = atf::tests::vars_map())
+{
+ run_h_tc_data data(config);
+ atf::process::child c = atf::process::fork(
+ run_h_tc_child< TestCase >,
+ atf::process::stream_redirect_path(atf::fs::path("stdout")),
+ atf::process::stream_redirect_path(atf::fs::path("stderr")),
+ &data);
+ const atf::process::status s = c.wait();
+ ATF_REQUIRE(s.exited());
+}
+
+namespace test_helpers_detail {
+
+typedef std::vector< std::string > string_vector;
+
+template< class Reader >
+std::pair< string_vector, string_vector >
+do_read(const char* input)
+{
+ string_vector errors;
+
+ std::istringstream is(input);
+ Reader reader(is);
+ try {
+ reader.read();
+ } catch (const atf::parser::parse_errors& pes) {
+ for (std::vector< atf::parser::parse_error >::const_iterator iter =
+ pes.begin(); iter != pes.end(); iter++)
+ errors.push_back(*iter);
+ } catch (const atf::parser::parse_error& pe) {
+ ATF_FAIL("Raised a lonely parse error: " +
+ atf::text::to_string(pe.first) + ": " + pe.second);
+ }
+
+ return std::make_pair(reader.m_calls, errors);
+}
+
+void check_equal(const char*[], const string_vector&);
+
+} // namespace test_helpers_detail
+
+template< class Reader >
+void
+do_parser_test(const char* input, const char* exp_calls[],
+ const char* exp_errors[])
+{
+ const std::pair< test_helpers_detail::string_vector,
+ test_helpers_detail::string_vector >
+ actual = test_helpers_detail::do_read< Reader >(input);
+ test_helpers_detail::check_equal(exp_calls, actual.first);
+ test_helpers_detail::check_equal(exp_errors, actual.second);
+}
diff --git a/contrib/atf/atf-c++/detail/text.cpp b/contrib/atf/atf-c++/detail/text.cpp
new file mode 100644
index 0000000..66eebf0
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/text.cpp
@@ -0,0 +1,160 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <regex.h>
+}
+
+#include <cctype>
+#include <cstring>
+
+extern "C" {
+#include "../../atf-c/error.h"
+
+#include "../../atf-c/detail/text.h"
+}
+
+#include "exceptions.hpp"
+#include "text.hpp"
+
+namespace impl = atf::text;
+#define IMPL_NAME "atf::text"
+
+char*
+impl::duplicate(const char* str)
+{
+ char* copy = new char[std::strlen(str) + 1];
+ std::strcpy(copy, str);
+ return copy;
+}
+
+bool
+impl::match(const std::string& str, const std::string& regex)
+{
+ bool found;
+
+ // Special case: regcomp does not like empty regular expressions.
+ if (regex.empty()) {
+ found = str.empty();
+ } else {
+ ::regex_t preg;
+
+ if (::regcomp(&preg, regex.c_str(), REG_EXTENDED) != 0)
+ throw std::runtime_error("Invalid regular expression '" + regex +
+ "'");
+
+ const int res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
+ regfree(&preg);
+ if (res != 0 && res != REG_NOMATCH)
+ throw std::runtime_error("Invalid regular expression " + regex);
+
+ found = res == 0;
+ }
+
+ return found;
+}
+
+std::string
+impl::to_lower(const std::string& str)
+{
+ std::string lc;
+ for (std::string::const_iterator iter = str.begin(); iter != str.end();
+ iter++)
+ lc += std::tolower(*iter);
+ return lc;
+}
+
+std::vector< std::string >
+impl::split(const std::string& str, const std::string& delim)
+{
+ std::vector< std::string > words;
+
+ std::string::size_type pos = 0, newpos = 0;
+ while (pos < str.length() && newpos != std::string::npos) {
+ newpos = str.find(delim, pos);
+ if (newpos != pos)
+ words.push_back(str.substr(pos, newpos - pos));
+ pos = newpos + delim.length();
+ }
+
+ return words;
+}
+
+std::string
+impl::trim(const std::string& str)
+{
+ std::string::size_type pos1 = str.find_first_not_of(" \t");
+ std::string::size_type pos2 = str.find_last_not_of(" \t");
+
+ if (pos1 == std::string::npos && pos2 == std::string::npos)
+ return "";
+ else if (pos1 == std::string::npos)
+ return str.substr(0, str.length() - pos2);
+ else if (pos2 == std::string::npos)
+ return str.substr(pos1);
+ else
+ return str.substr(pos1, pos2 - pos1 + 1);
+}
+
+bool
+impl::to_bool(const std::string& str)
+{
+ bool b;
+
+ atf_error_t err = atf_text_to_bool(str.c_str(), &b);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+
+ return b;
+}
+
+int64_t
+impl::to_bytes(std::string str)
+{
+ if (str.empty())
+ throw std::runtime_error("Empty value");
+
+ const char unit = str[str.length() - 1];
+ int64_t multiplier;
+ switch (unit) {
+ case 'k': case 'K': multiplier = 1 << 10; break;
+ case 'm': case 'M': multiplier = 1 << 20; break;
+ case 'g': case 'G': multiplier = 1 << 30; break;
+ case 't': case 'T': multiplier = int64_t(1) << 40; break;
+ default:
+ if (!std::isdigit(unit))
+ throw std::runtime_error(std::string("Unknown size unit '") + unit
+ + "'");
+ multiplier = 1;
+ }
+ if (multiplier != 1)
+ str.erase(str.length() - 1);
+
+ return to_type< int64_t >(str) * multiplier;
+}
diff --git a/contrib/atf/atf-c++/detail/text.hpp b/contrib/atf/atf-c++/detail/text.hpp
new file mode 100644
index 0000000..6a1b027
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/text.hpp
@@ -0,0 +1,153 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_TEXT_HPP_)
+#define _ATF_CXX_TEXT_HPP_
+
+extern "C" {
+#include <stdint.h>
+}
+
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace atf {
+namespace text {
+
+//!
+//! \brief Duplicates a C string using the new[] allocator.
+//!
+//! Replaces the functionality of strdup by using the new[] allocator and
+//! thus allowing the resulting memory to be managed by utils::auto_array.
+//!
+char* duplicate(const char*);
+
+//!
+//! \brief Joins multiple words into a string.
+//!
+//! Joins a list of words into a string, separating them using the provided
+//! separator. Empty words are not omitted.
+//!
+template< class T >
+std::string
+join(const T& words, const std::string& separator)
+{
+ std::string str;
+
+ typename T::const_iterator iter = words.begin();
+ bool done = iter == words.end();
+ while (!done) {
+ str += *iter;
+ iter++;
+ if (iter != words.end())
+ str += separator;
+ else
+ done = true;
+ }
+
+ return str;
+}
+
+//!
+//! \brief Checks if the string matches a regular expression.
+//!
+bool match(const std::string&, const std::string&);
+
+//!
+//! \brief Splits a string into words.
+//!
+//! Splits the given string into multiple words, all separated by the
+//! given delimiter. Multiple occurrences of the same delimiter are
+//! not condensed so that rejoining the words later on using the same
+//! delimiter results in the original string.
+//!
+std::vector< std::string > split(const std::string&, const std::string&);
+
+//!
+//! \brief Removes whitespace from the beginning and end of a string.
+//!
+std::string trim(const std::string&);
+
+//!
+//! \brief Converts a string to a boolean value.
+//!
+bool to_bool(const std::string&);
+
+//!
+//! \brief Converts the given string to a bytes size.
+//!
+int64_t to_bytes(std::string);
+
+//!
+//! \brief Changes the case of a string to lowercase.
+//!
+//! Returns a new string that is a lowercased version of the original
+//! one.
+//!
+std::string to_lower(const std::string&);
+
+//!
+//! \brief Converts the given object to a string.
+//!
+//! Returns a string with the representation of the given object. There
+//! must exist an operator<< method for that object.
+//!
+template< class T >
+std::string
+to_string(const T& ob)
+{
+ std::ostringstream ss;
+ ss << ob;
+ return ss.str();
+}
+
+//!
+//! \brief Converts the given string to another type.
+//!
+//! Attempts to convert the given string to the requested type. Throws
+//! an exception if the conversion failed.
+//!
+template< class T >
+T
+to_type(const std::string& str)
+{
+ std::istringstream ss(str);
+ T value;
+ ss >> value;
+ if (!ss.eof() || (ss.eof() && (ss.fail() || ss.bad())))
+ throw std::runtime_error("Cannot convert string to requested type");
+ return value;
+}
+
+} // namespace text
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_TEXT_HPP_)
diff --git a/contrib/atf/atf-c++/detail/text_test.cpp b/contrib/atf/atf-c++/detail/text_test.cpp
new file mode 100644
index 0000000..b7c0ba1
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/text_test.cpp
@@ -0,0 +1,390 @@
+//
+// 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.
+//
+
+#include <cstring>
+#include <set>
+#include <vector>
+
+#include "../macros.hpp"
+
+#include "text.hpp"
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(duplicate);
+ATF_TEST_CASE_HEAD(duplicate)
+{
+ set_md_var("descr", "Tests the duplicate function");
+}
+ATF_TEST_CASE_BODY(duplicate)
+{
+ using atf::text::duplicate;
+
+ const char* orig = "foo";
+
+ char* copy = duplicate(orig);
+ ATF_REQUIRE_EQ(std::strlen(copy), 3);
+ ATF_REQUIRE(std::strcmp(copy, "foo") == 0);
+
+ std::strcpy(copy, "bar");
+ ATF_REQUIRE(std::strcmp(copy, "bar") == 0);
+ ATF_REQUIRE(std::strcmp(orig, "foo") == 0);
+}
+
+ATF_TEST_CASE(join);
+ATF_TEST_CASE_HEAD(join)
+{
+ set_md_var("descr", "Tests the join function");
+}
+ATF_TEST_CASE_BODY(join)
+{
+ using atf::text::join;
+
+ // First set of tests using a non-sorted collection, std::vector.
+ {
+ std::vector< std::string > words;
+ std::string str;
+
+ words.clear();
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "");
+
+ words.clear();
+ words.push_back("");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "");
+
+ words.clear();
+ words.push_back("");
+ words.push_back("");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, ",");
+
+ words.clear();
+ words.push_back("foo");
+ words.push_back("");
+ words.push_back("baz");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "foo,,baz");
+
+ words.clear();
+ words.push_back("foo");
+ words.push_back("bar");
+ words.push_back("baz");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "foo,bar,baz");
+ }
+
+ // Second set of tests using a sorted collection, std::set.
+ {
+ std::set< std::string > words;
+ std::string str;
+
+ words.clear();
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "");
+
+ words.clear();
+ words.insert("");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "");
+
+ words.clear();
+ words.insert("foo");
+ words.insert("");
+ words.insert("baz");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, ",baz,foo");
+
+ words.clear();
+ words.insert("foo");
+ words.insert("bar");
+ words.insert("baz");
+ str = join(words, ",");
+ ATF_REQUIRE_EQ(str, "bar,baz,foo");
+ }
+}
+
+ATF_TEST_CASE(match);
+ATF_TEST_CASE_HEAD(match)
+{
+ set_md_var("descr", "Tests the match function");
+}
+ATF_TEST_CASE_BODY(match)
+{
+ using atf::text::match;
+
+ ATF_REQUIRE_THROW(std::runtime_error, match("", "["));
+
+ ATF_REQUIRE(match("", ""));
+ ATF_REQUIRE(!match("foo", ""));
+
+ ATF_REQUIRE(match("", ".*"));
+ ATF_REQUIRE(match("", "[a-z]*"));
+
+ ATF_REQUIRE(match("hello", "hello"));
+ ATF_REQUIRE(match("hello", "[a-z]+"));
+ ATF_REQUIRE(match("hello", "^[a-z]+$"));
+
+ ATF_REQUIRE(!match("hello", "helooo"));
+ ATF_REQUIRE(!match("hello", "[a-z]+5"));
+ ATF_REQUIRE(!match("hello", "^ [a-z]+$"));
+}
+
+ATF_TEST_CASE(split);
+ATF_TEST_CASE_HEAD(split)
+{
+ set_md_var("descr", "Tests the split function");
+}
+ATF_TEST_CASE_BODY(split)
+{
+ using atf::text::split;
+
+ std::vector< std::string > words;
+
+ words = split("", " ");
+ ATF_REQUIRE_EQ(words.size(), 0);
+
+ words = split(" ", " ");
+ ATF_REQUIRE_EQ(words.size(), 0);
+
+ words = split(" ", " ");
+ ATF_REQUIRE_EQ(words.size(), 0);
+
+ words = split("a b", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "a");
+ ATF_REQUIRE_EQ(words[1], "b");
+
+ words = split("a b c d", " ");
+ ATF_REQUIRE_EQ(words.size(), 4);
+ ATF_REQUIRE_EQ(words[0], "a");
+ ATF_REQUIRE_EQ(words[1], "b");
+ ATF_REQUIRE_EQ(words[2], "c");
+ ATF_REQUIRE_EQ(words[3], "d");
+
+ words = split("foo bar", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+
+ words = split("foo bar baz foobar", " ");
+ ATF_REQUIRE_EQ(words.size(), 4);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+ ATF_REQUIRE_EQ(words[2], "baz");
+ ATF_REQUIRE_EQ(words[3], "foobar");
+
+ words = split(" foo bar", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+
+ words = split("foo bar", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+
+ words = split("foo bar ", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+
+ words = split(" foo bar ", " ");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "foo");
+ ATF_REQUIRE_EQ(words[1], "bar");
+}
+
+ATF_TEST_CASE(split_delims);
+ATF_TEST_CASE_HEAD(split_delims)
+{
+ set_md_var("descr", "Tests the split function using different delimiters");
+}
+ATF_TEST_CASE_BODY(split_delims)
+{
+ using atf::text::split;
+
+ std::vector< std::string > words;
+
+ words = split("", "/");
+ ATF_REQUIRE_EQ(words.size(), 0);
+
+ words = split(" ", "/");
+ ATF_REQUIRE_EQ(words.size(), 1);
+ ATF_REQUIRE_EQ(words[0], " ");
+
+ words = split(" ", "/");
+ ATF_REQUIRE_EQ(words.size(), 1);
+ ATF_REQUIRE_EQ(words[0], " ");
+
+ words = split("a/b", "/");
+ ATF_REQUIRE_EQ(words.size(), 2);
+ ATF_REQUIRE_EQ(words[0], "a");
+ ATF_REQUIRE_EQ(words[1], "b");
+
+ words = split("aLONGDELIMbcdLONGDELIMef", "LONGDELIM");
+ ATF_REQUIRE_EQ(words.size(), 3);
+ ATF_REQUIRE_EQ(words[0], "a");
+ ATF_REQUIRE_EQ(words[1], "bcd");
+ ATF_REQUIRE_EQ(words[2], "ef");
+}
+
+ATF_TEST_CASE(trim);
+ATF_TEST_CASE_HEAD(trim)
+{
+ set_md_var("descr", "Tests the trim function");
+}
+ATF_TEST_CASE_BODY(trim)
+{
+ using atf::text::trim;
+
+ ATF_REQUIRE_EQ(trim(""), "");
+ ATF_REQUIRE_EQ(trim(" "), "");
+ ATF_REQUIRE_EQ(trim("\t"), "");
+
+ ATF_REQUIRE_EQ(trim(" foo"), "foo");
+ ATF_REQUIRE_EQ(trim("\t foo"), "foo");
+ ATF_REQUIRE_EQ(trim(" \tfoo"), "foo");
+ ATF_REQUIRE_EQ(trim("foo\t "), "foo");
+ ATF_REQUIRE_EQ(trim("foo \t"), "foo");
+
+ ATF_REQUIRE_EQ(trim("foo bar"), "foo bar");
+ ATF_REQUIRE_EQ(trim("\t foo bar"), "foo bar");
+ ATF_REQUIRE_EQ(trim(" \tfoo bar"), "foo bar");
+ ATF_REQUIRE_EQ(trim("foo bar\t "), "foo bar");
+ ATF_REQUIRE_EQ(trim("foo bar \t"), "foo bar");
+}
+
+ATF_TEST_CASE(to_bool);
+ATF_TEST_CASE_HEAD(to_bool)
+{
+ set_md_var("descr", "Tests the to_string function");
+}
+ATF_TEST_CASE_BODY(to_bool)
+{
+ using atf::text::to_bool;
+
+ ATF_REQUIRE(to_bool("true"));
+ ATF_REQUIRE(to_bool("TRUE"));
+ ATF_REQUIRE(to_bool("yes"));
+ ATF_REQUIRE(to_bool("YES"));
+
+ ATF_REQUIRE(!to_bool("false"));
+ ATF_REQUIRE(!to_bool("FALSE"));
+ ATF_REQUIRE(!to_bool("no"));
+ ATF_REQUIRE(!to_bool("NO"));
+
+ ATF_REQUIRE_THROW(std::runtime_error, to_bool(""));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bool("tru"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bool("true2"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bool("fals"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bool("false2"));
+}
+
+ATF_TEST_CASE(to_bytes);
+ATF_TEST_CASE_HEAD(to_bytes)
+{
+ set_md_var("descr", "Tests the to_bytes function");
+}
+ATF_TEST_CASE_BODY(to_bytes)
+{
+ using atf::text::to_bytes;
+
+ ATF_REQUIRE_EQ(0, to_bytes("0"));
+ ATF_REQUIRE_EQ(12345, to_bytes("12345"));
+ ATF_REQUIRE_EQ(2 * 1024, to_bytes("2k"));
+ ATF_REQUIRE_EQ(4 * 1024 * 1024, to_bytes("4m"));
+ ATF_REQUIRE_EQ(int64_t(8) * 1024 * 1024 * 1024, to_bytes("8g"));
+ ATF_REQUIRE_EQ(int64_t(16) * 1024 * 1024 * 1024 * 1024, to_bytes("16t"));
+
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "Empty", to_bytes(""));
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "Unknown size unit 'd'",
+ to_bytes("12d"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bytes(" "));
+ ATF_REQUIRE_THROW(std::runtime_error, to_bytes(" k"));
+}
+
+ATF_TEST_CASE(to_string);
+ATF_TEST_CASE_HEAD(to_string)
+{
+ set_md_var("descr", "Tests the to_string function");
+}
+ATF_TEST_CASE_BODY(to_string)
+{
+ using atf::text::to_string;
+
+ ATF_REQUIRE_EQ(to_string('a'), "a");
+ ATF_REQUIRE_EQ(to_string("a"), "a");
+ ATF_REQUIRE_EQ(to_string(5), "5");
+}
+
+ATF_TEST_CASE(to_type);
+ATF_TEST_CASE_HEAD(to_type)
+{
+ set_md_var("descr", "Tests the to_type function");
+}
+ATF_TEST_CASE_BODY(to_type)
+{
+ using atf::text::to_type;
+
+ ATF_REQUIRE_EQ(to_type< int >("0"), 0);
+ ATF_REQUIRE_EQ(to_type< int >("1234"), 1234);
+ ATF_REQUIRE_THROW(std::runtime_error, to_type< int >(" "));
+ ATF_REQUIRE_THROW(std::runtime_error, to_type< int >("0 a"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_type< int >("a"));
+
+ ATF_REQUIRE_EQ(to_type< float >("0.5"), 0.5);
+ ATF_REQUIRE_EQ(to_type< float >("1234.5"), 1234.5);
+ ATF_REQUIRE_THROW(std::runtime_error, to_type< float >("0.5 a"));
+ ATF_REQUIRE_THROW(std::runtime_error, to_type< float >("a"));
+
+ ATF_REQUIRE_EQ(to_type< std::string >("a"), "a");
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, duplicate);
+ ATF_ADD_TEST_CASE(tcs, join);
+ ATF_ADD_TEST_CASE(tcs, match);
+ ATF_ADD_TEST_CASE(tcs, split);
+ ATF_ADD_TEST_CASE(tcs, split_delims);
+ ATF_ADD_TEST_CASE(tcs, trim);
+ ATF_ADD_TEST_CASE(tcs, to_bool);
+ ATF_ADD_TEST_CASE(tcs, to_bytes);
+ ATF_ADD_TEST_CASE(tcs, to_string);
+ ATF_ADD_TEST_CASE(tcs, to_type);
+}
diff --git a/contrib/atf/atf-c++/detail/ui.cpp b/contrib/atf/atf-c++/detail/ui.cpp
new file mode 100644
index 0000000..07bde4f
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/ui.cpp
@@ -0,0 +1,173 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <sys/ioctl.h>
+
+#include <termios.h>
+#include <unistd.h>
+}
+
+#include <sstream>
+
+#include "env.hpp"
+#include "text.hpp"
+#include "sanity.hpp"
+#include "text.hpp"
+#include "ui.hpp"
+
+namespace impl = atf::ui;
+#define IMPL_NAME "atf::ui"
+
+static
+size_t
+terminal_width(void)
+{
+ static bool done = false;
+ static size_t width = 0;
+
+ if (!done) {
+ if (atf::env::has("COLUMNS")) {
+ const std::string cols = atf::env::get("COLUMNS");
+ if (cols.length() > 0) {
+ width = atf::text::to_type< size_t >(cols);
+ }
+ } else {
+ struct winsize ws;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
+ width = ws.ws_col;
+ }
+
+ if (width >= 80)
+ width -= 5;
+
+ done = true;
+ }
+
+ return width;
+}
+
+static
+std::string
+format_paragraph(const std::string& text,
+ const std::string& tag,
+ const bool first,
+ const bool repeat,
+ const size_t col)
+{
+ PRE(text.find('\n') == std::string::npos);
+
+ const std::string pad(col - tag.length(), ' ');
+ const std::string fullpad(col, ' ');
+
+ std::string formatted;
+ if (first || repeat)
+ formatted = tag + pad;
+ else
+ formatted = fullpad;
+ INV(formatted.length() == col);
+ size_t curcol = col;
+
+ const size_t maxcol = terminal_width();
+
+ std::vector< std::string > words = atf::text::split(text, " ");
+ for (std::vector< std::string >::const_iterator iter = words.begin();
+ iter != words.end(); iter++) {
+ const std::string& word = *iter;
+
+ if (iter != words.begin() && maxcol > 0 &&
+ curcol + word.length() + 1 > maxcol) {
+ if (repeat)
+ formatted += '\n' + tag + pad;
+ else
+ formatted += '\n' + fullpad;
+ curcol = col;
+ } else if (iter != words.begin()) {
+ formatted += ' ';
+ curcol++;
+ }
+
+ formatted += word;
+ curcol += word.length();
+ }
+
+ return formatted;
+}
+
+std::string
+impl::format_error(const std::string& prog_name, const std::string& error)
+{
+ return format_text_with_tag("ERROR: " + error, prog_name + ": ", true);
+}
+
+std::string
+impl::format_info(const std::string& prog_name, const std::string& msg)
+{
+ return format_text_with_tag(msg, prog_name + ": ", true);
+}
+
+std::string
+impl::format_text(const std::string& text)
+{
+ return format_text_with_tag(text, "", false, 0);
+}
+
+std::string
+impl::format_text_with_tag(const std::string& text, const std::string& tag,
+ bool repeat, size_t col)
+{
+ PRE(col == 0 || col >= tag.length());
+ if (col == 0)
+ col = tag.length();
+
+ std::string formatted;
+
+ std::vector< std::string > lines = atf::text::split(text, "\n");
+ for (std::vector< std::string >::const_iterator iter = lines.begin();
+ iter != lines.end(); iter++) {
+ const std::string& line = *iter;
+
+ formatted += format_paragraph(line, tag, iter == lines.begin(),
+ repeat, col);
+ if (iter + 1 != lines.end()) {
+ if (repeat)
+ formatted += "\n" + tag + "\n";
+ else
+ formatted += "\n\n";
+ }
+ }
+
+ return formatted;
+}
+
+std::string
+impl::format_warning(const std::string& prog_name, const std::string& error)
+{
+ return format_text_with_tag("WARNING: " + error, prog_name + ": ", true);
+}
diff --git a/contrib/atf/atf-c++/detail/ui.hpp b/contrib/atf/atf-c++/detail/ui.hpp
new file mode 100644
index 0000000..1c81c56
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/ui.hpp
@@ -0,0 +1,105 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_UI_HPP_)
+#define _ATF_CXX_UI_HPP_
+
+#include <string>
+
+namespace atf {
+namespace ui {
+
+//!
+//! \brief Formats an error message to fit on screen.
+//!
+//! Given the program's name and an error message, properly formats it to
+//! fit on screen.
+//!
+//! The program's name is not stored globally to prevent the usage of this
+//! function from inside the library. Making it a explicit parameter
+//! restricts its usage to the frontend.
+//!
+std::string format_error(const std::string&, const std::string&);
+
+//!
+//! \brief Formats an informational message to fit on screen.
+//!
+//! Given the program's name and an informational message, properly formats
+//! it to fit on screen.
+//!
+//! The program's name is not stored globally to prevent the usage of this
+//! function from inside the library. Making it a explicit parameter
+//! restricts its usage to the frontend.
+//!
+std::string format_info(const std::string&, const std::string&);
+
+//!
+//! \brief Formats a block of text to fit nicely on screen.
+//!
+//! Given a text, which is composed of multiple paragraphs separated by
+//! a single '\n' character, reformats it to fill on the current screen's
+//! width with proper line wrapping.
+//!
+//! This is just a special case of format_text_with_tag, provided for
+//! simplicity.
+//!
+std::string format_text(const std::string&);
+
+//!
+//! \brief Formats a block of text to fit nicely on screen, prepending a
+//! tag to it.
+//!
+//! Given a text, which is composed of multiple paragraphs separated by
+//! a single '\n' character, reformats it to fill on the current screen's
+//! width with proper line wrapping. The text is prepended with a tag;
+//! i.e. a word that is printed at the beginning of the first paragraph and
+//! optionally repeated at the beginning of each word. The last parameter
+//! specifies the column on which the text should start, and that position
+//! must be greater than the tag's length or 0, in which case it
+//! automatically takes the correct value.
+//!
+std::string format_text_with_tag(const std::string&, const std::string&,
+ bool, size_t = 0);
+
+//!
+//! \brief Formats a warning message to fit on screen.
+//!
+//! Given the program's name and a warning message, properly formats it to
+//! fit on screen.
+//!
+//! The program's name is not stored globally to prevent the usage of this
+//! function from inside the library. Making it a explicit parameter
+//! restricts its usage to the frontend.
+//!
+std::string format_warning(const std::string&, const std::string&);
+
+} // namespace ui
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_UI_HPP_)
diff --git a/contrib/atf/atf-c++/detail/ui_test.cpp b/contrib/atf/atf-c++/detail/ui_test.cpp
new file mode 100644
index 0000000..918d028
--- /dev/null
+++ b/contrib/atf/atf-c++/detail/ui_test.cpp
@@ -0,0 +1,462 @@
+//
+// 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 <cstring>
+#include <iostream>
+
+#include "../macros.hpp"
+
+#include "env.hpp"
+#include "ui.hpp"
+
+// ------------------------------------------------------------------------
+// Test cases for the free functions.
+// ------------------------------------------------------------------------
+
+struct test {
+ const char *tc;
+ const char *tag;
+ bool repeat;
+ size_t col;
+ const char *fmt;
+ const char *result;
+} tests[] = {
+ //
+ // wo_tag
+ //
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345",
+ "12345",
+ },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345 ",
+ "12345",
+ },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345 7890",
+ "12345 7890",
+ },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345 789012 45",
+ "12345 789012 45",
+ },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345 789012 456",
+ "12345 789012\n456",
+ },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "1234567890123456",
+ "1234567890123456",
+ },
+
+ // TODO(jmmv): Fix the code to pass this test...
+// {
+// "wo_tag",
+// "",
+// false,
+// 0,
+// " 2345678901234567",
+// "\n2345678901234567",
+// },
+
+ {
+ "wo_tag",
+ "",
+ false,
+ 0,
+ "12345 789012345 78",
+ "12345 789012345\n78",
+ },
+
+ //
+ // wo_tag_col
+ //
+
+ {
+ "wo_tag_col",
+ "",
+ false,
+ 10,
+ "12345",
+ " 12345",
+ },
+
+ {
+ "wo_tag_col",
+ "",
+ false,
+ 10,
+ "12345 7890",
+ " 12345\n"
+ " 7890",
+ },
+
+ {
+ "wo_tag_col",
+ "",
+ false,
+ 10,
+ "1 3 5 7 9",
+ " 1 3 5\n"
+ " 7 9",
+ },
+
+ //
+ // w_tag_no_repeat
+ //
+
+ {
+ "w_tag_no_repeat",
+ "1234: ",
+ false,
+ 0,
+ "789012345",
+ "1234: 789012345",
+ },
+
+ {
+ "w_tag_no_repeat",
+ "1234: ",
+ false,
+ 0,
+ "789 1234 56789",
+ "1234: 789 1234\n"
+ " 56789",
+ },
+
+ {
+ "w_tag_no_repeat",
+ "1234: ",
+ false,
+ 0,
+ "789012345",
+ "1234: 789012345",
+ },
+
+ {
+ "w_tag_no_repeat",
+ "1234: ",
+ false,
+ 0,
+ "789012345 7890",
+ "1234: 789012345\n"
+ " 7890",
+ },
+
+ //
+ // w_tag_repeat
+ //
+
+ {
+ "w_tag_repeat",
+ "1234: ",
+ true,
+ 0,
+ "789012345",
+ "1234: 789012345",
+ },
+
+ {
+ "w_tag_repeat",
+ "1234: ",
+ true,
+ 0,
+ "789 1234 56789",
+ "1234: 789 1234\n"
+ "1234: 56789",
+ },
+
+ {
+ "w_tag_repeat",
+ "1234: ",
+ true,
+ 0,
+ "789012345",
+ "1234: 789012345",
+ },
+
+ {
+ "w_tag_no_repeat",
+ "1234: ",
+ true,
+ 0,
+ "789012345 7890",
+ "1234: 789012345\n"
+ "1234: 7890",
+ },
+
+ //
+ // w_tag_col
+ //
+
+ {
+ "w_tag_col",
+ "1234:",
+ false,
+ 10,
+ "1 3 5",
+ "1234: 1 3 5",
+ },
+
+ {
+ "w_tag_col",
+ "1234:",
+ false,
+ 10,
+ "1 3 5 7 9",
+ "1234: 1 3 5\n"
+ " 7 9",
+ },
+
+ {
+ "w_tag_col",
+ "1234:",
+ true,
+ 10,
+ "1 3 5 7 9",
+ "1234: 1 3 5\n"
+ "1234: 7 9",
+ },
+
+ //
+ // paragraphs
+ //
+
+ {
+ "paragraphs",
+ "",
+ false,
+ 0,
+ "1 3 5\n\n",
+ "1 3 5"
+ },
+
+ {
+ "paragraphs",
+ "",
+ false,
+ 0,
+ "1 3 5\n2 4 6",
+ "1 3 5\n\n2 4 6"
+ },
+
+ {
+ "paragraphs",
+ "",
+ false,
+ 0,
+ "1234 6789 123456\n2 4 6",
+ "1234 6789\n123456\n\n2 4 6"
+ },
+
+ {
+ "paragraphs",
+ "12: ",
+ false,
+ 0,
+ "56789 123456\n2 4 6",
+ "12: 56789\n 123456\n\n 2 4 6"
+ },
+
+ {
+ "paragraphs",
+ "12: ",
+ true,
+ 0,
+ "56789 123456\n2 4 6",
+ "12: 56789\n12: 123456\n12: \n12: 2 4 6"
+ },
+
+ {
+ "paragraphs",
+ "12:",
+ false,
+ 4,
+ "56789 123456\n2 4 6",
+ "12: 56789\n 123456\n\n 2 4 6"
+ },
+
+ {
+ "paragraphs",
+ "12:",
+ true,
+ 4,
+ "56789 123456\n2 4 6",
+ "12: 56789\n12: 123456\n12:\n12: 2 4 6"
+ },
+
+ //
+ // end
+ //
+
+ {
+ NULL,
+ NULL,
+ false,
+ 0,
+ NULL,
+ NULL,
+ },
+};
+
+static
+void
+run_tests(const char *tc)
+{
+ struct test *t;
+
+ std::cout << "Running tests for " << tc << "\n";
+
+ atf::env::set("COLUMNS", "15");
+
+ for (t = &tests[0]; t->tc != NULL; t++) {
+ if (std::strcmp(t->tc, tc) == 0) {
+ std::cout << "\n";
+ std::cout << "Testing with tag '" << t->tag << "', '"
+ << (t->repeat ? "repeat" : "no repeat") << "', col "
+ << t->col << "\n";
+ std::cout << "Input: >>>" << t->fmt << "<<<\n";
+ std::cout << "Expected output: >>>" << t->result << "<<<\n";
+
+ std::string result = atf::ui::format_text_with_tag(t->fmt, t->tag,
+ t->repeat, t->col);
+ std::cout << "Output : >>>" << result << "<<<\n";
+ ATF_REQUIRE_EQ(t->result, result);
+ }
+ }
+}
+
+ATF_TEST_CASE(wo_tag);
+ATF_TEST_CASE_HEAD(wo_tag)
+{
+ set_md_var("descr", "Checks formatting without tags");
+}
+ATF_TEST_CASE_BODY(wo_tag)
+{
+ run_tests("wo_tag");
+}
+
+ATF_TEST_CASE(wo_tag_col);
+ATF_TEST_CASE_HEAD(wo_tag_col)
+{
+ set_md_var("descr", "Checks formatting without tags and with a non-zero "
+ "starting column");
+}
+ATF_TEST_CASE_BODY(wo_tag_col)
+{
+ run_tests("wo_tag_col");
+}
+
+ATF_TEST_CASE(w_tag_no_repeat);
+ATF_TEST_CASE_HEAD(w_tag_no_repeat)
+{
+ set_md_var("descr", "Checks formatting with a tag");
+}
+ATF_TEST_CASE_BODY(w_tag_no_repeat)
+{
+ run_tests("w_tag_no_repeat");
+}
+
+ATF_TEST_CASE(w_tag_repeat);
+ATF_TEST_CASE_HEAD(w_tag_repeat)
+{
+ set_md_var("descr", "Checks formatting with a tag and repeating it on "
+ "each line");
+}
+ATF_TEST_CASE_BODY(w_tag_repeat)
+{
+ run_tests("w_tag_repeat");
+}
+
+ATF_TEST_CASE(w_tag_col);
+ATF_TEST_CASE_HEAD(w_tag_col)
+{
+ set_md_var("descr", "Checks formatting with a tag and starting at a "
+ "column greater than its length");
+}
+ATF_TEST_CASE_BODY(w_tag_col)
+{
+ run_tests("w_tag_col");
+}
+
+ATF_TEST_CASE(paragraphs);
+ATF_TEST_CASE_HEAD(paragraphs)
+{
+ set_md_var("descr", "Checks formatting a string that contains multiple "
+ "paragraphs");
+}
+ATF_TEST_CASE_BODY(paragraphs)
+{
+ run_tests("paragraphs");
+}
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the free functions.
+ ATF_ADD_TEST_CASE(tcs, wo_tag);
+ ATF_ADD_TEST_CASE(tcs, wo_tag_col);
+ ATF_ADD_TEST_CASE(tcs, w_tag_no_repeat);
+ ATF_ADD_TEST_CASE(tcs, w_tag_repeat);
+ ATF_ADD_TEST_CASE(tcs, w_tag_col);
+ ATF_ADD_TEST_CASE(tcs, paragraphs);
+}
diff --git a/contrib/atf/atf-c++/macros.hpp b/contrib/atf/atf-c++/macros.hpp
new file mode 100644
index 0000000..c6ce9c2
--- /dev/null
+++ b/contrib/atf/atf-c++/macros.hpp
@@ -0,0 +1,222 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_MACROS_HPP_)
+#define _ATF_CXX_MACROS_HPP_
+
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+
+#include <atf-c++/tests.hpp>
+
+// Do not define inline methods for the test case classes. Doing so
+// significantly increases the memory requirements of GNU G++ during
+// compilation.
+
+#define ATF_TEST_CASE_WITHOUT_HEAD(name) \
+ namespace { \
+ class atfu_tc_ ## name : public atf::tests::tc { \
+ void body(void) const; \
+ public: \
+ atfu_tc_ ## name(void); \
+ }; \
+ static atfu_tc_ ## name* atfu_tcptr_ ## name; \
+ atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, false) {} \
+ }
+
+#define ATF_TEST_CASE(name) \
+ namespace { \
+ class atfu_tc_ ## name : public atf::tests::tc { \
+ void head(void); \
+ void body(void) const; \
+ public: \
+ atfu_tc_ ## name(void); \
+ }; \
+ static atfu_tc_ ## name* atfu_tcptr_ ## name; \
+ atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, false) {} \
+ }
+
+#define ATF_TEST_CASE_WITH_CLEANUP(name) \
+ namespace { \
+ class atfu_tc_ ## name : public atf::tests::tc { \
+ void head(void); \
+ void body(void) const; \
+ void cleanup(void) const; \
+ public: \
+ atfu_tc_ ## name(void); \
+ }; \
+ static atfu_tc_ ## name* atfu_tcptr_ ## name; \
+ atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, true) {} \
+ }
+
+#define ATF_TEST_CASE_NAME(name) atfu_tc_ ## name
+#define ATF_TEST_CASE_USE(name) (atfu_tcptr_ ## name) = NULL
+
+#define ATF_TEST_CASE_HEAD(name) \
+ void \
+ atfu_tc_ ## name::head(void)
+
+#define ATF_TEST_CASE_BODY(name) \
+ void \
+ atfu_tc_ ## name::body(void) \
+ const
+
+#define ATF_TEST_CASE_CLEANUP(name) \
+ void \
+ atfu_tc_ ## name::cleanup(void) \
+ const
+
+#define ATF_FAIL(reason) atf::tests::tc::fail(reason)
+
+#define ATF_SKIP(reason) atf::tests::tc::skip(reason)
+
+#define ATF_PASS() atf::tests::tc::pass()
+
+#define ATF_REQUIRE(x) \
+ do { \
+ if (!(x)) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " << #x << " not met"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } while (false)
+
+#define ATF_REQUIRE_EQ(x, y) \
+ do { \
+ if ((x) != (y)) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " << #x << " != " << #y \
+ << " (" << (x) << " != " << (y) << ")"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } while (false)
+
+#define ATF_REQUIRE_IN(element, collection) \
+ ATF_REQUIRE((collection).find(element) != (collection).end())
+
+#define ATF_REQUIRE_NOT_IN(element, collection) \
+ ATF_REQUIRE((collection).find(element) == (collection).end())
+
+#define ATF_REQUIRE_MATCH(regexp, string) \
+ do { \
+ if (!atf::tests::detail::match(regexp, string)) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": '" << string << "' does not " \
+ << "match regexp '" << regexp << "'"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } while (false)
+
+#define ATF_REQUIRE_THROW(e, x) \
+ do { \
+ try { \
+ x; \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " did not throw " \
+ #e " as expected"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } catch (const e&) { \
+ } catch (const std::exception& atfu_e) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
+ "unexpected error (not " #e "): " << atfu_e.what(); \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } catch (...) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
+ "unexpected error (not " #e ")"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } while (false)
+
+#define ATF_REQUIRE_THROW_RE(type, regexp, x) \
+ do { \
+ try { \
+ x; \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " did not throw " \
+ #type " as expected"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } catch (const type& e) { \
+ if (!atf::tests::detail::match(regexp, e.what())) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " threw " #type "(" \
+ << e.what() << "), but does not match '" << regexp \
+ << "'"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } catch (const std::exception& atfu_e) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
+ "unexpected error (not " #type "): " << atfu_e.what(); \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } catch (...) { \
+ std::ostringstream atfu_ss; \
+ atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
+ "unexpected error (not " #type ")"; \
+ atf::tests::tc::fail(atfu_ss.str()); \
+ } \
+ } while (false)
+
+#define ATF_CHECK_ERRNO(exp_errno, bool_expr) \
+ atf::tests::tc::check_errno(__FILE__, __LINE__, exp_errno, #bool_expr, \
+ bool_expr)
+
+#define ATF_REQUIRE_ERRNO(exp_errno, bool_expr) \
+ atf::tests::tc::require_errno(__FILE__, __LINE__, exp_errno, #bool_expr, \
+ bool_expr)
+
+#define ATF_INIT_TEST_CASES(tcs) \
+ namespace atf { \
+ namespace tests { \
+ int run_tp(int, char* const*, \
+ void (*)(std::vector< atf::tests::tc * >&)); \
+ } \
+ } \
+ \
+ static void atfu_init_tcs(std::vector< atf::tests::tc * >&); \
+ \
+ int \
+ main(int argc, char* const* argv) \
+ { \
+ return atf::tests::run_tp(argc, argv, atfu_init_tcs); \
+ } \
+ \
+ static \
+ void \
+ atfu_init_tcs(std::vector< atf::tests::tc * >& tcs)
+
+#define ATF_ADD_TEST_CASE(tcs, tcname) \
+ do { \
+ atfu_tcptr_ ## tcname = new atfu_tc_ ## tcname(); \
+ (tcs).push_back(atfu_tcptr_ ## tcname); \
+ } while (0);
+
+#endif // !defined(_ATF_CXX_MACROS_HPP_)
diff --git a/contrib/atf/atf-c++/macros_hpp_test.cpp b/contrib/atf/atf-c++/macros_hpp_test.cpp
new file mode 100644
index 0000000..2cb7536
--- /dev/null
+++ b/contrib/atf/atf-c++/macros_hpp_test.cpp
@@ -0,0 +1,130 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2008 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 <stdexcept>
+
+#include <atf-c++/macros.hpp>
+
+void
+atf_check_errno_semicolons(void)
+{
+ // Check that ATF_CHECK_ERRNO does not contain a semicolon that would
+ // cause an empty-statement that confuses some compilers.
+ ATF_CHECK_ERRNO(1, 1 == 1);
+ ATF_CHECK_ERRNO(2, 2 == 2);
+}
+
+void
+atf_require_inside_if(void)
+{
+ // Make sure that ATF_REQUIRE can be used inside an if statement that
+ // does not have braces. Earlier versions of it generated an error
+ // if there was an else clause because they confused the compiler
+ // by defining an unprotected nested if.
+ if (true)
+ ATF_REQUIRE(true);
+ else
+ ATF_REQUIRE(true);
+}
+
+void
+atf_require_eq_inside_if(void)
+{
+ // Make sure that ATF_REQUIRE_EQ can be used inside an if statement
+ // that does not have braces. Earlier versions of it generated an
+ // error if there was an else clause because they confused the
+ // compiler by defining an unprotected nested if.
+ if (true)
+ ATF_REQUIRE_EQ(true, true);
+ else
+ ATF_REQUIRE_EQ(true, true);
+}
+
+void
+atf_require_throw_runtime_error(void)
+{
+ // Check that we can pass std::runtime_error to ATF_REQUIRE_THROW.
+ // Earlier versions generated a warning because the macro's code also
+ // attempted to capture this exception, and thus we had a duplicate
+ // catch clause.
+ ATF_REQUIRE_THROW(std::runtime_error, (void)0);
+}
+
+void
+atf_require_throw_inside_if(void)
+{
+ // Make sure that ATF_REQUIRE_THROW can be used inside an if statement
+ // that does not have braces. Earlier versions of it generated an
+ // error because a trailing ; after a catch block was not allowed.
+ if (true)
+ ATF_REQUIRE_THROW(std::runtime_error, (void)0);
+ else
+ ATF_REQUIRE_THROW(std::runtime_error, (void)1);
+}
+
+void
+atf_require_errno_semicolons(void)
+{
+ // Check that ATF_REQUIRE_ERRNO does not contain a semicolon that would
+ // cause an empty-statement that confuses some compilers.
+ ATF_REQUIRE_ERRNO(1, 1 == 1);
+ ATF_REQUIRE_ERRNO(2, 2 == 2);
+}
+
+// Test case names should not be expanded during instatiation so that they
+// can have the exact same name as macros.
+#define TEST_MACRO_1 invalid + name
+#define TEST_MACRO_2 invalid + name
+#define TEST_MACRO_3 invalid + name
+ATF_TEST_CASE(TEST_MACRO_1);
+ATF_TEST_CASE_HEAD(TEST_MACRO_1) { }
+ATF_TEST_CASE_BODY(TEST_MACRO_1) { }
+void instantiate_1(void) {
+ ATF_TEST_CASE_USE(TEST_MACRO_1);
+ atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_1)();
+ delete the_test;
+}
+ATF_TEST_CASE_WITH_CLEANUP(TEST_MACRO_2);
+ATF_TEST_CASE_HEAD(TEST_MACRO_2) { }
+ATF_TEST_CASE_BODY(TEST_MACRO_2) { }
+ATF_TEST_CASE_CLEANUP(TEST_MACRO_2) { }
+void instatiate_2(void) {
+ ATF_TEST_CASE_USE(TEST_MACRO_2);
+ atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_2)();
+ delete the_test;
+}
+ATF_TEST_CASE_WITH_CLEANUP(TEST_MACRO_3);
+ATF_TEST_CASE_HEAD(TEST_MACRO_3) { }
+ATF_TEST_CASE_BODY(TEST_MACRO_3) { }
+ATF_TEST_CASE_CLEANUP(TEST_MACRO_3) { }
+void instatiate_3(void) {
+ ATF_TEST_CASE_USE(TEST_MACRO_3);
+ atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_3)();
+ delete the_test;
+}
diff --git a/contrib/atf/atf-c++/macros_test.cpp b/contrib/atf/atf-c++/macros_test.cpp
new file mode 100644
index 0000000..57e19e0
--- /dev/null
+++ b/contrib/atf/atf-c++/macros_test.cpp
@@ -0,0 +1,793 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2008 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.
+//
+
+extern "C" {
+#include <fcntl.h>
+#include <unistd.h>
+}
+
+#include <cerrno>
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include "macros.hpp"
+
+#include "detail/fs.hpp"
+#include "detail/process.hpp"
+#include "detail/sanity.hpp"
+#include "detail/test_helpers.hpp"
+#include "detail/text.hpp"
+
+// ------------------------------------------------------------------------
+// Auxiliary functions.
+// ------------------------------------------------------------------------
+
+static
+void
+create_ctl_file(const char *name)
+{
+ ATF_REQUIRE(open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644) != -1);
+}
+
+// ------------------------------------------------------------------------
+// Auxiliary test cases.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(h_pass);
+ATF_TEST_CASE_HEAD(h_pass)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_pass)
+{
+ create_ctl_file("before");
+ ATF_PASS();
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_fail);
+ATF_TEST_CASE_HEAD(h_fail)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_fail)
+{
+ create_ctl_file("before");
+ ATF_FAIL("Failed on purpose");
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_skip);
+ATF_TEST_CASE_HEAD(h_skip)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_skip)
+{
+ create_ctl_file("before");
+ ATF_SKIP("Skipped on purpose");
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require);
+ATF_TEST_CASE_HEAD(h_require)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require)
+{
+ bool condition = atf::text::to_bool(get_config_var("condition"));
+
+ create_ctl_file("before");
+ ATF_REQUIRE(condition);
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_eq);
+ATF_TEST_CASE_HEAD(h_require_eq)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_eq)
+{
+ long v1 = atf::text::to_type< long >(get_config_var("v1"));
+ long v2 = atf::text::to_type< long >(get_config_var("v2"));
+
+ create_ctl_file("before");
+ ATF_REQUIRE_EQ(v1, v2);
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_in);
+ATF_TEST_CASE_HEAD(h_require_in)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_in)
+{
+ const std::string element = get_config_var("value");
+
+ std::set< std::string > collection;
+ collection.insert("foo");
+ collection.insert("bar");
+ collection.insert("baz");
+
+ create_ctl_file("before");
+ ATF_REQUIRE_IN(element, collection);
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_match);
+ATF_TEST_CASE_HEAD(h_require_match)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_match)
+{
+ const std::string regexp = get_config_var("regexp");
+ const std::string string = get_config_var("string");
+
+ create_ctl_file("before");
+ ATF_REQUIRE_MATCH(regexp, string);
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_not_in);
+ATF_TEST_CASE_HEAD(h_require_not_in)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_not_in)
+{
+ const std::string element = get_config_var("value");
+
+ std::set< std::string > collection;
+ collection.insert("foo");
+ collection.insert("bar");
+ collection.insert("baz");
+
+ create_ctl_file("before");
+ ATF_REQUIRE_NOT_IN(element, collection);
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_throw);
+ATF_TEST_CASE_HEAD(h_require_throw)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_throw)
+{
+ create_ctl_file("before");
+
+ if (get_config_var("what") == "throw_int")
+ ATF_REQUIRE_THROW(std::runtime_error, if (1) throw int(5));
+ else if (get_config_var("what") == "throw_rt")
+ ATF_REQUIRE_THROW(std::runtime_error,
+ if (1) throw std::runtime_error("e"));
+ else if (get_config_var("what") == "no_throw_rt")
+ ATF_REQUIRE_THROW(std::runtime_error,
+ if (0) throw std::runtime_error("e"));
+
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_throw_re);
+ATF_TEST_CASE_HEAD(h_require_throw_re)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_throw_re)
+{
+ create_ctl_file("before");
+
+ if (get_config_var("what") == "throw_int")
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "5", if (1) throw int(5));
+ else if (get_config_var("what") == "throw_rt_match")
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "foo.*baz",
+ if (1) throw std::runtime_error("a foo bar baz"));
+ else if (get_config_var("what") == "throw_rt_no_match")
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "foo.*baz",
+ if (1) throw std::runtime_error("baz foo bar a"));
+ else if (get_config_var("what") == "no_throw_rt")
+ ATF_REQUIRE_THROW_RE(std::runtime_error, "e",
+ if (0) throw std::runtime_error("e"));
+
+ create_ctl_file("after");
+}
+
+static int
+errno_fail_stub(const int raised_errno)
+{
+ errno = raised_errno;
+ return -1;
+}
+
+static int
+errno_ok_stub(void)
+{
+ return 0;
+}
+
+ATF_TEST_CASE(h_check_errno);
+ATF_TEST_CASE_HEAD(h_check_errno)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_check_errno)
+{
+ create_ctl_file("before");
+
+ if (get_config_var("what") == "no_error")
+ ATF_CHECK_ERRNO(-1, errno_ok_stub() == -1);
+ else if (get_config_var("what") == "errno_ok")
+ ATF_CHECK_ERRNO(2, errno_fail_stub(2) == -1);
+ else if (get_config_var("what") == "errno_fail")
+ ATF_CHECK_ERRNO(3, errno_fail_stub(4) == -1);
+ else
+ UNREACHABLE;
+
+ create_ctl_file("after");
+}
+
+ATF_TEST_CASE(h_require_errno);
+ATF_TEST_CASE_HEAD(h_require_errno)
+{
+ set_md_var("descr", "Helper test case");
+}
+ATF_TEST_CASE_BODY(h_require_errno)
+{
+ create_ctl_file("before");
+
+ if (get_config_var("what") == "no_error")
+ ATF_REQUIRE_ERRNO(-1, errno_ok_stub() == -1);
+ else if (get_config_var("what") == "errno_ok")
+ ATF_REQUIRE_ERRNO(2, errno_fail_stub(2) == -1);
+ else if (get_config_var("what") == "errno_fail")
+ ATF_REQUIRE_ERRNO(3, errno_fail_stub(4) == -1);
+ else
+ UNREACHABLE;
+
+ create_ctl_file("after");
+}
+
+// ------------------------------------------------------------------------
+// Test cases for the macros.
+// ------------------------------------------------------------------------
+
+ATF_TEST_CASE(pass);
+ATF_TEST_CASE_HEAD(pass)
+{
+ set_md_var("descr", "Tests the ATF_PASS macro");
+}
+ATF_TEST_CASE_BODY(pass)
+{
+ ATF_TEST_CASE_USE(h_pass);
+ run_h_tc< ATF_TEST_CASE_NAME(h_pass) >();
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
+ ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
+}
+
+ATF_TEST_CASE(fail);
+ATF_TEST_CASE_HEAD(fail)
+{
+ set_md_var("descr", "Tests the ATF_FAIL macro");
+}
+ATF_TEST_CASE_BODY(fail)
+{
+ ATF_TEST_CASE_USE(h_fail);
+ run_h_tc< ATF_TEST_CASE_NAME(h_fail) >();
+ ATF_REQUIRE(grep_file("result", "^failed: Failed on purpose"));
+ ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
+ ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
+}
+
+ATF_TEST_CASE(skip);
+ATF_TEST_CASE_HEAD(skip)
+{
+ set_md_var("descr", "Tests the ATF_SKIP macro");
+}
+ATF_TEST_CASE_BODY(skip)
+{
+ ATF_TEST_CASE_USE(h_skip);
+ run_h_tc< ATF_TEST_CASE_NAME(h_skip) >();
+ ATF_REQUIRE(grep_file("result", "^skipped: Skipped on purpose"));
+ ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
+ ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
+}
+
+ATF_TEST_CASE(require);
+ATF_TEST_CASE_HEAD(require)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE macro");
+}
+ATF_TEST_CASE_BODY(require)
+{
+ struct test {
+ const char *cond;
+ bool ok;
+ } *t, tests[] = {
+ { "false", false },
+ { "true", true },
+ { NULL, false }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->cond != NULL; t++) {
+ atf::tests::vars_map config;
+ config["condition"] = t->cond;
+
+ std::cout << "Checking with a " << t->cond << " value\n";
+
+ ATF_TEST_CASE_USE(h_require);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed: .*condition not met"));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_eq);
+ATF_TEST_CASE_HEAD(require_eq)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_EQ macro");
+}
+ATF_TEST_CASE_BODY(require_eq)
+{
+ struct test {
+ const char *v1;
+ const char *v2;
+ bool ok;
+ } *t, tests[] = {
+ { "1", "1", true },
+ { "1", "2", false },
+ { "2", "1", false },
+ { "2", "2", true },
+ { NULL, NULL, false }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->v1 != NULL; t++) {
+ atf::tests::vars_map config;
+ config["v1"] = t->v1;
+ config["v2"] = t->v2;
+
+ std::cout << "Checking with " << t->v1 << ", " << t->v2
+ << " and expecting " << (t->ok ? "true" : "false")
+ << "\n";
+
+ ATF_TEST_CASE_USE(h_require_eq);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_eq) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed: .*v1 != v2"));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_in);
+ATF_TEST_CASE_HEAD(require_in)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_IN macro");
+}
+ATF_TEST_CASE_BODY(require_in)
+{
+ struct test {
+ const char *value;
+ bool ok;
+ } *t, tests[] = {
+ { "foo", true },
+ { "bar", true },
+ { "baz", true },
+ { "xxx", false },
+ { "fooa", false },
+ { "foo ", false },
+ { NULL, false }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->value != NULL; t++) {
+ atf::tests::vars_map config;
+ config["value"] = t->value;
+
+ ATF_TEST_CASE_USE(h_require_in);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_in) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed: "));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_match);
+ATF_TEST_CASE_HEAD(require_match)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_MATCH macro");
+}
+ATF_TEST_CASE_BODY(require_match)
+{
+ struct test {
+ const char *regexp;
+ const char *string;
+ bool ok;
+ } *t, tests[] = {
+ { "foo.*bar", "this is a foo, bar, baz", true },
+ { "bar.*baz", "this is a baz, bar, foo", false },
+ { NULL, NULL, false }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->regexp != NULL; t++) {
+ atf::tests::vars_map config;
+ config["regexp"] = t->regexp;
+ config["string"] = t->string;
+
+ std::cout << "Checking with " << t->regexp << ", " << t->string
+ << " and expecting " << (t->ok ? "true" : "false")
+ << "\n";
+
+ ATF_TEST_CASE_USE(h_require_match);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_match) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed: "));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_not_in);
+ATF_TEST_CASE_HEAD(require_not_in)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_NOT_IN macro");
+}
+ATF_TEST_CASE_BODY(require_not_in)
+{
+ struct test {
+ const char *value;
+ bool ok;
+ } *t, tests[] = {
+ { "foo", false },
+ { "bar", false },
+ { "baz", false },
+ { "xxx", true },
+ { "fooa", true },
+ { "foo ", true },
+ { NULL, false }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->value != NULL; t++) {
+ atf::tests::vars_map config;
+ config["value"] = t->value;
+
+ ATF_TEST_CASE_USE(h_require_not_in);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_not_in) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed: "));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_throw);
+ATF_TEST_CASE_HEAD(require_throw)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_THROW macro");
+}
+ATF_TEST_CASE_BODY(require_throw)
+{
+ struct test {
+ const char *what;
+ bool ok;
+ const char *msg;
+ } *t, tests[] = {
+ { "throw_int", false, "unexpected error" },
+ { "throw_rt", true, NULL },
+ { "no_throw_rt", false, "did not throw" },
+ { NULL, false, NULL }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->what != NULL; t++) {
+ atf::tests::vars_map config;
+ config["what"] = t->what;
+
+ std::cout << "Checking with " << t->what << " and expecting "
+ << (t->ok ? "true" : "false") << "\n";
+
+ ATF_TEST_CASE_USE(h_require_throw);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_throw) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ std::cout << "Checking that message contains '" << t->msg
+ << "'\n";
+ std::string exp_result = std::string("^failed: .*") + t->msg;
+ ATF_REQUIRE(grep_file("result", exp_result.c_str()));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_throw_re);
+ATF_TEST_CASE_HEAD(require_throw_re)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_THROW_RE macro");
+}
+ATF_TEST_CASE_BODY(require_throw_re)
+{
+ struct test {
+ const char *what;
+ bool ok;
+ const char *msg;
+ } *t, tests[] = {
+ { "throw_int", false, "unexpected error" },
+ { "throw_rt_match", true, NULL },
+ { "throw_rt_no_match", false,
+ "threw.*runtime_error\\(baz foo bar a\\).*"
+ "does not match 'foo\\.\\*baz'" },
+ { "no_throw_rt", false, "did not throw" },
+ { NULL, false, NULL }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->what != NULL; t++) {
+ atf::tests::vars_map config;
+ config["what"] = t->what;
+
+ std::cout << "Checking with " << t->what << " and expecting "
+ << (t->ok ? "true" : "false") << "\n";
+
+ ATF_TEST_CASE_USE(h_require_throw_re);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_throw_re) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ std::cout << "Checking that message contains '" << t->msg
+ << "'\n";
+ std::string exp_result = std::string("^failed: .*") + t->msg;
+ ATF_REQUIRE(grep_file("result", exp_result.c_str()));
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(check_errno);
+ATF_TEST_CASE_HEAD(check_errno)
+{
+ set_md_var("descr", "Tests the ATF_CHECK_ERRNO macro");
+}
+ATF_TEST_CASE_BODY(check_errno)
+{
+ struct test {
+ const char *what;
+ bool ok;
+ const char *msg;
+ } *t, tests[] = {
+ { "no_error", false,
+ "Expected true value in errno_ok_stub\\(\\) == -1" },
+ { "errno_ok", true, NULL },
+ { "errno_fail", false,
+ "Expected errno 3, got 4, in errno_fail_stub\\(4\\) == -1" },
+ { NULL, false, NULL }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->what != NULL; t++) {
+ atf::tests::vars_map config;
+ config["what"] = t->what;
+
+ ATF_TEST_CASE_USE(h_check_errno);
+ run_h_tc< ATF_TEST_CASE_NAME(h_check_errno) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ ATF_REQUIRE(atf::fs::exists(after));
+
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ } else {
+ ATF_REQUIRE(grep_file("result", "^failed"));
+
+ std::string exp_result = "macros_test.cpp:[0-9]+: " +
+ std::string(t->msg) + "$";
+ ATF_REQUIRE(grep_file("stderr", exp_result.c_str()));
+ }
+
+ atf::fs::remove(before);
+ atf::fs::remove(after);
+ }
+}
+
+ATF_TEST_CASE(require_errno);
+ATF_TEST_CASE_HEAD(require_errno)
+{
+ set_md_var("descr", "Tests the ATF_REQUIRE_ERRNO macro");
+}
+ATF_TEST_CASE_BODY(require_errno)
+{
+ struct test {
+ const char *what;
+ bool ok;
+ const char *msg;
+ } *t, tests[] = {
+ { "no_error", false,
+ "Expected true value in errno_ok_stub\\(\\) == -1" },
+ { "errno_ok", true, NULL },
+ { "errno_fail", false,
+ "Expected errno 3, got 4, in errno_fail_stub\\(4\\) == -1" },
+ { NULL, false, NULL }
+ };
+
+ const atf::fs::path before("before");
+ const atf::fs::path after("after");
+
+ for (t = &tests[0]; t->what != NULL; t++) {
+ atf::tests::vars_map config;
+ config["what"] = t->what;
+
+ ATF_TEST_CASE_USE(h_require_errno);
+ run_h_tc< ATF_TEST_CASE_NAME(h_require_errno) >(config);
+
+ ATF_REQUIRE(atf::fs::exists(before));
+ if (t->ok) {
+ ATF_REQUIRE(grep_file("result", "^passed"));
+ ATF_REQUIRE(atf::fs::exists(after));
+ } else {
+ std::string exp_result = "^failed: .*macros_test.cpp:[0-9]+: " +
+ std::string(t->msg) + "$";
+ ATF_REQUIRE(grep_file("result", exp_result.c_str()));
+
+ ATF_REQUIRE(!atf::fs::exists(after));
+ }
+
+ atf::fs::remove(before);
+ if (t->ok)
+ atf::fs::remove(after);
+ }
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/macros.hpp");
+BUILD_TC(use, "macros_hpp_test.cpp",
+ "Tests that the macros provided by the atf-c++/macros.hpp file "
+ "do not cause syntax errors when used",
+ "Build of macros_hpp_test.cpp failed; some macros in "
+ "atf-c++/macros.hpp are broken");
+BUILD_TC_FAIL(detect_unused_tests, "unused_test.cpp",
+ "Tests that defining an unused test case raises a warning (and thus "
+ "an error)",
+ "Build of unused_test.cpp passed; unused test cases are not properly "
+ "detected");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test cases for the macros.
+ ATF_ADD_TEST_CASE(tcs, pass);
+ ATF_ADD_TEST_CASE(tcs, fail);
+ ATF_ADD_TEST_CASE(tcs, skip);
+ ATF_ADD_TEST_CASE(tcs, check_errno);
+ ATF_ADD_TEST_CASE(tcs, require);
+ ATF_ADD_TEST_CASE(tcs, require_eq);
+ ATF_ADD_TEST_CASE(tcs, require_in);
+ ATF_ADD_TEST_CASE(tcs, require_match);
+ ATF_ADD_TEST_CASE(tcs, require_not_in);
+ ATF_ADD_TEST_CASE(tcs, require_throw);
+ ATF_ADD_TEST_CASE(tcs, require_throw_re);
+ ATF_ADD_TEST_CASE(tcs, require_errno);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+ ATF_ADD_TEST_CASE(tcs, use);
+ ATF_ADD_TEST_CASE(tcs, detect_unused_tests);
+}
diff --git a/contrib/atf/atf-c++/pkg_config_test.sh b/contrib/atf/atf-c++/pkg_config_test.sh
new file mode 100644
index 0000000..8409902
--- /dev/null
+++ b/contrib/atf/atf-c++/pkg_config_test.sh
@@ -0,0 +1,149 @@
+#
+# Automated Testing Framework (atf)
+#
+# Copyright (c) 2008 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.
+#
+
+# The following tests assume that the atfc++.pc file is installed in a
+# directory that is known by pkg-config. Otherwise they will fail,
+# and you will be required to adjust PKG_CONFIG_PATH accordingly.
+#
+# It would be possible to bypass this requirement by setting the path
+# explicitly during the tests, but then this would not do a real check
+# to ensure that the installation is working.
+
+require_pc()
+{
+ pkg-config ${1} || atf_fail "pkg-config could not locate ${1}.pc;" \
+ "maybe need to set PKG_CONFIG_PATH?"
+}
+
+check_version()
+{
+ atf_check -s eq:0 -o save:stdout -e empty -x \
+ "atf-version | head -n 1 | cut -d ' ' -f 4"
+ ver1=$(cat stdout)
+ echo "Version reported by atf-version: ${ver1}"
+
+ atf_check -s eq:0 -o save:stdout -e empty pkg-config --modversion "${1}"
+ ver2=$(cat stdout)
+ echo "Version reported by pkg-config: ${ver2}"
+
+ atf_check_equal ${ver1} ${ver2}
+}
+
+atf_test_case version
+version_head()
+{
+ atf_set "descr" "Checks that the version in atf-c++ is correct"
+ atf_set "require.progs" "pkg-config"
+}
+version_body()
+{
+ require_pc "atf-c++"
+
+ check_version "atf-c++"
+}
+
+atf_test_case build
+build_head()
+{
+ atf_set "descr" "Checks that a test program can be built against" \
+ "the C++ library based on the pkg-config information"
+ atf_set "require.progs" "pkg-config"
+}
+build_body()
+{
+ require_pc "atf-c++"
+
+ atf_check -s eq:0 -o save:stdout -e empty \
+ pkg-config --variable=cxx atf-c++
+ cxx=$(cat stdout)
+ echo "Compiler is: ${cxx}"
+ atf_require_prog ${cxx}
+
+ cat >tp.cpp <<EOF
+#include <iostream>
+
+#include <atf-c++.hpp>
+
+ATF_TEST_CASE(tc);
+ATF_TEST_CASE_HEAD(tc) {
+ set_md_var("descr", "A test case");
+}
+ATF_TEST_CASE_BODY(tc) {
+ std::cout << "Running\n";
+}
+
+ATF_INIT_TEST_CASES(tcs) {
+ ATF_ADD_TEST_CASE(tcs, tc);
+}
+EOF
+
+ atf_check -s eq:0 -o save:stdout -e empty pkg-config --cflags atf-c++
+ cxxflags=$(cat stdout)
+ echo "CXXFLAGS are: ${cxxflags}"
+
+ atf_check -s eq:0 -o save:stdout -e empty \
+ pkg-config --libs-only-L --libs-only-other atf-c++
+ ldflags=$(cat stdout)
+ atf_check -s eq:0 -o save:stdout -e empty \
+ pkg-config --libs-only-l atf-c++
+ libs=$(cat stdout)
+ echo "LDFLAGS are: ${ldflags}"
+ echo "LIBS are: ${libs}"
+
+ atf_check -s eq:0 -o empty -e empty ${cxx} ${cxxflags} -o tp.o -c tp.cpp
+ atf_check -s eq:0 -o empty -e empty ${cxx} ${ldflags} -o tp tp.o ${libs}
+
+ libpath=
+ for f in ${ldflags}; do
+ case ${f} in
+ -L*)
+ dir=$(echo ${f} | sed -e 's,^-L,,')
+ if [ -z "${libpath}" ]; then
+ libpath="${dir}"
+ else
+ libpath="${libpath}:${dir}"
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ atf_check -s eq:0 -o empty -e empty test -x tp
+ atf_check -s eq:0 -o match:'Running' -e empty -x \
+ "LD_LIBRARY_PATH=${libpath} ./tp tc"
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case version
+ atf_add_test_case build
+}
+
+# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
diff --git a/contrib/atf/atf-c++/tests.cpp b/contrib/atf/atf-c++/tests.cpp
new file mode 100644
index 0000000..cdc0dfb
--- /dev/null
+++ b/contrib/atf/atf-c++/tests.cpp
@@ -0,0 +1,710 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+}
+
+#include <algorithm>
+#include <cctype>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+
+extern "C" {
+#include "atf-c/error.h"
+#include "atf-c/tc.h"
+#include "atf-c/utils.h"
+}
+
+#include "tests.hpp"
+
+#include "detail/application.hpp"
+#include "detail/env.hpp"
+#include "detail/exceptions.hpp"
+#include "detail/fs.hpp"
+#include "detail/parser.hpp"
+#include "detail/sanity.hpp"
+#include "detail/text.hpp"
+
+namespace impl = atf::tests;
+namespace detail = atf::tests::detail;
+#define IMPL_NAME "atf::tests"
+
+// ------------------------------------------------------------------------
+// The "atf_tp_writer" class.
+// ------------------------------------------------------------------------
+
+detail::atf_tp_writer::atf_tp_writer(std::ostream& os) :
+ m_os(os),
+ m_is_first(true)
+{
+ atf::parser::headers_map hm;
+ atf::parser::attrs_map ct_attrs;
+ ct_attrs["version"] = "1";
+ hm["Content-Type"] = atf::parser::header_entry("Content-Type",
+ "application/X-atf-tp", ct_attrs);
+ atf::parser::write_headers(hm, m_os);
+}
+
+void
+detail::atf_tp_writer::start_tc(const std::string& ident)
+{
+ if (!m_is_first)
+ m_os << "\n";
+ m_os << "ident: " << ident << "\n";
+ m_os.flush();
+}
+
+void
+detail::atf_tp_writer::end_tc(void)
+{
+ if (m_is_first)
+ m_is_first = false;
+}
+
+void
+detail::atf_tp_writer::tc_meta_data(const std::string& name,
+ const std::string& value)
+{
+ PRE(name != "ident");
+ m_os << name << ": " << value << "\n";
+ m_os.flush();
+}
+
+// ------------------------------------------------------------------------
+// Free helper functions.
+// ------------------------------------------------------------------------
+
+bool
+detail::match(const std::string& regexp, const std::string& str)
+{
+ return atf::text::match(str, regexp);
+}
+
+// ------------------------------------------------------------------------
+// The "tc" class.
+// ------------------------------------------------------------------------
+
+static std::map< atf_tc_t*, impl::tc* > wraps;
+static std::map< const atf_tc_t*, const impl::tc* > cwraps;
+
+struct impl::tc_impl : atf::utils::noncopyable {
+ std::string m_ident;
+ atf_tc_t m_tc;
+ bool m_has_cleanup;
+
+ tc_impl(const std::string& ident, const bool has_cleanup) :
+ m_ident(ident),
+ m_has_cleanup(has_cleanup)
+ {
+ }
+
+ static void
+ wrap_head(atf_tc_t *tc)
+ {
+ std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc);
+ INV(iter != wraps.end());
+ (*iter).second->head();
+ }
+
+ static void
+ wrap_body(const atf_tc_t *tc)
+ {
+ std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
+ cwraps.find(tc);
+ INV(iter != cwraps.end());
+ try {
+ (*iter).second->body();
+ } catch (const std::exception& e) {
+ (*iter).second->fail("Caught unhandled exception: " + std::string(
+ e.what()));
+ } catch (...) {
+ (*iter).second->fail("Caught unknown exception");
+ }
+ }
+
+ static void
+ wrap_cleanup(const atf_tc_t *tc)
+ {
+ std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
+ cwraps.find(tc);
+ INV(iter != cwraps.end());
+ (*iter).second->cleanup();
+ }
+};
+
+impl::tc::tc(const std::string& ident, const bool has_cleanup) :
+ pimpl(new tc_impl(ident, has_cleanup))
+{
+}
+
+impl::tc::~tc(void)
+{
+ cwraps.erase(&pimpl->m_tc);
+ wraps.erase(&pimpl->m_tc);
+
+ atf_tc_fini(&pimpl->m_tc);
+}
+
+void
+impl::tc::init(const vars_map& config)
+{
+ atf_error_t err;
+
+ utils::auto_array< const char * > array(
+ new const char*[(config.size() * 2) + 1]);
+ const char **ptr = array.get();
+ for (vars_map::const_iterator iter = config.begin();
+ iter != config.end(); iter++) {
+ *ptr = (*iter).first.c_str();
+ *(ptr + 1) = (*iter).second.c_str();
+ ptr += 2;
+ }
+ *ptr = NULL;
+
+ wraps[&pimpl->m_tc] = this;
+ cwraps[&pimpl->m_tc] = this;
+
+ err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head,
+ pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL,
+ array.get());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+bool
+impl::tc::has_config_var(const std::string& var)
+ const
+{
+ return atf_tc_has_config_var(&pimpl->m_tc, var.c_str());
+}
+
+bool
+impl::tc::has_md_var(const std::string& var)
+ const
+{
+ return atf_tc_has_md_var(&pimpl->m_tc, var.c_str());
+}
+
+const std::string
+impl::tc::get_config_var(const std::string& var)
+ const
+{
+ return atf_tc_get_config_var(&pimpl->m_tc, var.c_str());
+}
+
+const std::string
+impl::tc::get_config_var(const std::string& var, const std::string& defval)
+ const
+{
+ return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str());
+}
+
+const std::string
+impl::tc::get_md_var(const std::string& var)
+ const
+{
+ return atf_tc_get_md_var(&pimpl->m_tc, var.c_str());
+}
+
+const impl::vars_map
+impl::tc::get_md_vars(void)
+ const
+{
+ vars_map vars;
+
+ char **array = atf_tc_get_md_vars(&pimpl->m_tc);
+ try {
+ char **ptr;
+ for (ptr = array; *ptr != NULL; ptr += 2)
+ vars[*ptr] = *(ptr + 1);
+ } catch (...) {
+ atf_utils_free_charpp(array);
+ throw;
+ }
+
+ return vars;
+}
+
+void
+impl::tc::set_md_var(const std::string& var, const std::string& val)
+{
+ atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), val.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+void
+impl::tc::run(const std::string& resfile)
+ const
+{
+ atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str());
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+void
+impl::tc::run_cleanup(void)
+ const
+{
+ atf_error_t err = atf_tc_cleanup(&pimpl->m_tc);
+ if (atf_is_error(err))
+ throw_atf_error(err);
+}
+
+void
+impl::tc::head(void)
+{
+}
+
+void
+impl::tc::cleanup(void)
+ const
+{
+}
+
+void
+impl::tc::require_prog(const std::string& prog)
+ const
+{
+ atf_tc_require_prog(prog.c_str());
+}
+
+void
+impl::tc::pass(void)
+{
+ atf_tc_pass();
+}
+
+void
+impl::tc::fail(const std::string& reason)
+{
+ atf_tc_fail("%s", reason.c_str());
+}
+
+void
+impl::tc::fail_nonfatal(const std::string& reason)
+{
+ atf_tc_fail_nonfatal("%s", reason.c_str());
+}
+
+void
+impl::tc::skip(const std::string& reason)
+{
+ atf_tc_skip("%s", reason.c_str());
+}
+
+void
+impl::tc::check_errno(const char* file, const int line, const int exp_errno,
+ const char* expr_str, const bool result)
+{
+ atf_tc_check_errno(file, line, exp_errno, expr_str, result);
+}
+
+void
+impl::tc::require_errno(const char* file, const int line, const int exp_errno,
+ const char* expr_str, const bool result)
+{
+ atf_tc_require_errno(file, line, exp_errno, expr_str, result);
+}
+
+void
+impl::tc::expect_pass(void)
+{
+ atf_tc_expect_pass();
+}
+
+void
+impl::tc::expect_fail(const std::string& reason)
+{
+ atf_tc_expect_fail("%s", reason.c_str());
+}
+
+void
+impl::tc::expect_exit(const int exitcode, const std::string& reason)
+{
+ atf_tc_expect_exit(exitcode, "%s", reason.c_str());
+}
+
+void
+impl::tc::expect_signal(const int signo, const std::string& reason)
+{
+ atf_tc_expect_signal(signo, "%s", reason.c_str());
+}
+
+void
+impl::tc::expect_death(const std::string& reason)
+{
+ atf_tc_expect_death("%s", reason.c_str());
+}
+
+void
+impl::tc::expect_timeout(const std::string& reason)
+{
+ atf_tc_expect_timeout("%s", reason.c_str());
+}
+
+// ------------------------------------------------------------------------
+// The "tp" class.
+// ------------------------------------------------------------------------
+
+class tp : public atf::application::app {
+public:
+ typedef std::vector< impl::tc * > tc_vector;
+
+private:
+ static const char* m_description;
+
+ bool m_lflag;
+ atf::fs::path m_resfile;
+ std::string m_srcdir_arg;
+ atf::fs::path m_srcdir;
+
+ atf::tests::vars_map m_vars;
+
+ std::string specific_args(void) const;
+ options_set specific_options(void) const;
+ void process_option(int, const char*);
+
+ void (*m_add_tcs)(tc_vector&);
+ tc_vector m_tcs;
+
+ void parse_vflag(const std::string&);
+ void handle_srcdir(void);
+
+ tc_vector init_tcs(void);
+
+ enum tc_part {
+ BODY,
+ CLEANUP,
+ };
+
+ void list_tcs(void);
+ impl::tc* find_tc(tc_vector, const std::string&);
+ static std::pair< std::string, tc_part > process_tcarg(const std::string&);
+ int run_tc(const std::string&);
+
+public:
+ tp(void (*)(tc_vector&));
+ ~tp(void);
+
+ int main(void);
+};
+
+const char* tp::m_description =
+ "This is an independent atf test program.";
+
+tp::tp(void (*add_tcs)(tc_vector&)) :
+ app(m_description, "atf-test-program(1)", "atf(7)", false),
+ m_lflag(false),
+ m_resfile("/dev/stdout"),
+ m_srcdir("."),
+ m_add_tcs(add_tcs)
+{
+}
+
+tp::~tp(void)
+{
+ for (tc_vector::iterator iter = m_tcs.begin();
+ iter != m_tcs.end(); iter++) {
+ impl::tc* tc = *iter;
+
+ delete tc;
+ }
+}
+
+std::string
+tp::specific_args(void)
+ const
+{
+ return "test_case";
+}
+
+tp::options_set
+tp::specific_options(void)
+ const
+{
+ using atf::application::option;
+ options_set opts;
+ opts.insert(option('l', "", "List test cases and their purpose"));
+ opts.insert(option('r', "resfile", "The file to which the test program "
+ "will write the results of the "
+ "executed test case"));
+ opts.insert(option('s', "srcdir", "Directory where the test's data "
+ "files are located"));
+ opts.insert(option('v', "var=value", "Sets the configuration variable "
+ "`var' to `value'"));
+ return opts;
+}
+
+void
+tp::process_option(int ch, const char* arg)
+{
+ switch (ch) {
+ case 'l':
+ m_lflag = true;
+ break;
+
+ case 'r':
+ m_resfile = atf::fs::path(arg);
+ break;
+
+ case 's':
+ m_srcdir_arg = arg;
+ break;
+
+ case 'v':
+ parse_vflag(arg);
+ break;
+
+ default:
+ UNREACHABLE;
+ }
+}
+
+void
+tp::parse_vflag(const std::string& str)
+{
+ if (str.empty())
+ throw std::runtime_error("-v requires a non-empty argument");
+
+ std::vector< std::string > ws = atf::text::split(str, "=");
+ if (ws.size() == 1 && str[str.length() - 1] == '=') {
+ m_vars[ws[0]] = "";
+ } else {
+ if (ws.size() != 2)
+ throw std::runtime_error("-v requires an argument of the form "
+ "var=value");
+
+ m_vars[ws[0]] = ws[1];
+ }
+}
+
+void
+tp::handle_srcdir(void)
+{
+ if (m_srcdir_arg.empty()) {
+ m_srcdir = atf::fs::path(m_argv0).branch_path();
+ if (m_srcdir.leaf_name() == ".libs")
+ m_srcdir = m_srcdir.branch_path();
+ } else
+ m_srcdir = atf::fs::path(m_srcdir_arg);
+
+ if (!atf::fs::exists(m_srcdir / m_prog_name))
+ throw std::runtime_error("Cannot find the test program in the "
+ "source directory `" + m_srcdir.str() + "'");
+
+ if (!m_srcdir.is_absolute())
+ m_srcdir = m_srcdir.to_absolute();
+
+ m_vars["srcdir"] = m_srcdir.str();
+}
+
+tp::tc_vector
+tp::init_tcs(void)
+{
+ m_add_tcs(m_tcs);
+ for (tc_vector::iterator iter = m_tcs.begin();
+ iter != m_tcs.end(); iter++) {
+ impl::tc* tc = *iter;
+
+ tc->init(m_vars);
+ }
+ return m_tcs;
+}
+
+//
+// An auxiliary unary predicate that compares the given test case's
+// identifier to the identifier stored in it.
+//
+class tc_equal_to_ident {
+ const std::string& m_ident;
+
+public:
+ tc_equal_to_ident(const std::string& i) :
+ m_ident(i)
+ {
+ }
+
+ bool operator()(const impl::tc* tc)
+ {
+ return tc->get_md_var("ident") == m_ident;
+ }
+};
+
+void
+tp::list_tcs(void)
+{
+ tc_vector tcs = init_tcs();
+ detail::atf_tp_writer writer(std::cout);
+
+ for (tc_vector::const_iterator iter = tcs.begin();
+ iter != tcs.end(); iter++) {
+ const impl::vars_map vars = (*iter)->get_md_vars();
+
+ {
+ impl::vars_map::const_iterator iter2 = vars.find("ident");
+ INV(iter2 != vars.end());
+ writer.start_tc((*iter2).second);
+ }
+
+ for (impl::vars_map::const_iterator iter2 = vars.begin();
+ iter2 != vars.end(); iter2++) {
+ const std::string& key = (*iter2).first;
+ if (key != "ident")
+ writer.tc_meta_data(key, (*iter2).second);
+ }
+
+ writer.end_tc();
+ }
+}
+
+impl::tc*
+tp::find_tc(tc_vector tcs, const std::string& name)
+{
+ std::vector< std::string > ids;
+ for (tc_vector::iterator iter = tcs.begin();
+ iter != tcs.end(); iter++) {
+ impl::tc* tc = *iter;
+
+ if (tc->get_md_var("ident") == name)
+ return tc;
+ }
+ throw atf::application::usage_error("Unknown test case `%s'",
+ name.c_str());
+}
+
+std::pair< std::string, tp::tc_part >
+tp::process_tcarg(const std::string& tcarg)
+{
+ const std::string::size_type pos = tcarg.find(':');
+ if (pos == std::string::npos) {
+ return std::make_pair(tcarg, BODY);
+ } else {
+ const std::string tcname = tcarg.substr(0, pos);
+
+ const std::string partname = tcarg.substr(pos + 1);
+ if (partname == "body")
+ return std::make_pair(tcname, BODY);
+ else if (partname == "cleanup")
+ return std::make_pair(tcname, CLEANUP);
+ else {
+ using atf::application::usage_error;
+ throw usage_error("Invalid test case part `%s'", partname.c_str());
+ }
+ }
+}
+
+int
+tp::run_tc(const std::string& tcarg)
+{
+ const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
+
+ impl::tc* tc = find_tc(init_tcs(), fields.first);
+
+ if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
+ "__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
+ {
+ std::cerr << m_prog_name << ": WARNING: Running test cases without "
+ "atf-run(1) is unsupported\n";
+ std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
+ "control is being applied; you may get unexpected failures; see "
+ "atf-test-case(4)\n";
+ }
+
+ try {
+ switch (fields.second) {
+ case BODY:
+ tc->run(m_resfile.str());
+ break;
+ case CLEANUP:
+ tc->run_cleanup();
+ break;
+ default:
+ UNREACHABLE;
+ }
+ return EXIT_SUCCESS;
+ } catch (const std::runtime_error& e) {
+ std::cerr << "ERROR: " << e.what() << "\n";
+ return EXIT_FAILURE;
+ }
+}
+
+int
+tp::main(void)
+{
+ using atf::application::usage_error;
+
+ int errcode;
+
+ handle_srcdir();
+
+ if (m_lflag) {
+ if (m_argc > 0)
+ throw usage_error("Cannot provide test case names with -l");
+
+ list_tcs();
+ errcode = EXIT_SUCCESS;
+ } else {
+ if (m_argc == 0)
+ throw usage_error("Must provide a test case name");
+ else if (m_argc > 1)
+ throw usage_error("Cannot provide more than one test case name");
+ INV(m_argc == 1);
+
+ errcode = run_tc(m_argv[0]);
+ }
+
+ return errcode;
+}
+
+namespace atf {
+ namespace tests {
+ int run_tp(int, char* const*, void (*)(tp::tc_vector&));
+ }
+}
+
+int
+impl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
+{
+ return tp(add_tcs).run(argc, argv);
+}
diff --git a/contrib/atf/atf-c++/tests.hpp b/contrib/atf/atf-c++/tests.hpp
new file mode 100644
index 0000000..af75229
--- /dev/null
+++ b/contrib/atf/atf-c++/tests.hpp
@@ -0,0 +1,127 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_TESTS_HPP_)
+#define _ATF_CXX_TESTS_HPP_
+
+#include <map>
+#include <memory>
+#include <string>
+
+extern "C" {
+#include <atf-c/defs.h>
+}
+
+#include <atf-c++/utils.hpp>
+
+namespace atf {
+namespace tests {
+
+namespace detail {
+
+class atf_tp_writer {
+ std::ostream& m_os;
+
+ bool m_is_first;
+
+public:
+ atf_tp_writer(std::ostream&);
+
+ void start_tc(const std::string&);
+ void end_tc(void);
+ void tc_meta_data(const std::string&, const std::string&);
+};
+
+bool match(const std::string&, const std::string&);
+
+} // namespace
+
+// ------------------------------------------------------------------------
+// The "vars_map" class.
+// ------------------------------------------------------------------------
+
+typedef std::map< std::string, std::string > vars_map;
+
+// ------------------------------------------------------------------------
+// The "tc" class.
+// ------------------------------------------------------------------------
+
+struct tc_impl;
+
+class tc : utils::noncopyable {
+ std::auto_ptr< tc_impl > pimpl;
+
+protected:
+ virtual void head(void);
+ virtual void body(void) const = 0;
+ virtual void cleanup(void) const;
+
+ void require_prog(const std::string&) const;
+
+ friend struct tc_impl;
+
+public:
+ tc(const std::string&, const bool);
+ virtual ~tc(void);
+
+ void init(const vars_map&);
+
+ const std::string get_config_var(const std::string&) const;
+ const std::string get_config_var(const std::string&, const std::string&)
+ const;
+ const std::string get_md_var(const std::string&) const;
+ const vars_map get_md_vars(void) const;
+ bool has_config_var(const std::string&) const;
+ bool has_md_var(const std::string&) const;
+ void set_md_var(const std::string&, const std::string&);
+
+ void run(const std::string&) const;
+ void run_cleanup(void) const;
+
+ // To be called from the child process only.
+ static void pass(void) ATF_DEFS_ATTRIBUTE_NORETURN;
+ static void fail(const std::string&) ATF_DEFS_ATTRIBUTE_NORETURN;
+ static void fail_nonfatal(const std::string&);
+ static void skip(const std::string&) ATF_DEFS_ATTRIBUTE_NORETURN;
+ static void check_errno(const char*, const int, const int, const char*,
+ const bool);
+ static void require_errno(const char*, const int, const int, const char*,
+ const bool);
+ static void expect_pass(void);
+ static void expect_fail(const std::string&);
+ static void expect_exit(const int, const std::string&);
+ static void expect_signal(const int, const std::string&);
+ static void expect_death(const std::string&);
+ static void expect_timeout(const std::string&);
+};
+
+} // namespace tests
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_TESTS_HPP_)
diff --git a/contrib/atf/atf-c++/tests_test.cpp b/contrib/atf/atf-c++/tests_test.cpp
new file mode 100644
index 0000000..63ab2ef
--- /dev/null
+++ b/contrib/atf/atf-c++/tests_test.cpp
@@ -0,0 +1,201 @@
+//
+// 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.
+//
+
+extern "C" {
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+}
+
+#include <fstream>
+#include <sstream>
+
+#include "macros.hpp"
+
+#include "detail/parser.hpp"
+#include "detail/test_helpers.hpp"
+
+// ------------------------------------------------------------------------
+// Tests for the "atf_tp_writer" class.
+// ------------------------------------------------------------------------
+
+static
+void
+print_indented(const std::string& str)
+{
+ std::vector< std::string > ws = atf::text::split(str, "\n");
+ for (std::vector< std::string >::const_iterator iter = ws.begin();
+ iter != ws.end(); iter++)
+ std::cout << ">>" << *iter << "<<\n";
+}
+
+// XXX Should this string handling and verbosity level be part of the
+// ATF_REQUIRE_EQ macro? It may be hard to predict sometimes that a
+// string can have newlines in it, and so the error message generated
+// at the moment will be bogus if there are some.
+static
+void
+check_equal(const atf::tests::tc& tc, const std::string& str,
+ const std::string& exp)
+{
+ if (str != exp) {
+ std::cout << "String equality check failed.\n"
+ "Adding >> and << to delimit the string boundaries below.\n";
+ std::cout << "GOT:\n";
+ print_indented(str);
+ std::cout << "EXPECTED:\n";
+ print_indented(exp);
+ tc.fail("Constructed string differs from the expected one");
+ }
+}
+
+ATF_TEST_CASE(atf_tp_writer);
+ATF_TEST_CASE_HEAD(atf_tp_writer)
+{
+ set_md_var("descr", "Verifies the application/X-atf-tp writer");
+}
+ATF_TEST_CASE_BODY(atf_tp_writer)
+{
+ std::ostringstream expss;
+ std::ostringstream ss;
+
+#define RESET \
+ expss.str(""); \
+ ss.str("")
+
+#define CHECK \
+ check_equal(*this, ss.str(), expss.str())
+
+ {
+ RESET;
+
+ atf::tests::detail::atf_tp_writer w(ss);
+ expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
+ CHECK;
+ }
+
+ {
+ RESET;
+
+ atf::tests::detail::atf_tp_writer w(ss);
+ expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
+ CHECK;
+
+ w.start_tc("test1");
+ expss << "ident: test1\n";
+ CHECK;
+
+ w.end_tc();
+ CHECK;
+ }
+
+ {
+ RESET;
+
+ atf::tests::detail::atf_tp_writer w(ss);
+ expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
+ CHECK;
+
+ w.start_tc("test1");
+ expss << "ident: test1\n";
+ CHECK;
+
+ w.end_tc();
+ CHECK;
+
+ w.start_tc("test2");
+ expss << "\nident: test2\n";
+ CHECK;
+
+ w.end_tc();
+ CHECK;
+ }
+
+ {
+ RESET;
+
+ atf::tests::detail::atf_tp_writer w(ss);
+ expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
+ CHECK;
+
+ w.start_tc("test1");
+ expss << "ident: test1\n";
+ CHECK;
+
+ w.tc_meta_data("descr", "the description");
+ expss << "descr: the description\n";
+ CHECK;
+
+ w.end_tc();
+ CHECK;
+
+ w.start_tc("test2");
+ expss << "\nident: test2\n";
+ CHECK;
+
+ w.tc_meta_data("descr", "second test case");
+ expss << "descr: second test case\n";
+ CHECK;
+
+ w.tc_meta_data("require.progs", "/bin/cp");
+ expss << "require.progs: /bin/cp\n";
+ CHECK;
+
+ w.tc_meta_data("X-custom", "foo bar baz");
+ expss << "X-custom: foo bar baz\n";
+ CHECK;
+
+ w.end_tc();
+ CHECK;
+ }
+
+#undef CHECK
+#undef RESET
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/tests.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add tests for the "atf_tp_writer" class.
+ ATF_ADD_TEST_CASE(tcs, atf_tp_writer);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
diff --git a/contrib/atf/atf-c++/unused_test.cpp b/contrib/atf/atf-c++/unused_test.cpp
new file mode 100644
index 0000000..2a18a45
--- /dev/null
+++ b/contrib/atf/atf-c++/unused_test.cpp
@@ -0,0 +1,52 @@
+//
+// Automated Testing Framework (atf)
+//
+// Copyright (c) 2012 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 <atf-c++/macros.hpp>
+
+ATF_TEST_CASE(this_is_used);
+ATF_TEST_CASE_HEAD(this_is_used)
+{
+}
+ATF_TEST_CASE_BODY(this_is_used)
+{
+}
+
+ATF_TEST_CASE(this_is_unused);
+ATF_TEST_CASE_HEAD(this_is_unused)
+{
+}
+ATF_TEST_CASE_BODY(this_is_unused)
+{
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, this_is_used);
+ //ATF_ADD_TEST_CASE(tcs, this_is_unused);
+}
diff --git a/contrib/atf/atf-c++/utils.hpp b/contrib/atf/atf-c++/utils.hpp
new file mode 100644
index 0000000..1858b7f
--- /dev/null
+++ b/contrib/atf/atf-c++/utils.hpp
@@ -0,0 +1,200 @@
+//
+// 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.
+//
+
+#if !defined(_ATF_CXX_UTILS_HPP_)
+#define _ATF_CXX_UTILS_HPP_
+
+#include <cstddef>
+
+namespace atf {
+namespace utils {
+
+// ------------------------------------------------------------------------
+// The "auto_array" class.
+// ------------------------------------------------------------------------
+
+template< class T >
+struct auto_array_ref {
+ T* m_ptr;
+
+ explicit auto_array_ref(T*);
+};
+
+template< class T >
+auto_array_ref< T >::auto_array_ref(T* ptr) :
+ m_ptr(ptr)
+{
+}
+
+template< class T >
+class auto_array {
+ T* m_ptr;
+
+public:
+ auto_array(T* = NULL) throw();
+ auto_array(auto_array< T >&) throw();
+ auto_array(auto_array_ref< T >) throw();
+ ~auto_array(void) throw();
+
+ T* get(void) throw();
+ const T* get(void) const throw();
+ T* release(void) throw();
+ void reset(T* = NULL) throw();
+
+ auto_array< T >& operator=(auto_array< T >&) throw();
+ auto_array< T >& operator=(auto_array_ref< T >) throw();
+
+ T& operator[](int) throw();
+ operator auto_array_ref< T >(void) throw();
+};
+
+template< class T >
+auto_array< T >::auto_array(T* ptr)
+ throw() :
+ m_ptr(ptr)
+{
+}
+
+template< class T >
+auto_array< T >::auto_array(auto_array< T >& ptr)
+ throw() :
+ m_ptr(ptr.release())
+{
+}
+
+template< class T >
+auto_array< T >::auto_array(auto_array_ref< T > ref)
+ throw() :
+ m_ptr(ref.m_ptr)
+{
+}
+
+template< class T >
+auto_array< T >::~auto_array(void)
+ throw()
+{
+ if (m_ptr != NULL)
+ delete [] m_ptr;
+}
+
+template< class T >
+T*
+auto_array< T >::get(void)
+ throw()
+{
+ return m_ptr;
+}
+
+template< class T >
+const T*
+auto_array< T >::get(void)
+ const throw()
+{
+ return m_ptr;
+}
+
+template< class T >
+T*
+auto_array< T >::release(void)
+ throw()
+{
+ T* ptr = m_ptr;
+ m_ptr = NULL;
+ return ptr;
+}
+
+template< class T >
+void
+auto_array< T >::reset(T* ptr)
+ throw()
+{
+ if (m_ptr != NULL)
+ delete [] m_ptr;
+ m_ptr = ptr;
+}
+
+template< class T >
+auto_array< T >&
+auto_array< T >::operator=(auto_array< T >& ptr)
+ throw()
+{
+ reset(ptr.release());
+ return *this;
+}
+
+template< class T >
+auto_array< T >&
+auto_array< T >::operator=(auto_array_ref< T > ref)
+ throw()
+{
+ if (m_ptr != ref.m_ptr) {
+ delete [] m_ptr;
+ m_ptr = ref.m_ptr;
+ }
+ return *this;
+}
+
+template< class T >
+T&
+auto_array< T >::operator[](int pos)
+ throw()
+{
+ return m_ptr[pos];
+}
+
+template< class T >
+auto_array< T >::operator auto_array_ref< T >(void)
+ throw()
+{
+ return auto_array_ref< T >(release());
+}
+
+// ------------------------------------------------------------------------
+// The "noncopyable" class.
+// ------------------------------------------------------------------------
+
+class noncopyable {
+ // The class cannot be empty; otherwise we get ABI-stability warnings
+ // during the build, which will break it due to strict checking.
+ int m_noncopyable_dummy;
+
+ noncopyable(const noncopyable& nc);
+ noncopyable& operator=(const noncopyable& nc);
+
+protected:
+ // Explicitly needed to provide some non-private functions. Otherwise
+ // we also get some warnings during the build.
+ noncopyable(void) {}
+ ~noncopyable(void) {}
+};
+
+} // namespace utils
+} // namespace atf
+
+#endif // !defined(_ATF_CXX_UTILS_HPP_)
diff --git a/contrib/atf/atf-c++/utils_test.cpp b/contrib/atf/atf-c++/utils_test.cpp
new file mode 100644
index 0000000..f75e0a7
--- /dev/null
+++ b/contrib/atf/atf-c++/utils_test.cpp
@@ -0,0 +1,310 @@
+//
+// 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.
+//
+
+#include <iostream>
+
+#include "atf-c/defs.h"
+
+#include "macros.hpp"
+#include "utils.hpp"
+
+#include "detail/test_helpers.hpp"
+
+// ------------------------------------------------------------------------
+// Tests for the "auto_array" class.
+// ------------------------------------------------------------------------
+
+class test_array {
+public:
+ int m_value;
+
+ static ssize_t m_nblocks;
+
+ static
+ atf::utils::auto_array< test_array >
+ do_copy(atf::utils::auto_array< test_array >& ta)
+ {
+ return atf::utils::auto_array< test_array >(ta);
+ }
+
+ void* operator new(size_t size ATF_DEFS_ATTRIBUTE_UNUSED)
+ {
+ ATF_FAIL("New called but should have been new[]");
+ return new int(5);
+ }
+
+ void* operator new[](size_t size)
+ {
+ m_nblocks++;
+ void* mem = ::operator new(size);
+ std::cout << "Allocated 'test_array' object " << mem << "\n";
+ return mem;
+ }
+
+ void operator delete(void* mem ATF_DEFS_ATTRIBUTE_UNUSED)
+ {
+ ATF_FAIL("Delete called but should have been delete[]");
+ }
+
+ void operator delete[](void* mem)
+ {
+ std::cout << "Releasing 'test_array' object " << mem << "\n";
+ if (m_nblocks == 0)
+ ATF_FAIL("Unbalanced delete[]");
+ m_nblocks--;
+ ::operator delete(mem);
+ }
+};
+
+ssize_t test_array::m_nblocks = 0;
+
+ATF_TEST_CASE(auto_array_scope);
+ATF_TEST_CASE_HEAD(auto_array_scope)
+{
+ set_md_var("descr", "Tests the automatic scope handling in the "
+ "auto_array smart pointer class");
+}
+ATF_TEST_CASE_BODY(auto_array_scope)
+{
+ using atf::utils::auto_array;
+
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ {
+ auto_array< test_array > t(new test_array[10]);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_copy);
+ATF_TEST_CASE_HEAD(auto_array_copy)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' copy "
+ "constructor");
+}
+ATF_TEST_CASE_BODY(auto_array_copy)
+{
+ using atf::utils::auto_array;
+
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ {
+ auto_array< test_array > t1(new test_array[10]);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+
+ {
+ auto_array< test_array > t2(t1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_copy_ref);
+ATF_TEST_CASE_HEAD(auto_array_copy_ref)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' copy "
+ "constructor through the auxiliary auto_array_ref object");
+}
+ATF_TEST_CASE_BODY(auto_array_copy_ref)
+{
+ using atf::utils::auto_array;
+
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ {
+ auto_array< test_array > t1(new test_array[10]);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+
+ {
+ auto_array< test_array > t2 = test_array::do_copy(t1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_get);
+ATF_TEST_CASE_HEAD(auto_array_get)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' get "
+ "method");
+}
+ATF_TEST_CASE_BODY(auto_array_get)
+{
+ using atf::utils::auto_array;
+
+ test_array* ta = new test_array[10];
+ auto_array< test_array > t(ta);
+ ATF_REQUIRE_EQ(t.get(), ta);
+}
+
+ATF_TEST_CASE(auto_array_release);
+ATF_TEST_CASE_HEAD(auto_array_release)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' release "
+ "method");
+}
+ATF_TEST_CASE_BODY(auto_array_release)
+{
+ using atf::utils::auto_array;
+
+ test_array* ta1 = new test_array[10];
+ {
+ auto_array< test_array > t(ta1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ test_array* ta2 = t.release();
+ ATF_REQUIRE_EQ(ta2, ta1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ delete [] ta1;
+}
+
+ATF_TEST_CASE(auto_array_reset);
+ATF_TEST_CASE_HEAD(auto_array_reset)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' reset "
+ "method");
+}
+ATF_TEST_CASE_BODY(auto_array_reset)
+{
+ using atf::utils::auto_array;
+
+ test_array* ta1 = new test_array[10];
+ test_array* ta2 = new test_array[10];
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
+
+ {
+ auto_array< test_array > t(ta1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
+ t.reset(ta2);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ t.reset();
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_assign);
+ATF_TEST_CASE_HEAD(auto_array_assign)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' "
+ "assignment operator");
+}
+ATF_TEST_CASE_BODY(auto_array_assign)
+{
+ using atf::utils::auto_array;
+
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ {
+ auto_array< test_array > t1(new test_array[10]);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+
+ {
+ auto_array< test_array > t2;
+ t2 = t1;
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_assign_ref);
+ATF_TEST_CASE_HEAD(auto_array_assign_ref)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' "
+ "assignment operator through the auxiliary auto_array_ref "
+ "object");
+}
+ATF_TEST_CASE_BODY(auto_array_assign_ref)
+{
+ using atf::utils::auto_array;
+
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ {
+ auto_array< test_array > t1(new test_array[10]);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+
+ {
+ auto_array< test_array > t2;
+ t2 = test_array::do_copy(t1);
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+ }
+ ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
+}
+
+ATF_TEST_CASE(auto_array_access);
+ATF_TEST_CASE_HEAD(auto_array_access)
+{
+ set_md_var("descr", "Tests the auto_array smart pointer class' access "
+ "operator");
+}
+ATF_TEST_CASE_BODY(auto_array_access)
+{
+ using atf::utils::auto_array;
+
+ auto_array< test_array > t(new test_array[10]);
+
+ for (int i = 0; i < 10; i++)
+ t[i].m_value = i * 2;
+
+ for (int i = 0; i < 10; i++)
+ ATF_REQUIRE_EQ(t[i].m_value, i * 2);
+}
+
+// ------------------------------------------------------------------------
+// Tests cases for the header file.
+// ------------------------------------------------------------------------
+
+HEADER_TC(include, "atf-c++/utils.hpp");
+
+// ------------------------------------------------------------------------
+// Main.
+// ------------------------------------------------------------------------
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ // Add the test for the "auto_array" class.
+ ATF_ADD_TEST_CASE(tcs, auto_array_scope);
+ ATF_ADD_TEST_CASE(tcs, auto_array_copy);
+ ATF_ADD_TEST_CASE(tcs, auto_array_copy_ref);
+ ATF_ADD_TEST_CASE(tcs, auto_array_get);
+ ATF_ADD_TEST_CASE(tcs, auto_array_release);
+ ATF_ADD_TEST_CASE(tcs, auto_array_reset);
+ ATF_ADD_TEST_CASE(tcs, auto_array_assign);
+ ATF_ADD_TEST_CASE(tcs, auto_array_assign_ref);
+ ATF_ADD_TEST_CASE(tcs, auto_array_access);
+
+ // Add the test cases for the header file.
+ ATF_ADD_TEST_CASE(tcs, include);
+}
OpenPOWER on IntegriCloud