Import atf-0.20:
Experimental version released on February 7th, 2014. This is the first release without the code for the deprecated tools. If you require such code, please fetch a copy of the 0.19 release and extract the 'tools' directory for your own consumption. * Removed the deprecated tools. This includes atf-config, atf-report, atf-run and atf-version.
This commit is contained in:
parent
8fee91db34
commit
9b3afb9f3c
10
Atffile
10
Atffile
@ -1,10 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: atf-c
|
||||
tp: atf-c++
|
||||
tp: atf-sh
|
||||
tp: test-programs
|
||||
|
||||
tp-glob: tools*
|
43
INSTALL
43
INSTALL
@ -94,14 +94,6 @@ The most common, standard flags given to 'configure' are:
|
||||
Specifies where the program (binaries and all associated files) will
|
||||
be installed.
|
||||
|
||||
* --sysconfdir=directory
|
||||
Possible values: Any path
|
||||
Default: /usr/local/etc
|
||||
|
||||
Specifies where the installed programs will look for configuration files.
|
||||
'/atf' will be appended to the given path unless ATF_CONFSUBDIR is
|
||||
redefined as explained later on.
|
||||
|
||||
* --help
|
||||
Shows information about all available flags and exits immediately,
|
||||
without running any configuration tasks.
|
||||
@ -152,14 +144,6 @@ script:
|
||||
Specifies the C++ compiler flags that ATF will use at run time whenever
|
||||
the build-time-specific checks are used.
|
||||
|
||||
* ATF_CONFSUBDIR
|
||||
Possible values: empty, a relative path.
|
||||
Default: atf.
|
||||
|
||||
Specifies the subdirectory of the configuration directory (given by the
|
||||
--sysconfdir argument) under which ATF will search for its configuration
|
||||
files.
|
||||
|
||||
* ATF_SHELL
|
||||
Possible values: empty, absolute path to a POSIX shell interpreter.
|
||||
Default: empty.
|
||||
@ -177,14 +161,6 @@ script:
|
||||
and work directories for test cases. This is just a default and can be
|
||||
overriden at run time.
|
||||
|
||||
* GDB
|
||||
Possible values: empty, absolute path to GNU GDB.
|
||||
Default: empty.
|
||||
|
||||
Specifies the path to the GNU GDB binary that atf-run will use to gather
|
||||
a stack trace of a crashing test program. If empty, the configure script
|
||||
will try to find a suitable binary for you.
|
||||
|
||||
The following flags are specific to ATF's 'configure' script:
|
||||
|
||||
* --enable-developer
|
||||
@ -199,25 +175,6 @@ The following flags are specific to ATF's 'configure' script:
|
||||
detection features regardless of the value of this flag. However, such
|
||||
warnings are only fatal when --enable-developer is 'yes'.
|
||||
|
||||
* --enable-tools
|
||||
Possible values: yes, no
|
||||
Default: no.
|
||||
|
||||
Enables the build of the deprecated atf-config, atf-report, atf-run
|
||||
and atf-version tools. atf-report and atf-run have been superseded by
|
||||
Kyua, and atf-config and atf-version are unnecessary.
|
||||
|
||||
|
||||
Post-installation steps
|
||||
***********************
|
||||
|
||||
After installing ATF, you have to register the DTDs it provides into the
|
||||
system-wide XML catalog. See the comments at the top of the files in
|
||||
${datadir}/share/xml/atf to see the correct public identifiers. This
|
||||
directory will typically be /usr/local/share/xml/atf or /usr/share/xml/atf.
|
||||
Failure to do so will lead to further errors when processing the XML files
|
||||
generated by atf-report.
|
||||
|
||||
|
||||
===========================================================================
|
||||
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2
|
||||
|
4
Kyuafile
4
Kyuafile
@ -6,7 +6,3 @@ include("atf-c/Kyuafile")
|
||||
include("atf-c++/Kyuafile")
|
||||
include("atf-sh/Kyuafile")
|
||||
include("test-programs/Kyuafile")
|
||||
|
||||
if fs.exists("tools/Kyuafile") then
|
||||
include("tools/Kyuafile")
|
||||
end
|
||||
|
44
Makefile.am
44
Makefile.am
@ -30,7 +30,6 @@
|
||||
atf_aclocal_DATA =
|
||||
BUILT_SOURCES =
|
||||
CLEANFILES =
|
||||
DIST_HOOKS =
|
||||
EXTRA_DIST =
|
||||
bin_PROGRAMS =
|
||||
dist_man_MANS =
|
||||
@ -54,10 +53,6 @@ include bootstrap/Makefile.am.inc
|
||||
include doc/Makefile.am.inc
|
||||
include test-programs/Makefile.am.inc
|
||||
|
||||
if ENABLE_TOOLS
|
||||
include tools/Makefile.am.inc
|
||||
endif
|
||||
|
||||
#
|
||||
# Top-level distfile documents.
|
||||
#
|
||||
@ -76,32 +71,9 @@ TESTS_ENVIRONMENT = PATH=$(prefix)/bin:$${PATH} \
|
||||
testsdir = $(exec_prefix)/tests
|
||||
pkgtestsdir = $(testsdir)/$(PACKAGE)
|
||||
|
||||
if ENABLE_TOOLS
|
||||
INSTALLCHECK_TARGETS += installcheck-atf
|
||||
PHONY_TARGETS += installcheck-atf
|
||||
installcheck-atf:
|
||||
logfile=$$(pwd)/installcheck.log; \
|
||||
fifofile=$$(pwd)/installcheck.fifo; \
|
||||
cd $(pkgtestsdir); \
|
||||
rm -f $${fifofile}; \
|
||||
mkfifo $${fifofile}; \
|
||||
cat $${fifofile} | tee $${logfile} | $(TESTS_ENVIRONMENT) atf-report & \
|
||||
$(TESTS_ENVIRONMENT) atf-run >>$${fifofile}; \
|
||||
res=$${?}; \
|
||||
wait; \
|
||||
rm $${fifofile}; \
|
||||
echo; \
|
||||
echo "The verbatim output of atf-run has been saved to" \
|
||||
"installcheck.log; exit was $${res}"; \
|
||||
test $${res} -eq 0
|
||||
CLEANFILES += installcheck.fifo installcheck.log
|
||||
endif
|
||||
|
||||
PHONY_TARGETS += installcheck-kyua
|
||||
if HAVE_KYUA
|
||||
if !ENABLE_TOOLS
|
||||
INSTALLCHECK_TARGETS += installcheck-kyua
|
||||
endif
|
||||
installcheck-kyua:
|
||||
cd $(pkgtestsdir) && $(TESTS_ENVIRONMENT) $(KYUA) test
|
||||
endif
|
||||
@ -109,9 +81,6 @@ endif
|
||||
installcheck-local: $(INSTALLCHECK_TARGETS)
|
||||
|
||||
pkgtests_DATA = Kyuafile
|
||||
if ENABLE_TOOLS
|
||||
pkgtests_DATA += Atffile
|
||||
endif
|
||||
EXTRA_DIST += $(pkgtests_DATA)
|
||||
|
||||
BUILD_SH_TP = \
|
||||
@ -124,17 +93,6 @@ BUILD_SH_TP = \
|
||||
# Custom targets.
|
||||
#
|
||||
|
||||
DIST_HOOKS += forbid-dist
|
||||
if ENABLE_TOOLS
|
||||
forbid-dist:
|
||||
@true
|
||||
else
|
||||
forbid-dist:
|
||||
@echo "Sorry; cannot make dist without the tools enabled."
|
||||
@echo "Please reconfigure with --enable-tools."
|
||||
@false
|
||||
endif
|
||||
|
||||
PHONY_TARGETS += clean-all
|
||||
clean-all:
|
||||
GIT="$(GIT)" $(SH) $(srcdir)/admin/clean-all.sh
|
||||
@ -149,6 +107,4 @@ release-test:
|
||||
|
||||
.PHONY: $(PHONY_TARGETS)
|
||||
|
||||
dist-hook: $(DIST_HOOKS)
|
||||
|
||||
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8
|
||||
|
2102
Makefile.in
2102
Makefile.in
File diff suppressed because it is too large
Load Diff
13
NEWS
13
NEWS
@ -2,6 +2,19 @@ Major changes between releases Automated Testing Framework
|
||||
===========================================================================
|
||||
|
||||
|
||||
Changes in version 0.20
|
||||
***********************
|
||||
|
||||
Experimental version released on February 7th, 2014.
|
||||
|
||||
This is the first release without the code for the deprecated tools. If
|
||||
you require such code, please fetch a copy of the 0.19 release and extract
|
||||
the 'tools' directory for your own consumption.
|
||||
|
||||
* Removed the deprecated tools. This includes atf-config, atf-report,
|
||||
atf-run and atf-version.
|
||||
|
||||
|
||||
Changes in version 0.19
|
||||
***********************
|
||||
|
||||
|
25
README
25
README
@ -5,21 +5,18 @@ Introductory information Automated Testing Framework
|
||||
Introduction
|
||||
************
|
||||
|
||||
The Automated Testing Framework (ATF) is a collection of libraries and
|
||||
utilities designed to ease unattended application testing in the hands of
|
||||
developers and end users of a specific piece of software.
|
||||
The Automated Testing Framework (ATF) is a collection of libraries to
|
||||
implement test programs in a variety of languages. At the moment, ATF
|
||||
offers C, C++ and POSIX shell bindings with which to implement tests.
|
||||
These bindings all offer a similar set of functionality and any test
|
||||
program written with them exposes a consistent user interface.
|
||||
|
||||
As regards developers, ATF provides the necessary means to easily create
|
||||
test suites composed of multiple test programs, which in turn are a
|
||||
collection of test cases. It also attempts to simplify the debugging of
|
||||
problems when these test cases detect an error by providing as much
|
||||
information as possible about the failure.
|
||||
|
||||
As regards users, it simplifies the process of running the test suites and,
|
||||
in special, encourages end users to run them often: they do not need to
|
||||
have source trees around nor any other development tools installed to be
|
||||
able to certify that a given piece of software works on their machine as
|
||||
advertised.
|
||||
ATF-based test programs rely on a separate runtime engine to execute them.
|
||||
The runtime engine is in charge of isolating the test programs from the
|
||||
rest of the system to ensure that their results are deterministic and that
|
||||
they cannot affect the running system. The runtime engine is also
|
||||
responsible for gathering the results of all tests and composing reports.
|
||||
The current runtime of choice is Kyua.
|
||||
|
||||
|
||||
Other documents
|
||||
|
1
aclocal.m4
vendored
1
aclocal.m4
vendored
@ -1219,5 +1219,4 @@ m4_include([m4/module-application.m4])
|
||||
m4_include([m4/module-defs.m4])
|
||||
m4_include([m4/module-env.m4])
|
||||
m4_include([m4/module-fs.m4])
|
||||
m4_include([m4/module-signals.m4])
|
||||
m4_include([m4/runtime-tool.m4])
|
||||
|
@ -108,7 +108,7 @@ find_sources() {
|
||||
\! -name "ltsugar.m4" \
|
||||
\! -name "lt~obsolete.m4" \
|
||||
\! -name "*.so.*" \
|
||||
\) | grep -v tools/
|
||||
\)
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -1,14 +0,0 @@
|
||||
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
|
@ -71,8 +71,7 @@ atf-c++/atf-c++.pc: $(srcdir)/atf-c++/atf-c++.pc.in Makefile
|
||||
<$(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 \
|
||||
tests_atf_c___DATA = atf-c++/Kyuafile \
|
||||
atf-c++/macros_hpp_test.cpp \
|
||||
atf-c++/unused_test.cpp
|
||||
tests_atf_c__dir = $(pkgtestsdir)/atf-c++
|
||||
|
@ -1,11 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: application_test
|
||||
tp: auto_array_test
|
||||
tp: env_test
|
||||
tp: exceptions_test
|
||||
tp: fs_test
|
||||
tp: sanity_test
|
||||
tp: text_test
|
@ -42,8 +42,7 @@ libatf_c___la_SOURCES += atf-c++/detail/application.cpp \
|
||||
atf-c++/detail/text.cpp \
|
||||
atf-c++/detail/text.hpp
|
||||
|
||||
tests_atf_c___detail_DATA = atf-c++/detail/Atffile \
|
||||
atf-c++/detail/Kyuafile
|
||||
tests_atf_c___detail_DATA = atf-c++/detail/Kyuafile
|
||||
tests_atf_c___detaildir = $(pkgtestsdir)/atf-c++/detail
|
||||
EXTRA_DIST += $(tests_atf_c___detail_DATA)
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
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: error_test
|
||||
tp: macros_test
|
||||
tp: pkg_config_test
|
||||
tp: tc_test
|
||||
tp: tp_test
|
||||
tp: utils_test
|
@ -60,7 +60,7 @@ libatf_c_la_LDFLAGS = -version-info 0:0:0
|
||||
|
||||
# XXX For some reason, the nodist line above does not work as expected.
|
||||
# Work this problem around.
|
||||
DIST_HOOKS += kill-defs-h
|
||||
dist-hook: kill-defs-h
|
||||
kill-defs-h:
|
||||
rm -f $(distdir)/atf-c/defs.h
|
||||
|
||||
@ -95,8 +95,7 @@ atf-c/atf-c.pc: $(srcdir)/atf-c/atf-c.pc.in Makefile
|
||||
<$(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 \
|
||||
tests_atf_c_DATA = atf-c/Kyuafile \
|
||||
atf-c/macros_h_test.c \
|
||||
atf-c/unused_test.c
|
||||
tests_atf_cdir = $(pkgtestsdir)/atf-c
|
||||
|
@ -1,13 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: dynstr_test
|
||||
tp: env_test
|
||||
tp: fs_test
|
||||
tp: list_test
|
||||
tp: map_test
|
||||
tp: process_test
|
||||
tp: sanity_test
|
||||
tp: text_test
|
||||
tp: user_test
|
@ -47,8 +47,7 @@ libatf_c_la_SOURCES += atf-c/detail/dynstr.c \
|
||||
atf-c/detail/user.c \
|
||||
atf-c/detail/user.h
|
||||
|
||||
tests_atf_c_detail_DATA = atf-c/detail/Atffile \
|
||||
atf-c/detail/Kyuafile
|
||||
tests_atf_c_detail_DATA = atf-c/detail/Kyuafile
|
||||
tests_atf_c_detaildir = $(pkgtestsdir)/atf-c/detail
|
||||
EXTRA_DIST += $(tests_atf_c_detail_DATA)
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: tc_test
|
||||
tp: tp_test
|
||||
tp: normalize_test
|
||||
tp: config_test
|
||||
tp: atf-check_test
|
||||
tp: atf_check_test
|
||||
tp: integration_test
|
@ -57,8 +57,7 @@ atf-sh/atf-sh.pc: $(srcdir)/atf-sh/atf-sh.pc.in Makefile
|
||||
<$(srcdir)/atf-sh/atf-sh.pc.in >atf-sh/atf-sh.pc.tmp
|
||||
mv atf-sh/atf-sh.pc.tmp atf-sh/atf-sh.pc
|
||||
|
||||
tests_atf_sh_DATA = atf-sh/Atffile \
|
||||
atf-sh/Kyuafile
|
||||
tests_atf_sh_DATA = atf-sh/Kyuafile
|
||||
tests_atf_shdir = $(pkgtestsdir)/atf-sh
|
||||
EXTRA_DIST += $(tests_atf_sh_DATA)
|
||||
|
||||
|
@ -57,9 +57,6 @@
|
||||
/* Define to 1 if vsnprintf is in std */
|
||||
#undef HAVE_VSNPRINTF_IN_STD
|
||||
|
||||
/* Define to the last valid signal number */
|
||||
#undef LAST_SIGNO
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
@ -27,15 +27,7 @@
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
check_PROGRAMS = bootstrap/h_app_empty
|
||||
bootstrap_h_app_empty_SOURCES = bootstrap/h_app_empty.cpp
|
||||
bootstrap_h_app_empty_LDADD = tools/libtools.a $(ATF_CXX_LIBS)
|
||||
|
||||
check_PROGRAMS += bootstrap/h_app_opts_args
|
||||
bootstrap_h_app_opts_args_SOURCES = bootstrap/h_app_opts_args.cpp
|
||||
bootstrap_h_app_opts_args_LDADD = tools/libtools.a $(ATF_CXX_LIBS)
|
||||
|
||||
check_PROGRAMS += bootstrap/h_tp_basic_c
|
||||
check_PROGRAMS = bootstrap/h_tp_basic_c
|
||||
bootstrap_h_tp_basic_c_SOURCES = bootstrap/h_tp_basic_c.c
|
||||
bootstrap_h_tp_basic_c_LDADD = libatf-c.la
|
||||
|
||||
@ -85,11 +77,7 @@ EXTRA_DIST += bootstrap/testsuite \
|
||||
bootstrap/testsuite.at \
|
||||
$(testsuite_incs)
|
||||
|
||||
testsuite_incs= $(srcdir)/bootstrap/t_application_help.at \
|
||||
$(srcdir)/bootstrap/t_application_opts_args.at \
|
||||
$(srcdir)/bootstrap/t_atf_config.at \
|
||||
$(srcdir)/bootstrap/t_atf_run.at \
|
||||
$(srcdir)/bootstrap/t_subr_atf_check.at \
|
||||
testsuite_incs= $(srcdir)/bootstrap/t_subr_atf_check.at \
|
||||
$(srcdir)/bootstrap/t_test_program_compare.at \
|
||||
$(srcdir)/bootstrap/t_test_program_filter.at \
|
||||
$(srcdir)/bootstrap/t_test_program_list.at \
|
||||
@ -103,7 +91,6 @@ testsuite_incs= $(srcdir)/bootstrap/t_application_help.at \
|
||||
echo 'm4_define(AT_PACKAGE_VERSION, @PACKAGE_VERSION@)'; \
|
||||
echo 'm4_define(AT_PACKAGE_STRING, @PACKAGE_STRING@)'; \
|
||||
echo 'm4_define(AT_PACKAGE_BUGREPORT, @PACKAGE_BUGREPORT@)'; \
|
||||
echo 'm4_define(ENABLE_TOOLS, @ENABLE_TOOLS@)'; \
|
||||
} >$(srcdir)/bootstrap/package.m4
|
||||
|
||||
@target_srcdir@bootstrap/testsuite: $(srcdir)/bootstrap/testsuite.at \
|
||||
|
@ -1,62 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "tools/application.hpp"
|
||||
|
||||
class h_app_empty : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
public:
|
||||
h_app_empty(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
const char* h_app_empty::m_description =
|
||||
"A helper application for the bootstrap test suite that does nothing "
|
||||
"on its own and redefines no methods.";
|
||||
|
||||
h_app_empty::h_app_empty(void) :
|
||||
app(m_description, "h_app_empty(1)", "atf(7)")
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
h_app_empty::main(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return h_app_empty().run(argc, argv);
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "tools/application.hpp"
|
||||
|
||||
class h_app_opts_args : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
std::string specific_args(void) const;
|
||||
options_set specific_options(void) const;
|
||||
void process_option(int, const char*);
|
||||
|
||||
public:
|
||||
h_app_opts_args(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
const char* h_app_opts_args::m_description =
|
||||
"A helper application for the bootstrap test suite that redefines the "
|
||||
"methods to specify custom options and arguments.";
|
||||
|
||||
h_app_opts_args::h_app_opts_args(void) :
|
||||
app(m_description, "h_app_opts_args(1)", "atf(7)")
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
h_app_opts_args::specific_args(void)
|
||||
const
|
||||
{
|
||||
return "<arg1> <arg2>";
|
||||
}
|
||||
|
||||
h_app_opts_args::options_set
|
||||
h_app_opts_args::specific_options(void)
|
||||
const
|
||||
{
|
||||
using tools::application::option;
|
||||
options_set opts;
|
||||
opts.insert(option('d', "", "Debug mode"));
|
||||
opts.insert(option('v', "level", "Verbosity level"));
|
||||
return opts;
|
||||
}
|
||||
|
||||
void
|
||||
h_app_opts_args::process_option(int ch, const char* arg)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
std::cout << "-d given\n";
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
std::cout << "-v given with argument " << arg << "\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
h_app_opts_args::main(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return h_app_opts_args().run(argc, argv);
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
# Signature of the current package.
|
||||
m4_define(AT_PACKAGE_NAME, Automated Testing Framework)
|
||||
m4_define(AT_PACKAGE_TARNAME, atf)
|
||||
m4_define(AT_PACKAGE_VERSION, 0.19)
|
||||
m4_define(AT_PACKAGE_STRING, Automated Testing Framework 0.19)
|
||||
m4_define(AT_PACKAGE_VERSION, 0.20)
|
||||
m4_define(AT_PACKAGE_STRING, Automated Testing Framework 0.20)
|
||||
m4_define(AT_PACKAGE_BUGREPORT, atf-devel@NetBSD.org)
|
||||
m4_define(ENABLE_TOOLS, yes)
|
||||
|
@ -1,40 +0,0 @@
|
||||
dnl
|
||||
dnl Automated Testing Framework (atf)
|
||||
dnl
|
||||
dnl Copyright (c) 2007 The NetBSD Foundation, 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
|
||||
dnl are met:
|
||||
dnl 1. Redistributions of source code must retain the above copyright
|
||||
dnl notice, this list of conditions and the following disclaimer.
|
||||
dnl 2. 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
|
||||
dnl THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
dnl CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
dnl IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
dnl DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
dnl GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
dnl IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dnl
|
||||
|
||||
AT_SETUP([application: online help option])
|
||||
|
||||
AT_CHECK([APP_HELPER(app_empty)], 0, [stdout], [])
|
||||
AT_CHECK([grep 'Available options' stdout], 1, [ignore], [])
|
||||
|
||||
AT_CHECK([APP_HELPER(app_empty) -h], 0, [stdout], [])
|
||||
AT_CHECK([grep 'Available options' stdout], 0, [ignore], [])
|
||||
|
||||
AT_CLEANUP()
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
@ -1,86 +0,0 @@
|
||||
dnl
|
||||
dnl Automated Testing Framework (atf)
|
||||
dnl
|
||||
dnl Copyright (c) 2007 The NetBSD Foundation, 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
|
||||
dnl are met:
|
||||
dnl 1. Redistributions of source code must retain the above copyright
|
||||
dnl notice, this list of conditions and the following disclaimer.
|
||||
dnl 2. 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
|
||||
dnl THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
dnl CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
dnl IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
dnl DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
dnl GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
dnl IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dnl
|
||||
|
||||
AT_SETUP([application: arguments and options handling])
|
||||
|
||||
dnl Check that an application that does not redefine any method does
|
||||
dnl not show strange flags in the usage message.
|
||||
AT_CHECK([APP_HELPER(app_empty) -h], 0, [stdout], [])
|
||||
AT_CHECK([grep ' -d ' stdout], 1, [ignore], [])
|
||||
AT_CHECK([grep ' -h ' stdout], 0, [ignore], [])
|
||||
AT_CHECK([grep ' -v ' stdout], 1, [ignore], [])
|
||||
AT_CHECK([grep ' -z ' stdout], 1, [ignore], [])
|
||||
|
||||
dnl Check that an application that adds its own options shows them in
|
||||
dnl the usage message.
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -h], 0, [stdout], [])
|
||||
AT_CHECK([grep ' -d ' stdout], 0, [ignore], [])
|
||||
AT_CHECK([grep ' -h ' stdout], 0, [ignore], [])
|
||||
AT_CHECK([grep ' -v ' stdout], 0, [ignore], [])
|
||||
AT_CHECK([grep ' -z ' stdout], 1, [ignore], [])
|
||||
|
||||
dnl Check that an application that does not redefine any method does
|
||||
dnl not recognize strange flags.
|
||||
AT_CHECK([APP_HELPER(app_empty) -d], 1, [], [stderr])
|
||||
AT_CHECK([grep 'Unknown option.*-d' stderr], 0, [ignore], [])
|
||||
AT_CHECK([APP_HELPER(app_empty) -v], 1, [], [stderr])
|
||||
AT_CHECK([grep 'Unknown option.*-v' stderr], 0, [ignore], [])
|
||||
AT_CHECK([APP_HELPER(app_empty) -z], 1, [], [stderr])
|
||||
AT_CHECK([grep 'Unknown option.*-z' stderr], 0, [ignore], [])
|
||||
|
||||
dnl Check that an application that adds its own options is able to
|
||||
dnl properly handle them.
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -d], 0, [stdout], [])
|
||||
AT_CHECK([grep -- '-d given' stdout], 0, [ignore], [])
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -v], 1, [], [stderr])
|
||||
AT_CHECK([grep 'Option.*-v.*requires an argument' stderr], 0, [ignore], [])
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -v foo], 0, [stdout], [])
|
||||
AT_CHECK([grep -- '-v given with argument foo' stdout], 0, [ignore], [])
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -z], 1, [], [stderr])
|
||||
AT_CHECK([grep 'Unknown option.*-z' stderr], 0, [ignore], [])
|
||||
|
||||
dnl Check that option processing stops after an argument.
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -- -d], 0, [stdout], [])
|
||||
AT_CHECK([grep -- '-d given' stdout], 1, [], [])
|
||||
AT_CHECK([APP_HELPER(app_opts_args) arg -d], 0, [stdout], [])
|
||||
AT_CHECK([grep -- '-d given' stdout], 1, [], [])
|
||||
|
||||
dnl Check that an application that does not redefine any method does
|
||||
dnl not show unexpected arguments in the usage message.
|
||||
AT_CHECK([APP_HELPER(app_empty) -h], 0, [stdout], [])
|
||||
AT_CHECK([grep '\@<:@options\@:>@$' stdout], 0, [ignore], [])
|
||||
|
||||
dnl Check that an application that defines the arguments it takes
|
||||
dnl shows them in the usage message.
|
||||
AT_CHECK([APP_HELPER(app_opts_args) -h], 0, [stdout], [])
|
||||
AT_CHECK([grep '\@<:@options\@:>@ <arg1> <arg2>' stdout], 0, [ignore], [])
|
||||
|
||||
AT_CLEANUP()
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
@ -1,108 +0,0 @@
|
||||
dnl
|
||||
dnl Automated Testing Framework (atf)
|
||||
dnl
|
||||
dnl Copyright (c) 2007 The NetBSD Foundation, 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
|
||||
dnl are met:
|
||||
dnl 1. Redistributions of source code must retain the above copyright
|
||||
dnl notice, this list of conditions and the following disclaimer.
|
||||
dnl 2. 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
|
||||
dnl THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
dnl CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
dnl IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
dnl DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
dnl GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
dnl IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dnl
|
||||
|
||||
AT_SETUP([atf-config: querying of build-time variables])
|
||||
AT_TESTED(atf-config)
|
||||
|
||||
all_vars="atf_arch \
|
||||
atf_build_cc \
|
||||
atf_build_cflags \
|
||||
atf_build_cpp \
|
||||
atf_build_cppflags \
|
||||
atf_build_cxx \
|
||||
atf_build_cxxflags \
|
||||
atf_confdir \
|
||||
atf_includedir \
|
||||
atf_libdir \
|
||||
atf_libexecdir \
|
||||
atf_machine \
|
||||
atf_pkgdatadir \
|
||||
atf_shell \
|
||||
atf_workdir"
|
||||
all_vars_no=15
|
||||
|
||||
dnl List all variables.
|
||||
AT_CHECK([atf-config], [0], [stdout], [])
|
||||
AT_CHECK([COUNT_LINES(stdout, ${all_vars_no})], [0], [], [])
|
||||
for v in ${all_vars}; do
|
||||
AT_CHECK([grep "${v}" stdout], [0], [ignore], [])
|
||||
done
|
||||
|
||||
dnl Query a single variable and test terse mode.
|
||||
for v in ${all_vars}; do
|
||||
AT_CHECK([atf-config ${v}], [0], [stdout], [])
|
||||
AT_CHECK([COUNT_LINES(stdout, 1)], [0], [], [])
|
||||
AT_CHECK([grep "${v}" stdout], [0], [ignore], [])
|
||||
AT_CHECK([cut -d ' ' -f 3- stdout], [0], [stdout], [])
|
||||
AT_CHECK([mv stdout expout], [0], [], [])
|
||||
AT_CHECK([atf-config -t ${v}], [0], [expout], [])
|
||||
done
|
||||
|
||||
dnl Query several variables.
|
||||
AT_CHECK([atf-config atf_libexecdir atf_pkgdatadir], [0], [stdout], [])
|
||||
AT_CHECK([grep 'atf_libexecdir' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'atf_pkgdatadir' stdout], [0], [ignore], [])
|
||||
AT_CHECK([COUNT_LINES(stdout, 2)], [0], [ignore], [])
|
||||
|
||||
dnl Query a non-existent variable.
|
||||
AT_CHECK([atf-config non_existent], [1], [], [stderr])
|
||||
AT_CHECK([grep 'Unknown variable.*non_existent' stderr], [0], [ignore], [])
|
||||
|
||||
dnl Query an existent and non-existent variable.
|
||||
for v in ${all_vars}; do
|
||||
AT_CHECK([atf-config ${v} non_existent], [1], [], [stderr])
|
||||
AT_CHECK([grep 'Unknown variable.*non_existent' stderr],
|
||||
[0], [ignore], [])
|
||||
AT_CHECK([atf-config non_existent ${v}], [1], [], [stderr])
|
||||
AT_CHECK([grep 'Unknown variable.*non_existent' stderr],
|
||||
[0], [ignore], [])
|
||||
done
|
||||
|
||||
dnl Override every variable through the environment.
|
||||
for v in ${all_vars}; do
|
||||
V=$(echo ${v} | tr '@<:@a-z@:>@' '@<:@A-Z@:>@')
|
||||
AT_CHECK([env ${V}=testval atf-config], [0], [stdout], [])
|
||||
AT_CHECK([mv stdout all], [0], [], [])
|
||||
|
||||
AT_CHECK([grep "^${v} : " all], [0], [stdout], [])
|
||||
AT_CHECK([mv stdout affected], [0], [], [])
|
||||
AT_CHECK([grep -v "^${v} : " all], [0], [stdout], [])
|
||||
AT_CHECK([mv stdout unaffected], [0], [], [])
|
||||
|
||||
AT_CHECK([COUNT_LINES(affected, 1)], [0], [ignore], [])
|
||||
AT_CHECK([COUNT_LINES(unaffected, $((${all_vars_no} - 1)))],
|
||||
[0], [ignore], [])
|
||||
|
||||
AT_CHECK([grep "^${v} : testval$" affected], [0], [ignore], [])
|
||||
AT_CHECK([grep ' : testval$' unaffected], [1], [], [])
|
||||
done
|
||||
|
||||
AT_CLEANUP()
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
@ -1,178 +0,0 @@
|
||||
dnl
|
||||
dnl Automated Testing Framework (atf)
|
||||
dnl
|
||||
dnl Copyright (c) 2007 The NetBSD Foundation, 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
|
||||
dnl are met:
|
||||
dnl 1. Redistributions of source code must retain the above copyright
|
||||
dnl notice, this list of conditions and the following disclaimer.
|
||||
dnl 2. 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
|
||||
dnl THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
dnl CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
dnl IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
dnl DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
dnl GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
dnl IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dnl
|
||||
|
||||
AT_SETUP([atf-run: execution of tests])
|
||||
AT_TESTED(atf-run)
|
||||
|
||||
m4_define([CREATE_PASS_TEST],
|
||||
[AT_CHECK([sed -e 's,@TC_NAME@,$2,g' <TEST_HELPER_NO_S(tp_pass)],
|
||||
[0], [stdout], [])
|
||||
AT_CHECK([mv stdout $1], [0], [], [])
|
||||
AT_CHECK([chmod +x $1], [0], [], [])
|
||||
])
|
||||
|
||||
m4_define([CREATE_FAIL_TEST],
|
||||
[AT_CHECK([sed -e 's,@TC_NAME@,$2,g' <TEST_HELPER_NO_S(tp_fail)],
|
||||
[0], [stdout], [])
|
||||
AT_CHECK([mv stdout $1], [0], [], [])
|
||||
AT_CHECK([chmod +x $1], [0], [], [])
|
||||
])
|
||||
|
||||
AT_CHECK([mkdir top], [0], [], [])
|
||||
AT_CHECK([mkdir top/dir1], [0], [], [])
|
||||
AT_CHECK([mkdir top/dir2], [0], [], [])
|
||||
AT_DATA([top/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: dir1
|
||||
tp: dir2
|
||||
tp: test1
|
||||
tp: test2
|
||||
])
|
||||
AT_DATA([top/dir1/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: test3
|
||||
])
|
||||
AT_DATA([top/dir2/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: test4
|
||||
tp: test5
|
||||
])
|
||||
CREATE_PASS_TEST([top/test1], [tc_1])
|
||||
CREATE_FAIL_TEST([top/test2], [tc_2])
|
||||
CREATE_PASS_TEST([top/dir1/test3], [tc_3])
|
||||
CREATE_FAIL_TEST([top/dir2/test4], [tc_4])
|
||||
CREATE_PASS_TEST([top/dir2/test5], [tc_5])
|
||||
|
||||
AT_CHECK([cd top/dir1 && atf-run], [0], [stdout], [])
|
||||
CHECK_TPS_TCR(tc_3, passed, stdout)
|
||||
AT_CHECK([grep -i 'tc_@<:@1245@:>@' stdout], [1], [], [])
|
||||
AT_CHECK([grep 'tc-so:ignore-me' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'tc-se:ignore-me' stdout], [0], [ignore], [])
|
||||
|
||||
AT_CHECK([cd top/dir2 && atf-run], [1], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(tc_4, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_5, passed, stdout)
|
||||
AT_CHECK([grep -i 'tc_@<:@123@:>@' stdout], [1], [], [])
|
||||
AT_CHECK([grep 'tc-so:ignore-me' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'tc-se:ignore-me' stdout], [0], [ignore], [])
|
||||
|
||||
AT_CHECK([cd top && atf-run], [1], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(tc_1, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_2, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_3, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_4, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_5, passed, stdout)
|
||||
AT_CHECK([grep 'tc-so:ignore-me' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'tc-se:ignore-me' stdout], [0], [ignore], [])
|
||||
|
||||
dnl Repeat previous but using a glob that matches everything.
|
||||
AT_DATA([top/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp-glob: *
|
||||
])
|
||||
AT_CHECK([cd top && atf-run], [1], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(tc_1, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_2, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_3, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_4, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_5, passed, stdout)
|
||||
AT_CHECK([grep 'tc-so:ignore-me' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'tc-se:ignore-me' stdout], [0], [ignore], [])
|
||||
|
||||
dnl Repeat previous but using a glob that matches directories only.
|
||||
AT_DATA([top/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp-glob: d*
|
||||
])
|
||||
AT_CHECK([cd top && atf-run], [1], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(tc_3, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_4, failed, stdout)
|
||||
CHECK_TPS_TCR(tc_5, passed, stdout)
|
||||
AT_CHECK([grep 'tc-so:ignore-me' stdout], [0], [ignore], [])
|
||||
AT_CHECK([grep 'tc-se:ignore-me' stdout], [0], [ignore], [])
|
||||
|
||||
dnl Make sure globs do not match non-executable nor hidden files.
|
||||
dnl XXX This is not really part of the bootstrap test suite. Move to
|
||||
dnl tests/atf/tools/t_atf_run.sh when it exists.
|
||||
AT_CHECK([rm -rf top], [0], [], [])
|
||||
AT_CHECK([mkdir top], [0], [], [])
|
||||
CREATE_PASS_TEST([top/test1], [tc_1])
|
||||
CREATE_PASS_TEST([top/test2], [tc_2])
|
||||
CREATE_PASS_TEST([top/test3], [tc_3])
|
||||
AT_CHECK([chmod -x top/test3], [0], [], [])
|
||||
CREATE_PASS_TEST([top/.test4], [tc_4])
|
||||
AT_CHECK([chmod -x top/.test4], [0], [], [])
|
||||
AT_DATA([top/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp-glob: *
|
||||
])
|
||||
AT_CHECK([cd top && atf-run], [0], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(tc_1, passed, stdout)
|
||||
CHECK_TPS_TCR(tc_2, passed, stdout)
|
||||
AT_CHECK([grep -i 'tc_3' stdout], [1], [ignore], [])
|
||||
AT_CHECK([grep -i 'tc_4' stdout], [1], [ignore], [])
|
||||
|
||||
dnl Run all test cases from a test program.
|
||||
AT_CHECK([rm -rf top], [0], [], [])
|
||||
AT_CHECK([mkdir top], [0], [], [])
|
||||
AT_CHECK([cp TEST_HELPER_NO_S(tp_basic_sh) top])
|
||||
AT_DATA([top/Atffile],
|
||||
[Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: h_tp_basic_sh
|
||||
])
|
||||
AT_CHECK([cd top && atf-run], [1], [stdout], [stderr])
|
||||
CHECK_TPS_TCR(pass, passed, stdout)
|
||||
CHECK_TPS_TCR(fail, failed, stdout)
|
||||
CHECK_TPS_TCR(skip, skipped, stdout)
|
||||
CHECK_TPS_TCR(default, passed, stdout)
|
||||
|
||||
AT_CLEANUP()
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
2487
bootstrap/testsuite
2487
bootstrap/testsuite
File diff suppressed because it is too large
Load Diff
@ -74,11 +74,4 @@ m4_include(bootstrap/t_test_program_list.at)
|
||||
m4_include(bootstrap/t_test_program_compare.at)
|
||||
m4_include(bootstrap/t_subr_atf_check.at)
|
||||
|
||||
m4_if(ENABLE_TOOLS, yes, [
|
||||
m4_include(bootstrap/t_application_opts_args.at)
|
||||
m4_include(bootstrap/t_application_help.at)
|
||||
m4_include(bootstrap/t_atf_config.at)
|
||||
m4_include(bootstrap/t_atf_run.at)
|
||||
])
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
||||
|
301
configure
vendored
301
configure
vendored
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for Automated Testing Framework 0.19.
|
||||
# Generated by GNU Autoconf 2.69 for Automated Testing Framework 0.20.
|
||||
#
|
||||
# Report bugs to <atf-devel@NetBSD.org>.
|
||||
#
|
||||
@ -592,8 +592,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='Automated Testing Framework'
|
||||
PACKAGE_TARNAME='atf'
|
||||
PACKAGE_VERSION='0.19'
|
||||
PACKAGE_STRING='Automated Testing Framework 0.19'
|
||||
PACKAGE_VERSION='0.20'
|
||||
PACKAGE_STRING='Automated Testing Framework 0.20'
|
||||
PACKAGE_BUGREPORT='atf-devel@NetBSD.org'
|
||||
PACKAGE_URL='https://github.com/jmmv/atf/'
|
||||
|
||||
@ -642,19 +642,10 @@ GIT
|
||||
HAVE_KYUA_FALSE
|
||||
HAVE_KYUA_TRUE
|
||||
KYUA
|
||||
GDB
|
||||
ATF_SHELL
|
||||
atf_xsldir
|
||||
atf_pkgconfigdir
|
||||
atf_egdir
|
||||
atf_dtddir
|
||||
atf_cssdir
|
||||
atf_aclocaldir
|
||||
ATF_WORKDIR
|
||||
atf_confdir
|
||||
ATF_CONFSUBDIR
|
||||
atf_machine
|
||||
atf_arch
|
||||
target_srcdir
|
||||
ATF_BUILD_CXXFLAGS
|
||||
ATF_BUILD_CXX
|
||||
@ -672,9 +663,6 @@ CXXDEPMODE
|
||||
ac_ct_CXX
|
||||
CXXFLAGS
|
||||
CXX
|
||||
ENABLE_TOOLS_FALSE
|
||||
ENABLE_TOOLS_TRUE
|
||||
ENABLE_TOOLS
|
||||
CPP
|
||||
OTOOL64
|
||||
OTOOL
|
||||
@ -803,7 +791,6 @@ enable_fast_install
|
||||
with_gnu_ld
|
||||
with_sysroot
|
||||
enable_libtool_lock
|
||||
enable_tools
|
||||
enable_developer
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
@ -825,7 +812,6 @@ ATF_BUILD_CPP
|
||||
ATF_BUILD_CPPFLAGS
|
||||
ATF_BUILD_CXX
|
||||
ATF_BUILD_CXXFLAGS
|
||||
ATF_CONFSUBDIR
|
||||
ATF_WORKDIR
|
||||
ATF_SHELL'
|
||||
|
||||
@ -1368,7 +1354,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures Automated Testing Framework 0.19 to adapt to many kinds of systems.
|
||||
\`configure' configures Automated Testing Framework 0.20 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@ -1439,7 +1425,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of Automated Testing Framework 0.19:";;
|
||||
short | recursive ) echo "Configuration of Automated Testing Framework 0.20:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@ -1458,7 +1444,6 @@ Optional Features:
|
||||
--enable-fast-install[=PKGS]
|
||||
optimize for fast installation [default=yes]
|
||||
--disable-libtool-lock avoid locking (might break parallel builds)
|
||||
--enable-tools Enables the build of the deprecated ATF tools
|
||||
--enable-developer enable developer features
|
||||
|
||||
Optional Packages:
|
||||
@ -1494,8 +1479,6 @@ Some influential environment variables:
|
||||
C++ compiler to use at runtime
|
||||
ATF_BUILD_CXXFLAGS
|
||||
C++ compiler flags to use at runtime
|
||||
ATF_CONFSUBDIR
|
||||
Subdirectory of sysconfdir under which to look for files
|
||||
ATF_WORKDIR Default location to use for ATF work directories
|
||||
ATF_SHELL Location of the POSIX shell interpreter to use
|
||||
|
||||
@ -1566,7 +1549,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
Automated Testing Framework configure 0.19
|
||||
Automated Testing Framework configure 0.20
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@ -2072,65 +2055,11 @@ $as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_cxx_check_func
|
||||
|
||||
# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES
|
||||
# ---------------------------------------------
|
||||
# Tests whether TYPE exists after having included INCLUDES, setting cache
|
||||
# variable VAR accordingly.
|
||||
ac_fn_cxx_check_type ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
|
||||
$as_echo_n "checking for $2... " >&6; }
|
||||
if eval \${$3+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
eval "$3=no"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$4
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (sizeof ($2))
|
||||
return 0;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$4
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (sizeof (($2)))
|
||||
return 0;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
|
||||
else
|
||||
eval "$3=yes"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
eval ac_res=\$$3
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
|
||||
} # ac_fn_cxx_check_type
|
||||
cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by Automated Testing Framework $as_me 0.19, which was
|
||||
It was created by Automated Testing Framework $as_me 0.20, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@ -3116,7 +3045,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='atf'
|
||||
VERSION='0.19'
|
||||
VERSION='0.20'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@ -11931,27 +11860,6 @@ CC="$lt_save_CC"
|
||||
|
||||
|
||||
|
||||
# Check whether --enable-tools was given.
|
||||
if test "${enable_tools+set}" = set; then :
|
||||
enableval=$enable_tools; case $enableval in
|
||||
yes|no) enable_tools=${enableval} ;;
|
||||
*) as_fn_error $? "Invalid value passed to --enable-tools" "$LINENO" 5 ;;
|
||||
esac
|
||||
else
|
||||
enable_tools=no
|
||||
fi
|
||||
|
||||
ENABLE_TOOLS=${enable_tools}
|
||||
|
||||
if test "${enable_tools}" = yes; then
|
||||
ENABLE_TOOLS_TRUE=
|
||||
ENABLE_TOOLS_FALSE='#'
|
||||
else
|
||||
ENABLE_TOOLS_TRUE='#'
|
||||
ENABLE_TOOLS_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
@ -17061,102 +16969,6 @@ $as_echo "#define HAVE_GETCWD_DYN 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the last valid signal" >&5
|
||||
$as_echo_n "checking for the last valid signal... " >&6; }
|
||||
if ${kyua_cv_signal_lastno+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
if test "$cross_compiling" = yes; then :
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "cannot run test program while cross compiling
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
int i;
|
||||
FILE *f;
|
||||
|
||||
i = 0;
|
||||
while (i < 1024) {
|
||||
i++;
|
||||
if (i != SIGKILL && i != SIGSTOP) {
|
||||
struct sigaction sa;
|
||||
int ret;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
ret = sigaction(i, &sa, NULL);
|
||||
if (ret == -1) {
|
||||
if (errno == EINVAL) {
|
||||
i--;
|
||||
break;
|
||||
} else
|
||||
err(EXIT_FAILURE, "sigaction failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 100)
|
||||
errx(EXIT_FAILURE, "too much signals");
|
||||
|
||||
f = fopen("conftest.cnt", "w");
|
||||
if (f == NULL)
|
||||
err(EXIT_FAILURE, "failed to open file");
|
||||
|
||||
fprintf(f, "%d\n", i);
|
||||
fclose(f);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_run "$LINENO"; then :
|
||||
if test ! -f conftest.cnt; then
|
||||
kyua_cv_signal_lastno=15
|
||||
else
|
||||
kyua_cv_signal_lastno=$(cat conftest.cnt)
|
||||
rm -f conftest.cnt
|
||||
fi
|
||||
else
|
||||
kyua_cv_signal_lastno=15
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $kyua_cv_signal_lastno" >&5
|
||||
$as_echo "$kyua_cv_signal_lastno" >&6; }
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define LAST_SIGNO ${kyua_cv_signal_lastno}
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
ac_fn_cxx_check_type "$LINENO" "timer_t" "ac_cv_type_timer_t" "#include <time.h>
|
||||
"
|
||||
if test "x$ac_cv_type_timer_t" = xyes; then :
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
test x"${ATF_BUILD_CC-unset}" = x"unset" && ATF_BUILD_CC="${CC}"
|
||||
@ -17197,37 +17009,6 @@ fi
|
||||
|
||||
|
||||
|
||||
atf_arch=`uname -p`
|
||||
atf_machine=`uname -m`
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: Machine type: ${atf_machine}, architecture: ${atf_arch}" >&5
|
||||
$as_echo "$as_me: Machine type: ${atf_machine}, architecture: ${atf_arch}" >&6;}
|
||||
atf_arch=${atf_arch}
|
||||
|
||||
atf_machine=${atf_machine}
|
||||
|
||||
|
||||
|
||||
|
||||
if test x"${ATF_CONFSUBDIR-unset}" = x"unset"; then
|
||||
ATF_CONFSUBDIR=atf
|
||||
else
|
||||
case ${ATF_CONFSUBDIR} in
|
||||
/*)
|
||||
as_fn_error $? "ATF_CONFSUBDIR must hold a relative path" "$LINENO" 5
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test x"${ATF_CONFSUBDIR}" = x""; then
|
||||
atf_confdir=\${sysconfdir}
|
||||
|
||||
else
|
||||
atf_confdir=\${sysconfdir}/${ATF_CONFSUBDIR}
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test x"${ATF_WORKDIR}" = x""; then
|
||||
for t in /tmp /var/tmp; do
|
||||
@ -17251,16 +17032,8 @@ fi
|
||||
|
||||
atf_aclocaldir=\${datadir}/aclocal
|
||||
|
||||
atf_cssdir=\${datadir}/examples/atf
|
||||
|
||||
atf_dtddir=\${datadir}/xml/atf
|
||||
|
||||
atf_egdir=\${datadir}/examples/atf
|
||||
|
||||
atf_pkgconfigdir=\${libdir}/pkgconfig
|
||||
|
||||
atf_xsldir=\${datadir}/xsl/atf
|
||||
|
||||
|
||||
|
||||
|
||||
@ -17324,46 +17097,6 @@ if test x"${ATF_SHELL}" = x""; then
|
||||
fi
|
||||
|
||||
|
||||
# Extract the first word of "gdb", so it can be a program name with args.
|
||||
set dummy gdb; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_GDB+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $GDB in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_GDB="$GDB" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_GDB="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
GDB=$ac_cv_path_GDB
|
||||
if test -n "$GDB"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDB" >&5
|
||||
$as_echo "$GDB" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
# Extract the first word of "kyua", so it can be a program name with args.
|
||||
set dummy kyua; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
@ -17454,7 +17187,7 @@ fi
|
||||
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile atf-c/defs.h tools/defs.hpp"
|
||||
ac_config_files="$ac_config_files Makefile atf-c/defs.h"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@ -17589,10 +17322,6 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
|
||||
as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${ENABLE_TOOLS_TRUE}" && test -z "${ENABLE_TOOLS_FALSE}"; then
|
||||
as_fn_error $? "conditional \"ENABLE_TOOLS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
|
||||
as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
@ -18002,7 +17731,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by Automated Testing Framework $as_me 0.19, which was
|
||||
This file was extended by Automated Testing Framework $as_me 0.20, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@ -18069,7 +17798,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
Automated Testing Framework config.status 0.19
|
||||
Automated Testing Framework config.status 0.20
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
@ -18580,7 +18309,6 @@ do
|
||||
"libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
|
||||
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
|
||||
"atf-c/defs.h") CONFIG_FILES="$CONFIG_FILES atf-c/defs.h" ;;
|
||||
"tools/defs.hpp") CONFIG_FILES="$CONFIG_FILES tools/defs.hpp" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
@ -20128,10 +19856,3 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
|
||||
fi
|
||||
|
||||
|
||||
if test ${enable_tools} = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building the deprecated ATF tools (atf-run and atf-report);" >&5
|
||||
$as_echo "$as_me: WARNING: Building the deprecated ATF tools (atf-run and atf-report);" >&2;}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: please migrate to Kyua as soon as feasible." >&5
|
||||
$as_echo "$as_me: WARNING: please migrate to Kyua as soon as feasible." >&2;}
|
||||
fi
|
||||
|
||||
|
58
configure.ac
58
configure.ac
@ -31,7 +31,7 @@ dnl -----------------------------------------------------------------------
|
||||
dnl Initialize the GNU build system.
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
AC_INIT([Automated Testing Framework], [0.19], [atf-devel@NetBSD.org], [atf],
|
||||
AC_INIT([Automated Testing Framework], [0.20], [atf-devel@NetBSD.org], [atf],
|
||||
[https://github.com/jmmv/atf/])
|
||||
AC_PREREQ([2.65])
|
||||
AC_COPYRIGHT([Copyright (c) 2007-2012 The NetBSD Foundation, Inc.])
|
||||
@ -51,17 +51,6 @@ AM_INIT_AUTOMAKE([1.9 check-news foreign subdir-objects -Wall])
|
||||
AM_PROG_AR
|
||||
LT_INIT
|
||||
|
||||
AC_ARG_ENABLE(tools,
|
||||
AS_HELP_STRING([--enable-tools],
|
||||
[Enables the build of the deprecated ATF tools]),
|
||||
[case $enableval in
|
||||
yes|no) enable_tools=${enableval} ;;
|
||||
*) AC_MSG_ERROR([Invalid value passed to --enable-tools]) ;;
|
||||
esac],
|
||||
[enable_tools=no])
|
||||
AC_SUBST([ENABLE_TOOLS], ${enable_tools})
|
||||
AM_CONDITIONAL([ENABLE_TOOLS], [test "${enable_tools}" = yes])
|
||||
|
||||
dnl -----------------------------------------------------------------------
|
||||
dnl Check for the C and C++ compilers and required features.
|
||||
dnl -----------------------------------------------------------------------
|
||||
@ -91,9 +80,6 @@ ATF_MODULE_APPLICATION
|
||||
ATF_MODULE_DEFS
|
||||
ATF_MODULE_ENV
|
||||
ATF_MODULE_FS
|
||||
ATF_MODULE_SIGNALS
|
||||
|
||||
AC_CHECK_TYPE([timer_t], [], [], [[#include <time.h>]])
|
||||
|
||||
ATF_RUNTIME_TOOL([ATF_BUILD_CC],
|
||||
[C compiler to use at runtime], [${CC}])
|
||||
@ -122,40 +108,10 @@ else
|
||||
fi
|
||||
AC_SUBST([target_srcdir])
|
||||
|
||||
dnl -----------------------------------------------------------------------
|
||||
dnl Architecture and machine checks.
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
atf_arch=`uname -p`
|
||||
atf_machine=`uname -m`
|
||||
|
||||
AC_MSG_NOTICE([Machine type: ${atf_machine}, architecture: ${atf_arch}])
|
||||
AC_SUBST(atf_arch, ${atf_arch})
|
||||
AC_SUBST(atf_machine, ${atf_machine})
|
||||
|
||||
dnl -----------------------------------------------------------------------
|
||||
dnl User-customizable variables.
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
AC_ARG_VAR([ATF_CONFSUBDIR],
|
||||
[Subdirectory of sysconfdir under which to look for files])
|
||||
if test x"${ATF_CONFSUBDIR-unset}" = x"unset"; then
|
||||
ATF_CONFSUBDIR=atf
|
||||
else
|
||||
case ${ATF_CONFSUBDIR} in
|
||||
/*)
|
||||
AC_MSG_ERROR([ATF_CONFSUBDIR must hold a relative path])
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test x"${ATF_CONFSUBDIR}" = x""; then
|
||||
AC_SUBST(atf_confdir, \${sysconfdir})
|
||||
else
|
||||
AC_SUBST(atf_confdir, \${sysconfdir}/${ATF_CONFSUBDIR})
|
||||
fi
|
||||
|
||||
AC_ARG_VAR([ATF_WORKDIR],
|
||||
[Default location to use for ATF work directories])
|
||||
if test x"${ATF_WORKDIR}" = x""; then
|
||||
@ -179,11 +135,7 @@ else
|
||||
fi
|
||||
|
||||
AC_SUBST(atf_aclocaldir, \${datadir}/aclocal)
|
||||
AC_SUBST(atf_cssdir, \${datadir}/examples/atf)
|
||||
AC_SUBST(atf_dtddir, \${datadir}/xml/atf)
|
||||
AC_SUBST(atf_egdir, \${datadir}/examples/atf)
|
||||
AC_SUBST(atf_pkgconfigdir, \${libdir}/pkgconfig)
|
||||
AC_SUBST(atf_xsldir, \${datadir}/xsl/atf)
|
||||
|
||||
dnl -----------------------------------------------------------------------
|
||||
dnl Check for the shell and portability problems.
|
||||
@ -209,7 +161,6 @@ dnl -----------------------------------------------------------------------
|
||||
dnl Check for required tools.
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
AC_PATH_PROG([GDB], [gdb])
|
||||
AC_PATH_PROG([KYUA], [kyua])
|
||||
AM_CONDITIONAL([HAVE_KYUA], [test -n "${KYUA}"])
|
||||
AC_PATH_PROG([GIT], [git])
|
||||
@ -218,11 +169,6 @@ dnl -----------------------------------------------------------------------
|
||||
dnl Finally, generate output.
|
||||
dnl -----------------------------------------------------------------------
|
||||
|
||||
AC_OUTPUT([Makefile atf-c/defs.h tools/defs.hpp])
|
||||
|
||||
if test ${enable_tools} = yes; then
|
||||
AC_MSG_WARN([Building the deprecated ATF tools (atf-run and atf-report);])
|
||||
AC_MSG_WARN([please migrate to Kyua as soon as feasible.])
|
||||
fi
|
||||
AC_OUTPUT([Makefile atf-c/defs.h])
|
||||
|
||||
dnl vim: syntax=m4:expandtab:shiftwidth=4:softtabstop=4
|
||||
|
@ -1,86 +0,0 @@
|
||||
dnl
|
||||
dnl Automated Testing Framework (atf)
|
||||
dnl
|
||||
dnl Copyright (c) 2008 The NetBSD Foundation, 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
|
||||
dnl are met:
|
||||
dnl 1. Redistributions of source code must retain the above copyright
|
||||
dnl notice, this list of conditions and the following disclaimer.
|
||||
dnl 2. 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
|
||||
dnl THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
dnl CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
dnl INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
dnl MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
dnl IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
dnl DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
dnl GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
dnl INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
dnl IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
dnl OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
dnl IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
dnl
|
||||
|
||||
AC_DEFUN([ATF_MODULE_SIGNALS], [
|
||||
AC_CACHE_CHECK(
|
||||
[for the last valid signal],
|
||||
[kyua_cv_signal_lastno], [
|
||||
AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>], [
|
||||
int i;
|
||||
FILE *f;
|
||||
|
||||
i = 0;
|
||||
while (i < 1024) {
|
||||
i++;
|
||||
if (i != SIGKILL && i != SIGSTOP) {
|
||||
struct sigaction sa;
|
||||
int ret;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
ret = sigaction(i, &sa, NULL);
|
||||
if (ret == -1) {
|
||||
if (errno == EINVAL) {
|
||||
i--;
|
||||
break;
|
||||
} else
|
||||
err(EXIT_FAILURE, "sigaction failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 100)
|
||||
errx(EXIT_FAILURE, "too much signals");
|
||||
|
||||
f = fopen("conftest.cnt", "w");
|
||||
if (f == NULL)
|
||||
err(EXIT_FAILURE, "failed to open file");
|
||||
|
||||
fprintf(f, "%d\n", i);
|
||||
fclose(f);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
])],
|
||||
[if test ! -f conftest.cnt; then
|
||||
kyua_cv_signal_lastno=15
|
||||
else
|
||||
kyua_cv_signal_lastno=$(cat conftest.cnt)
|
||||
rm -f conftest.cnt
|
||||
fi],
|
||||
[kyua_cv_signal_lastno=15])
|
||||
])
|
||||
AC_DEFINE_UNQUOTED([LAST_SIGNO], [${kyua_cv_signal_lastno}],
|
||||
[Define to the last valid signal number])
|
||||
])
|
@ -1,9 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: config_test
|
||||
tp: expect_test
|
||||
tp: meta_data_test
|
||||
tp: srcdir_test
|
||||
tp: result_test
|
@ -27,8 +27,7 @@
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
tests_test_programs_DATA = test-programs/Atffile \
|
||||
test-programs/Kyuafile
|
||||
tests_test_programs_DATA = test-programs/Kyuafile
|
||||
tests_test_programsdir = $(pkgtestsdir)/test-programs
|
||||
EXTRA_DIST += $(tests_test_programs_DATA)
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: atf-config_test
|
||||
tp: atf-report_test
|
||||
tp: atf-run_test
|
||||
tp: application_test
|
||||
tp: atffile_test
|
||||
tp: auto_array_test
|
||||
tp: config_test
|
||||
tp: config_file_test
|
||||
tp: env_test
|
||||
tp: expand_test
|
||||
tp: fs_test
|
||||
tp: io_test
|
||||
tp: parser_test
|
||||
tp: process_test
|
||||
tp: reader_test
|
||||
tp: requirements_test
|
||||
tp: signals_test
|
||||
tp: test_program_test
|
||||
tp: text_test
|
||||
tp: ui_test
|
||||
tp: user_test
|
@ -1,24 +0,0 @@
|
||||
syntax("kyuafile", 1)
|
||||
|
||||
test_suite("atf")
|
||||
|
||||
atf_test_program{name="atf-config_test"}
|
||||
atf_test_program{name="atf-report_test"}
|
||||
atf_test_program{name="atf-run_test"}
|
||||
atf_test_program{name="application_test"}
|
||||
atf_test_program{name="atffile_test"}
|
||||
atf_test_program{name="auto_array_test"}
|
||||
atf_test_program{name="config_test"}
|
||||
atf_test_program{name="config_file_test"}
|
||||
atf_test_program{name="env_test"}
|
||||
atf_test_program{name="expand_test"}
|
||||
atf_test_program{name="fs_test"}
|
||||
atf_test_program{name="io_test"}
|
||||
atf_test_program{name="parser_test"}
|
||||
atf_test_program{name="process_test"}
|
||||
atf_test_program{name="reader_test"}
|
||||
atf_test_program{name="requirements_test"}
|
||||
atf_test_program{name="signals_test"}
|
||||
atf_test_program{name="test_program_test"}
|
||||
atf_test_program{name="text_test"}
|
||||
atf_test_program{name="ui_test"}
|
@ -1,332 +0,0 @@
|
||||
#
|
||||
# Automated Testing Framework (atf)
|
||||
#
|
||||
# Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
TOOLS_CPPFLAGS = -I$(top_srcdir)/tools -I$(top_builddir)/tools
|
||||
TOOLS_LDADD = tools/libtools.a
|
||||
|
||||
noinst_LIBRARIES = tools/libtools.a
|
||||
tools_libtools_a_SOURCES = tools/application.cpp \
|
||||
tools/application.hpp \
|
||||
tools/atffile.cpp \
|
||||
tools/atffile.hpp \
|
||||
tools/auto_array.hpp \
|
||||
tools/config.cpp \
|
||||
tools/config.hpp \
|
||||
tools/config_file.cpp \
|
||||
tools/config_file.hpp \
|
||||
tools/env.cpp \
|
||||
tools/env.hpp \
|
||||
tools/exceptions.cpp \
|
||||
tools/exceptions.hpp \
|
||||
tools/expand.cpp \
|
||||
tools/expand.hpp \
|
||||
tools/fs.cpp \
|
||||
tools/fs.hpp \
|
||||
tools/io.cpp \
|
||||
tools/io.hpp \
|
||||
tools/parser.cpp \
|
||||
tools/parser.hpp \
|
||||
tools/process.cpp \
|
||||
tools/process.hpp \
|
||||
tools/reader.cpp \
|
||||
tools/reader.hpp \
|
||||
tools/requirements.cpp \
|
||||
tools/requirements.hpp \
|
||||
tools/signals.cpp \
|
||||
tools/signals.hpp \
|
||||
tools/test-program.cpp \
|
||||
tools/test-program.hpp \
|
||||
tools/test_helpers.hpp \
|
||||
tools/text.cpp \
|
||||
tools/text.hpp \
|
||||
tools/timers.cpp \
|
||||
tools/timers.hpp \
|
||||
tools/ui.cpp \
|
||||
tools/ui.hpp \
|
||||
tools/user.cpp \
|
||||
tools/user.hpp
|
||||
nodist_tools_libtools_a_SOURCES = tools/defs.hpp
|
||||
tools_libtools_a_CPPFLAGS = "-DATF_ARCH=\"$(atf_arch)\"" \
|
||||
"-DATF_BUILD_CC=\"$(ATF_BUILD_CC)\"" \
|
||||
"-DATF_BUILD_CFLAGS=\"$(ATF_BUILD_CFLAGS)\"" \
|
||||
"-DATF_BUILD_CPP=\"$(ATF_BUILD_CPP)\"" \
|
||||
"-DATF_BUILD_CPPFLAGS=\"$(ATF_BUILD_CPPFLAGS)\"" \
|
||||
"-DATF_BUILD_CXX=\"$(ATF_BUILD_CXX)\"" \
|
||||
"-DATF_BUILD_CXXFLAGS=\"$(ATF_BUILD_CXXFLAGS)\"" \
|
||||
"-DATF_CONFDIR=\"$(atf_confdir)\"" \
|
||||
"-DATF_INCLUDEDIR=\"$(includedir)\"" \
|
||||
"-DATF_LIBDIR=\"$(libdir)\"" \
|
||||
"-DATF_LIBEXECDIR=\"$(libexecdir)\"" \
|
||||
"-DATF_MACHINE=\"$(atf_machine)\"" \
|
||||
"-DATF_PKGDATADIR=\"$(pkgdatadir)\"" \
|
||||
"-DATF_SHELL=\"$(ATF_SHELL)\"" \
|
||||
"-DATF_WORKDIR=\"$(ATF_WORKDIR)\"" \
|
||||
$(TOOLS_CPPFLAGS)
|
||||
|
||||
# XXX For some reason, the nodist line above does not work as expected.
|
||||
# Work this problem around.
|
||||
DIST_HOOKS += kill-defs-hpp
|
||||
kill-defs-hpp:
|
||||
rm -f $(distdir)/tools/defs.hpp
|
||||
|
||||
|
||||
|
||||
bin_PROGRAMS += tools/atf-config
|
||||
tools_atf_config_SOURCES = tools/atf-config.cpp
|
||||
tools_atf_config_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_atf_config_LDADD = $(TOOLS_LDADD)
|
||||
dist_man_MANS += tools/atf-config.1
|
||||
|
||||
bin_PROGRAMS += tools/atf-report
|
||||
tools_atf_report_SOURCES = tools/atf-report.cpp
|
||||
tools_atf_report_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_atf_report_LDADD = $(TOOLS_LDADD)
|
||||
dist_man_MANS += tools/atf-report.1
|
||||
|
||||
bin_PROGRAMS += tools/atf-run
|
||||
tools_atf_run_CPPFLAGS = $(TOOLS_CPPFLAGS) "-DGDB=\"$(GDB)\""
|
||||
tools_atf_run_SOURCES = tools/atf-run.cpp
|
||||
tools_atf_run_LDADD = $(TOOLS_LDADD)
|
||||
dist_man_MANS += tools/atf-run.1
|
||||
|
||||
bin_PROGRAMS += tools/atf-version
|
||||
tools_atf_version_SOURCES = tools/atf-version.cpp
|
||||
nodist_tools_atf_version_SOURCES = tools/revision.h
|
||||
tools_atf_version_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_atf_version_LDADD = $(TOOLS_LDADD)
|
||||
dist_man_MANS += tools/atf-version.1
|
||||
|
||||
EXTRA_DIST += tools/generate-revision.sh
|
||||
|
||||
BUILT_SOURCES += tools/revision.h
|
||||
CLEANFILES += tools/revision.h
|
||||
tools/revision.h: tools/revision.h.stamp
|
||||
@test -d tools || mkdir -p tools
|
||||
@cmp -s tools/revision.h tools/revision.h.stamp || \
|
||||
cp -p tools/revision.h.stamp tools/revision.h
|
||||
|
||||
CLEANFILES += tools/revision.h.stamp
|
||||
PHONY_TARGETS += tools/revision.h.stamp
|
||||
tools/revision.h.stamp:
|
||||
@test -d tools || mkdir -p tools
|
||||
@$(top_srcdir)/tools/generate-revision.sh \
|
||||
-g "$(GIT)" -r $(top_srcdir) -o tools/revision.h.stamp \
|
||||
-v $(PACKAGE_VERSION)
|
||||
|
||||
|
||||
|
||||
man_MANS += tools/atf.7
|
||||
CLEANFILES += tools/atf.7
|
||||
EXTRA_DIST += tools/atf.7.in
|
||||
|
||||
dist_man_MANS += tools/atf-formats.5
|
||||
|
||||
tools/atf.7: $(srcdir)/tools/atf.7.in
|
||||
test -d tools || mkdir -p tools
|
||||
sed -e 's#__DOCDIR__#$(docdir)#g' \
|
||||
-e 's#__TESTSDIR__#$(testsdir)#g' \
|
||||
<$(srcdir)/tools/atf.7.in >tools/atf.7.tmp
|
||||
mv tools/atf.7.tmp tools/atf.7
|
||||
|
||||
|
||||
|
||||
cssdir = $(atf_cssdir)
|
||||
css_DATA = tools/tests-results.css
|
||||
EXTRA_DIST += $(css_DATA)
|
||||
|
||||
dtddir = $(atf_dtddir)
|
||||
dtd_DATA = tools/tests-results.dtd
|
||||
EXTRA_DIST += $(dtd_DATA)
|
||||
|
||||
egdir = $(atf_egdir)
|
||||
eg_DATA = tools/sample/atf-run.hooks
|
||||
eg_DATA += tools/sample/common.conf
|
||||
EXTRA_DIST += $(eg_DATA)
|
||||
|
||||
hooksdir = $(pkgdatadir)
|
||||
hooks_DATA = tools/share/atf-run.hooks
|
||||
EXTRA_DIST += $(hooks_DATA)
|
||||
|
||||
xsldir = $(atf_xsldir)
|
||||
xsl_DATA = tools/tests-results.xsl
|
||||
EXTRA_DIST += $(xsl_DATA)
|
||||
|
||||
|
||||
|
||||
tests_tools_DATA = tools/Atffile tools/Kyuafile
|
||||
tests_toolsdir = $(pkgtestsdir)/tools
|
||||
EXTRA_DIST += $(tests_tools_DATA)
|
||||
|
||||
tests_tools_SCRIPTS = tools/atf-config_test
|
||||
CLEANFILES += tools/atf-config_test
|
||||
EXTRA_DIST += tools/atf-config_test.sh
|
||||
tools/atf-config_test: $(srcdir)/tools/atf-config_test.sh
|
||||
@test -d tools || mkdir -p tools
|
||||
@src="$(srcdir)/tools/atf-config_test.sh"; \
|
||||
dst="tools/atf-config_test"; $(BUILD_SH_TP)
|
||||
|
||||
tests_tools_SCRIPTS += tools/atf-report_test
|
||||
CLEANFILES += tools/atf-report_test
|
||||
EXTRA_DIST += tools/atf-report_test.sh
|
||||
tools/atf-report_test: $(srcdir)/tools/atf-report_test.sh
|
||||
@test -d tools || mkdir -p tools
|
||||
@src="$(srcdir)/tools/atf-report_test.sh"; \
|
||||
dst="tools/atf-report_test"; $(BUILD_SH_TP)
|
||||
|
||||
tests_tools_SCRIPTS += tools/atf-run_test
|
||||
CLEANFILES += tools/atf-run_test
|
||||
EXTRA_DIST += tools/atf-run_test.sh
|
||||
tools/atf-run_test: $(srcdir)/tools/atf-run_test.sh
|
||||
@test -d tools || mkdir -p tools
|
||||
@src="$(srcdir)/tools/atf-run_test.sh"; \
|
||||
dst="tools/atf-run_test"; $(BUILD_SH_TP)
|
||||
|
||||
tests_tools_PROGRAMS = tools/application_test
|
||||
tools_application_test_SOURCES = tools/application_test.cpp
|
||||
tools_application_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_application_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/atffile_test
|
||||
tools_atffile_test_SOURCES = tools/atffile_test.cpp
|
||||
tools_atffile_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_atffile_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/auto_array_test
|
||||
tools_auto_array_test_SOURCES = tools/auto_array_test.cpp
|
||||
tools_auto_array_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_auto_array_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/bad_metadata_helper
|
||||
tools_bad_metadata_helper_SOURCES = tools/bad_metadata_helper.c
|
||||
tools_bad_metadata_helper_LDADD = libatf-c.la
|
||||
|
||||
tests_tools_PROGRAMS += tools/config_test
|
||||
tools_config_test_SOURCES = tools/config_test.cpp
|
||||
tools_config_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_config_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/config_file_test
|
||||
tools_config_file_test_SOURCES = tools/config_file_test.cpp
|
||||
tools_config_file_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_config_file_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/env_test
|
||||
tools_env_test_SOURCES = tools/env_test.cpp
|
||||
tools_env_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_env_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/expand_test
|
||||
tools_expand_test_SOURCES = tools/expand_test.cpp
|
||||
tools_expand_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_expand_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/expect_helpers
|
||||
tools_expect_helpers_SOURCES = tools/expect_helpers.c
|
||||
tools_expect_helpers_LDADD = libatf-c.la
|
||||
|
||||
tests_tools_PROGRAMS += tools/fail_helper
|
||||
tools_fail_helper_SOURCES = tools/fail_helper.cpp
|
||||
tools_fail_helper_LDADD = $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/fs_test
|
||||
tools_fs_test_SOURCES = tools/fs_test.cpp
|
||||
tools_fs_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_fs_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/io_test
|
||||
tools_io_test_SOURCES = tools/io_test.cpp
|
||||
tools_io_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_io_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/misc_helpers
|
||||
tools_misc_helpers_SOURCES = tools/misc_helpers.cpp
|
||||
tools_misc_helpers_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_misc_helpers_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/parser_test
|
||||
tools_parser_test_SOURCES = tools/parser_test.cpp
|
||||
tools_parser_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_parser_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/process_test
|
||||
tools_process_test_SOURCES = tools/process_test.cpp
|
||||
tools_process_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_process_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/pass_helper
|
||||
tools_pass_helper_SOURCES = tools/pass_helper.cpp
|
||||
tools_pass_helper_LDADD = $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/process_helpers
|
||||
tools_process_helpers_SOURCES = tools/process_helpers.c
|
||||
|
||||
tests_tools_PROGRAMS += tools/reader_test
|
||||
tools_reader_test_SOURCES = tools/reader_test.cpp
|
||||
tools_reader_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_reader_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/requirements_test
|
||||
tools_requirements_test_SOURCES = tools/requirements_test.cpp
|
||||
tools_requirements_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_requirements_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/several_tcs_helper
|
||||
tools_several_tcs_helper_SOURCES = tools/several_tcs_helper.c
|
||||
tools_several_tcs_helper_LDADD = libatf-c.la
|
||||
|
||||
tests_tools_PROGRAMS += tools/signals_test
|
||||
tools_signals_test_SOURCES = tools/signals_test.cpp tools/signals.cpp
|
||||
tools_signals_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_signals_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/test_program_test
|
||||
tools_test_program_test_SOURCES = tools/test_program_test.cpp
|
||||
tools_test_program_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_test_program_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/text_test
|
||||
tools_text_test_SOURCES = tools/text_test.cpp tools/text.cpp
|
||||
tools_text_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_text_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/ui_test
|
||||
tools_ui_test_SOURCES = tools/ui_test.cpp tools/ui.cpp
|
||||
tools_ui_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_ui_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/user_test
|
||||
tools_user_test_SOURCES = tools/user_test.cpp tools/user.cpp
|
||||
tools_user_test_CPPFLAGS = $(TOOLS_CPPFLAGS)
|
||||
tools_user_test_LDADD = $(TOOLS_LDADD) $(ATF_CXX_LIBS)
|
||||
|
||||
tests_tools_PROGRAMS += tools/zero_tcs_helper
|
||||
tools_zero_tcs_helper_SOURCES = tools/zero_tcs_helper.c
|
||||
tools_zero_tcs_helper_LDADD = libatf-c.la
|
||||
|
||||
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8
|
@ -1,317 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "bconfig.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "defs.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
#if !defined(HAVE_VSNPRINTF_IN_STD)
|
||||
namespace std {
|
||||
using ::vsnprintf;
|
||||
}
|
||||
#endif // !defined(HAVE_VSNPRINTF_IN_STD)
|
||||
|
||||
namespace impl = tools::application;
|
||||
#define IMPL_NAME "tools::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) :
|
||||
m_hflag(false),
|
||||
m_argc(-1),
|
||||
m_argv(NULL),
|
||||
m_prog_name(NULL),
|
||||
m_description(description),
|
||||
m_manpage(manpage),
|
||||
m_global_manpage(global_manpage)
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
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)
|
||||
{
|
||||
assert(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':
|
||||
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)
|
||||
{
|
||||
assert(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();
|
||||
assert(!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)
|
||||
{
|
||||
assert(argc > 0);
|
||||
assert(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) {
|
||||
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) {
|
||||
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";
|
||||
errcode = EXIT_FAILURE;
|
||||
} catch (const std::runtime_error& e) {
|
||||
std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
|
||||
<< "\n";
|
||||
errcode = EXIT_FAILURE;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << ui::format_error(m_prog_name, std::string("Caught "
|
||||
"unexpected error: ") + e.what() + "\n" + bug) << "\n";
|
||||
errcode = EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
std::cerr << ui::format_error(m_prog_name, std::string("Caught "
|
||||
"unknown error\n") + bug) << "\n";
|
||||
errcode = EXIT_FAILURE;
|
||||
}
|
||||
return errcode;
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_APPLICATION_HPP)
|
||||
#define TOOLS_APPLICATION_HPP
|
||||
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
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;
|
||||
|
||||
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&);
|
||||
virtual ~app(void);
|
||||
|
||||
int run(int, char* const*);
|
||||
};
|
||||
|
||||
} // namespace application
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_APPLICATION_HPP)
|
@ -1,94 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "application.hpp"
|
||||
|
||||
class getopt_app : public tools::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);
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd March 14, 2009
|
||||
.Dt ATF-CONFIG 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm atf-config
|
||||
.Nd queries static configuration information of ATF
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl t
|
||||
.Op Ar var1 Op Ar .. varN
|
||||
.Nm
|
||||
.Fl h
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a utility that queries static configuration information of ATF.
|
||||
Static configuration refers to all those values for settings that
|
||||
were built into the ATF binaries at build time.
|
||||
.Pp
|
||||
In the first synopsis form,
|
||||
.Nm
|
||||
will print variable-value pairs for all built-in static variables if
|
||||
no variable names are provided as arguments.
|
||||
If any is provided, it will only print the variable-value pairs for
|
||||
those variables.
|
||||
The output of the utility does not use the
|
||||
.Sq =
|
||||
symbol to separate the variable name from its corresponding value in
|
||||
an attempt to avoid sourcing the output in shell scripts or Makefiles.
|
||||
If you need to do that, the
|
||||
.Fl t
|
||||
flag allows you to query the value of individual variables without any
|
||||
surrounding text.
|
||||
.Pp
|
||||
In the second synopsis form,
|
||||
.Nm
|
||||
will print information about all supported options and their purpose.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width flag
|
||||
.It Fl h
|
||||
Shows a short summary of all available options and their purpose.
|
||||
.It Fl t
|
||||
Changes the output of the utility to show the variable values, one
|
||||
per line, without the variable names.
|
||||
.El
|
||||
.Ss Static configuration variables
|
||||
The following list describes all the variables that are part of ATF's
|
||||
static configuration:
|
||||
.Bl -tag -width atfXbuildXcppflagsXX
|
||||
.It Va atf_arch
|
||||
The architecture name detected by ATF.
|
||||
This is derived from
|
||||
.Va atf_machine
|
||||
because it is a subset of it.
|
||||
Given that this name might be misdetected, it is provided to the user
|
||||
as a configuration variable so that he can fix its value temporarily
|
||||
until a real fix is incorporated into mainstream sources.
|
||||
.It Va atf_build_cc
|
||||
The C compiler used by the ATF checks that provide build-time tests.
|
||||
.It Va atf_build_cflags
|
||||
The C compiler flags used by the ATF checks that provide build-time tests.
|
||||
.It Va atf_build_cpp
|
||||
The C/C++ preprocessor used by the ATF checks that provide build-time tests.
|
||||
.It Va atf_build_cppflags
|
||||
The C/C++ preprocessor flags used by the ATF checks that provide build-time
|
||||
tests.
|
||||
.It Va atf_build_cxx
|
||||
The C++ compiler used by the ATF checks that provide build-time tests.
|
||||
.It Va atf_build_cxxflags
|
||||
The C++ compiler flags used by the ATF checks that provide build-time tests.
|
||||
.It Va atf_confdir
|
||||
The path to the directory that contains the system-wide configuration
|
||||
files for ATF.
|
||||
.It Va atf_includedir
|
||||
The path to the directory that contains the ATF header files.
|
||||
.It Va atf_libdir
|
||||
The path to the directory that contains the ATF libraries.
|
||||
.It Va atf_libexecdir
|
||||
The path to the directory that contains the auxiliary utilities of ATF,
|
||||
used internally by the public tools.
|
||||
.It Va atf_machine
|
||||
The machine type name detected by ATF.
|
||||
This should not be tunable but is provided for symmetry with
|
||||
.Va atf_arch .
|
||||
.It Va atf_pkgdatadir
|
||||
The path to the directory that contains the files that form the ATF's
|
||||
shell-scripting library.
|
||||
.It Va atf_shell
|
||||
The path to the shell interpreter that will be used by ATF.
|
||||
.It Va atf_workdir
|
||||
The path to the temporary directory that the utilities and the test
|
||||
programs will use to store temporary files in.
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
Every variable that is part of the static configuration can be
|
||||
overridden at run-time by defining an environment variable.
|
||||
This environment variable has the exact same name as the one shown by
|
||||
.Nm
|
||||
except that the name is all composed of uppercase letters.
|
||||
.Pp
|
||||
In general, empty values in the environment will be ignored unless
|
||||
otherwise noted below.
|
||||
.Pp
|
||||
The recognized environment variables are:
|
||||
.Bl -tag -width ATFXBUILDXCPPFLAGSXX
|
||||
.It Ev ATF_ARCH
|
||||
Overrides the built-in value of
|
||||
.Va atf_arch .
|
||||
.It Ev ATF_BUILD_CC
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cc .
|
||||
.It Ev ATF_BUILD_CFLAGS
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cflags .
|
||||
Empty values are allowed.
|
||||
.It Ev ATF_BUILD_CPP
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cpp .
|
||||
.It Ev ATF_BUILD_CPPFLAGS
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cppflags .
|
||||
Empty values are allowed.
|
||||
.It Ev ATF_BUILD_CXX
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cxx .
|
||||
.It Ev ATF_BUILD_CXXFLAGS
|
||||
Overrides the built-in value of
|
||||
.Va atf_build_cxxflags .
|
||||
Empty values are allowed.
|
||||
.It Ev ATF_CONFDIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_confdir .
|
||||
.It Ev ATF_INCLUDEDIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_includedir .
|
||||
.It Ev ATF_LIBDIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_libdir .
|
||||
.It Ev ATF_LIBEXECDIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_libexecdir .
|
||||
.It Ev ATF_MACHINE
|
||||
Overrides the built-in value of
|
||||
.Va atf_machine .
|
||||
.It Ev ATF_PKGDATADIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_pkgdatadir .
|
||||
.It Ev ATF_SHELL
|
||||
Overrides the built-in value of
|
||||
.Va atf_shell .
|
||||
.It Ev ATF_WORKDIR
|
||||
Overrides the built-in value of
|
||||
.Va atf_workdir .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr atf 7
|
@ -1,140 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "config.hpp"
|
||||
#include "defs.hpp"
|
||||
|
||||
class atf_config : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
bool m_tflag;
|
||||
|
||||
void process_option(int, const char*);
|
||||
std::string specific_args(void) const;
|
||||
options_set specific_options(void) const;
|
||||
|
||||
std::string format_var(const std::string&, const std::string&);
|
||||
|
||||
public:
|
||||
atf_config(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
const char* atf_config::m_description =
|
||||
"atf-config is a tool that queries the value of several "
|
||||
"installation-specific configuration values of the atf. "
|
||||
"It can be used by external tools to discover where specific "
|
||||
"internal atf files are installed.";
|
||||
|
||||
atf_config::atf_config(void) :
|
||||
app(m_description, "atf-config(1)", "atf(7)"),
|
||||
m_tflag(false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
atf_config::process_option(int ch, const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
switch (ch) {
|
||||
case 't':
|
||||
m_tflag = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
atf_config::specific_args(void)
|
||||
const
|
||||
{
|
||||
return "[var1 [.. varN]]";
|
||||
}
|
||||
|
||||
atf_config::options_set
|
||||
atf_config::specific_options(void)
|
||||
const
|
||||
{
|
||||
using tools::application::option;
|
||||
options_set opts;
|
||||
opts.insert(option('t', "", "Terse output: show values only"));
|
||||
return opts;
|
||||
}
|
||||
|
||||
std::string
|
||||
atf_config::format_var(const std::string& name, const std::string& val)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
if (m_tflag)
|
||||
str = val;
|
||||
else
|
||||
str = name + " : " + val;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int
|
||||
atf_config::main(void)
|
||||
{
|
||||
if (m_argc < 1) {
|
||||
std::map< std::string, std::string > cv = tools::config::get_all();
|
||||
|
||||
for (std::map< std::string, std::string >::const_iterator iter =
|
||||
cv.begin(); iter != cv.end(); iter++)
|
||||
std::cout << format_var((*iter).first, (*iter).second) << "\n";
|
||||
} else {
|
||||
for (int i = 0; i < m_argc; i++) {
|
||||
if (!tools::config::has(m_argv[i]))
|
||||
throw std::runtime_error(std::string("Unknown variable `") +
|
||||
m_argv[i] + "'");
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_argc; i++) {
|
||||
std::cout << format_var(m_argv[i], tools::config::get(m_argv[i]))
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return atf_config().run(argc, argv);
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
#
|
||||
# Automated Testing Framework (atf)
|
||||
#
|
||||
# Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
all_vars="atf_arch \
|
||||
atf_build_cc \
|
||||
atf_build_cflags \
|
||||
atf_build_cpp \
|
||||
atf_build_cppflags \
|
||||
atf_build_cxx \
|
||||
atf_build_cxxflags \
|
||||
atf_confdir \
|
||||
atf_includedir \
|
||||
atf_libdir \
|
||||
atf_libexecdir \
|
||||
atf_machine \
|
||||
atf_pkgdatadir \
|
||||
atf_shell \
|
||||
atf_workdir"
|
||||
all_vars_no=15
|
||||
|
||||
atf_test_case list_all
|
||||
list_all_head()
|
||||
{
|
||||
atf_set "descr" "Tests that at atf-config prints all expected" \
|
||||
"variables, and not more"
|
||||
}
|
||||
list_all_body()
|
||||
{
|
||||
atf_check -s eq:0 -o save:stdout -e empty atf-config
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l stdout | awk '{ print $1 }')" = "${all_vars_no}"
|
||||
for v in ${all_vars}; do
|
||||
atf_check -s eq:0 -o ignore -e empty grep "${v}" stdout
|
||||
done
|
||||
}
|
||||
|
||||
atf_test_case query_one
|
||||
query_one_head()
|
||||
{
|
||||
atf_set "descr" "Tests that querying a single variable works"
|
||||
}
|
||||
query_one_body()
|
||||
{
|
||||
for v in ${all_vars}; do
|
||||
atf_check -s eq:0 -o save:stdout -o match:"${v}" -e empty \
|
||||
atf-config "${v}"
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l stdout | awk '{ print $1 }')" = 1
|
||||
done
|
||||
}
|
||||
|
||||
atf_test_case query_one_terse
|
||||
query_one_terse_head()
|
||||
{
|
||||
atf_set "descr" "Tests that querying a single variable in terse mode" \
|
||||
"works"
|
||||
}
|
||||
query_one_terse_body()
|
||||
{
|
||||
for v in ${all_vars}; do
|
||||
atf_check -s eq:0 -o save:stdout -o match:"${v}" -e empty \
|
||||
atf-config "${v}"
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l stdout | awk '{ print $1 }')" = 1
|
||||
atf_check -s eq:0 -o save:stdout -e empty cut -d ' ' -f 3- stdout
|
||||
atf_check -s eq:0 -o empty -e empty mv stdout expout
|
||||
atf_check -s eq:0 -o file:expout -e empty atf-config -t "${v}"
|
||||
done
|
||||
}
|
||||
|
||||
atf_test_case query_multiple
|
||||
query_multiple_head()
|
||||
{
|
||||
atf_set "descr" "Tests that querying multiple variables works"
|
||||
}
|
||||
query_multiple_body()
|
||||
{
|
||||
atf_check -s eq:0 -o save:stdout -o match:'atf_libexecdir' \
|
||||
-o match:'atf_shell' -e empty atf-config atf_libexecdir atf_shell
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l stdout | awk '{ print $1 }')" = 2
|
||||
}
|
||||
|
||||
atf_test_case query_unknown
|
||||
query_unknown_head()
|
||||
{
|
||||
atf_set "descr" "Tests that querying an unknown variable delivers" \
|
||||
"the correct error"
|
||||
}
|
||||
query_unknown_body()
|
||||
{
|
||||
atf_check -s eq:1 -o empty -e match:'Unknown variable.*non_existent' \
|
||||
atf-config non_existent
|
||||
}
|
||||
|
||||
atf_test_case query_mixture
|
||||
query_mixture_head()
|
||||
{
|
||||
atf_set "descr" "Tests that querying a known and an unknown variable" \
|
||||
"delivers the correct error"
|
||||
}
|
||||
query_mixture_body()
|
||||
{
|
||||
for v in ${all_vars}; do
|
||||
atf_check -s eq:1 -o empty -e match:'Unknown variable.*non_existent' \
|
||||
atf-config "${v}" non_existent
|
||||
atf_check -s eq:1 -o empty -e match:'Unknown variable.*non_existent' \
|
||||
atf-config non_existent "${v}"
|
||||
done
|
||||
}
|
||||
|
||||
atf_test_case override_env
|
||||
override_env_head()
|
||||
{
|
||||
atf_set "descr" "Tests that build-time variables can be overriden" \
|
||||
"through their corresponding environment variables"
|
||||
}
|
||||
override_env_body()
|
||||
{
|
||||
for v in ${all_vars}; do
|
||||
V=$(echo ${v} | tr '[a-z]' '[A-Z]')
|
||||
atf_check -s eq:0 -o save:stdout -e empty -x "${V}=testval atf-config"
|
||||
atf_check -s eq:0 -o empty -e empty mv stdout all
|
||||
|
||||
atf_check -s eq:0 -o save:stdout -e empty grep "^${v} : " all
|
||||
atf_check -s eq:0 -o empty -e empty mv stdout affected
|
||||
atf_check -s eq:0 -o save:stdout -e empty grep -v "^${v} : " all
|
||||
atf_check -s eq:0 -o empty -e empty mv stdout unaffected
|
||||
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l affected | awk '{ print $1 }')" = 1
|
||||
atf_check -s eq:0 -o empty -e empty \
|
||||
test "$(wc -l unaffected | awk '{ print $1 }')" = \
|
||||
"$((${all_vars_no} -1))"
|
||||
|
||||
atf_check -s eq:0 -o ignore -e empty grep "^${v} : testval$" affected
|
||||
atf_check -s eq:1 -o empty -e empty grep ' : testval$' unaffected
|
||||
done
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case list_all
|
||||
|
||||
atf_add_test_case query_one
|
||||
atf_add_test_case query_one_terse
|
||||
atf_add_test_case query_multiple
|
||||
atf_add_test_case query_unknown
|
||||
atf_add_test_case query_mixture
|
||||
|
||||
atf_add_test_case override_env
|
||||
}
|
||||
|
||||
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
|
@ -1,231 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 20, 2011
|
||||
.Dt ATF-FORMATS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm atf-formats
|
||||
.Nd machine-parseable data formats used by ATF
|
||||
.Sh DESCRIPTION
|
||||
This manual page describes the multiple data formats used in ATF.
|
||||
These formats affect configuration files, control files and any data that
|
||||
is externalized or internalized by the tools.
|
||||
.Pp
|
||||
Data files are always organized as follows:
|
||||
.Bd -literal -offset indent
|
||||
Header1: Value1 \\
|
||||
... | head
|
||||
HeaderN: ValueN /
|
||||
mandatory blank line
|
||||
Free-form text contents \\
|
||||
... | body
|
||||
... /
|
||||
.Ed
|
||||
.Pp
|
||||
A file must always contain a
|
||||
.Sq Content-Type
|
||||
header and must always separate that header from the body with a blank
|
||||
line, even if the body is empty.
|
||||
.Pp
|
||||
The
|
||||
.Sq Content-Type
|
||||
is always of the form:
|
||||
.Bd -literal -offset indent
|
||||
Content-Type: application/X-atf-<subtype>; version="<version>"
|
||||
.Ed
|
||||
.Pp
|
||||
where
|
||||
.Sq subtype
|
||||
indicates the specific file format and
|
||||
.Sq version
|
||||
its format version.
|
||||
This header must be the first one of the file.
|
||||
.Pp
|
||||
The main purpose of the
|
||||
.Sq Content-Type
|
||||
header, aside from determining the format used in the file, is to allow
|
||||
future changes to a given format.
|
||||
Whenever an incompatible change is made, the version is bumped by one.
|
||||
By keeping the header in the first line, future versions may even remove
|
||||
the need for such a header -- e.g. if some format was replaced by XML
|
||||
files, which have their own mandatory header.
|
||||
.Pp
|
||||
The rest of this document details the different format types.
|
||||
.Ss Format: application/X-atf-atffile, version: 1
|
||||
Atffiles are logically divided into three sections:
|
||||
.Bl -bullet
|
||||
.It
|
||||
Test programs: the list of test programs that define the test suite
|
||||
described by the Atffile.
|
||||
.It
|
||||
Meta-data properties: these define some constant values applicable to
|
||||
all the test programs defined in the file.
|
||||
In some sense they define the properties that describe the test suite.
|
||||
.It
|
||||
Configuration variables: defaults for configuration variables that
|
||||
can be overridden through configuration files or the command line.
|
||||
.El
|
||||
.Pp
|
||||
The grammar for Atffiles is the following:
|
||||
.Bd -literal -offset indent
|
||||
DATA ::= ( ( CONF | PROP | TP )? COMMENT? NEWLINE )* EOF
|
||||
CONF ::= 'conf:' WORD EQUAL STRING
|
||||
PROP ::= 'prop:' WORD EQUAL STRING
|
||||
TP ::= TPFILE | TPGLOB
|
||||
TPFILE ::= 'tp: ' STRING
|
||||
TPGLOB ::= 'tp-glob: ' STRING
|
||||
STRING ::= WORD | '"' WORD* '"'
|
||||
.Ed
|
||||
.Pp
|
||||
The meaning of the constructions above is:
|
||||
.Bl -tag -width TPGLOBXX
|
||||
.It CONF
|
||||
Definition of a configuration variable.
|
||||
.It PROP
|
||||
Definition of a meta-data property.
|
||||
.It TPFILE
|
||||
Addition of a test program into the test suite.
|
||||
The string is taken literally as the program's name, and this program
|
||||
must exist.
|
||||
.It TPGLOB
|
||||
Addition of multiple test programs into the test suite.
|
||||
The string is taken as a glob pattern, which may have or not have any
|
||||
matches in the current directory.
|
||||
.El
|
||||
.Pp
|
||||
An example:
|
||||
.Bd -literal -offset indent
|
||||
prop: test-suite = utilities
|
||||
|
||||
conf: unprivileged-user = nobody
|
||||
|
||||
tp: t_cp
|
||||
tp: t_mv
|
||||
tp: t_df
|
||||
tp-glob: t_dir_*
|
||||
.Ed
|
||||
.Ss Format: application/X-atf-config, version: 1
|
||||
Configuration files are very simple: they only contain a list of variable
|
||||
name/variable value pairs.
|
||||
Their grammar is:
|
||||
.Bd -literal -offset indent
|
||||
DATA ::= ( VAR? COMMENT? NEWLINE )* EOF
|
||||
VAR ::= WORD EQUAL STRING
|
||||
COMMENT ::= HASH WORD*
|
||||
STRING ::= WORD | '"' WORD* '"'
|
||||
.Ed
|
||||
.Pp
|
||||
An example:
|
||||
.Bd -literal -offset indent
|
||||
# This is the system-wide configuration file for ATF.
|
||||
# The above and this line are comments placed on their own line.
|
||||
|
||||
var1 = this is a variable value
|
||||
var2 = this is another one # Optional comment at the end.
|
||||
.Ed
|
||||
.Ss Format: application/X-atf-tps, version: 3
|
||||
The
|
||||
.Sq application/X-atf-tps
|
||||
format multiplexes the standard output, standard error and results output
|
||||
streams from multiple test programs into a single data file.
|
||||
This format is used by
|
||||
.Xr atf-run 1
|
||||
to report the execution of several test programs and is later parsed by
|
||||
.Xr atf-report 1
|
||||
to inform the user of this process.
|
||||
It has the following grammar:
|
||||
.Bd -literal -offset indent
|
||||
DATA ::= INFO* TPS-COUNT TP-STANZA* INFO* EOF
|
||||
INFO ::= 'info' COLON STRING COMMA STRING NEWLINE
|
||||
TPS-COUNT ::= 'tps-count' COLON POSITIVE-NUMBER NEWLINE
|
||||
TP-STANZA ::= TP-START TC-STANZA* TC-END
|
||||
TP-START ::= 'tp-start' COLON TIMESTAMP COMMA STRING COMMA
|
||||
POSITIVE-NUMBER NEWLINE
|
||||
TP-END ::= 'tc-end' COLON TIMESTAMP COMMA STRING (COMMA STRING)?
|
||||
TC-STANZA ::= TC-START (TC-SO | TC-SE)* TC-END
|
||||
TC-START ::= 'tc-start' COLON TIMESTAMP COMMA STRING NEWLINE
|
||||
TC-SO ::= 'tc-so' COLON STRING NEWLINE
|
||||
TC-SE ::= 'tc-se' COLON STRING NEWLINE
|
||||
TC-END ::= 'tc-end' COLON TIMESTAMP COMMA STRING COMMA TCR NEWLINE
|
||||
TCR ::= 'passed' | ('failed' | 'skipped') COMMA STRING
|
||||
TIMESTAMP ::= [0-9]+.[0-9]+
|
||||
.Ed
|
||||
.Pp
|
||||
The meaning of the constructions above is:
|
||||
.Bl -tag -width TPSXCOUNTXX
|
||||
.It TPS-COUNT
|
||||
Indicates the number of test programs that will be executed.
|
||||
There will be this exact amount of
|
||||
.Sq TP-STANZA
|
||||
constructions following it.
|
||||
.It TP-START
|
||||
Indicates the beginning of a test program.
|
||||
This includes the program's name and the amount of test cases that
|
||||
will follow.
|
||||
.It TP-END
|
||||
Indicates the completion of a test program.
|
||||
This is followed by the program's name and, if the program ended
|
||||
prematurely, an error message indicating the reason of its failure.
|
||||
A successful execution of a test program (regardless of the status of its
|
||||
test cases) must not be accompanied by any reason.
|
||||
.It TC-START
|
||||
Indicates the beginning of a test case.
|
||||
This is accompanied by the test case's name.
|
||||
.It TC-SO
|
||||
Contains a text line sent to the standard output stream during the
|
||||
execution of the test case.
|
||||
Leading and trailing space is preserved.
|
||||
.It TC-SE
|
||||
Contains a text line sent to the standard error stream during the
|
||||
execution of the test case.
|
||||
Leading and trailing space is preserved.
|
||||
.It TC-END
|
||||
Indicates the completion of a test case.
|
||||
This is accompanied by the test case's name, its result and the reason
|
||||
associated with this result (if applicable).
|
||||
.El
|
||||
.Pp
|
||||
An example:
|
||||
.Bd -literal -offset indent
|
||||
tps-count: 2
|
||||
tp-start: calculator, 1324318951.838923, 2
|
||||
tc-start: add, 1324318951.839101
|
||||
tc-end: add, 1324318951.839500, passed
|
||||
tc-start: subtract, 1324318951.840001
|
||||
tc-so: 3-2 expected to return 1 but got 0
|
||||
tc-end: subtract, 1324318952.000123, failed, Calculated an unexpected value
|
||||
tp-end: calculator, 1324318952.002301
|
||||
tp-start: files, 1, 1324318952.502348
|
||||
tc-start: copy, 1324318952.508291
|
||||
tc-se: could not find the cp(1) utility
|
||||
tc-end: copy, 1324318953.203145, skipped
|
||||
tp-end: files, 1324318953.203800
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr atf 7
|
@ -1,168 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 16, 2011
|
||||
.Dt ATF-REPORT 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm atf-report
|
||||
.Nd transforms the output of atf-run to different formats
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl o Ar fmt1:path1 Op .. Fl o Ar fmtN:pathN
|
||||
.Nm
|
||||
.Fl h
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
reads the output of
|
||||
.Nm atf-run
|
||||
and transforms it to different formats.
|
||||
Some of these are user-friendly and others are machine-parseable, which
|
||||
opens a wide range of possibilities to analyze the results of a test
|
||||
suite's execution.
|
||||
See
|
||||
.Sx Output formats
|
||||
below for more details on which these formats are.
|
||||
.Pp
|
||||
In the first synopsis form,
|
||||
.Nm
|
||||
reads the output of
|
||||
.Nm atf-run
|
||||
through its standard input and, if no
|
||||
.Fl o
|
||||
options are given, prints a user-friendly report on its standard
|
||||
output using the
|
||||
.Sq ticker
|
||||
format.
|
||||
If
|
||||
.Fl o
|
||||
options are provided (more than one are allowed), they specify the complete
|
||||
list of reports to generate.
|
||||
They are all generated simultaneously, and for obvious reasons, two reports
|
||||
cannot be written to the same file.
|
||||
Note that the default output is suppressed when
|
||||
.Fl o
|
||||
is provided.
|
||||
.Pp
|
||||
In the second synopsis form,
|
||||
.Nm
|
||||
will print information about all supported options and their purpose.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width XoXfmtXpathXX
|
||||
.It Fl h
|
||||
Shows a short summary of all available options and their purpose.
|
||||
.It Fl o Ar fmt:path
|
||||
Adds a new output format.
|
||||
.Ar fmt
|
||||
is one of the formats described later on in
|
||||
.Sx Output formats .
|
||||
.Ar path
|
||||
specifies where the report will be written to.
|
||||
Depending on the chosen format, this may refer to a single file or to
|
||||
a directory.
|
||||
For those formats that write to a single file, specifying a
|
||||
.Sq -
|
||||
as the path will redirect the report to the standard output.
|
||||
.El
|
||||
.Ss Output formats
|
||||
The following output formats are allowed:
|
||||
.Bl -tag -width tickerXX
|
||||
.It csv
|
||||
A machine-parseable Comma-Separated Values (CSV) file.
|
||||
This file contains the results for all test cases and test programs.
|
||||
Test cases are logged using the following syntax:
|
||||
.Bd -literal -offset indent
|
||||
tc, duration, test-program, test-case, result[, reason]
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Sq result
|
||||
field for test cases is always one of
|
||||
.Sq passed ,
|
||||
.Sq skipped
|
||||
or
|
||||
.Sq failed .
|
||||
The last two are always followed by a reason.
|
||||
.Pp
|
||||
Test programs are logged with the following syntax:
|
||||
.Bd -literal -offset indent
|
||||
tp, duration, test-program, result[, reason]
|
||||
.Ed
|
||||
.Pp
|
||||
In this case, the
|
||||
.Sq result
|
||||
can be one of:
|
||||
.Sq passed ,
|
||||
which denotes test programs that ran without any failure;
|
||||
.Sq failed ,
|
||||
which refers to test programs in which one or more test cases failed;
|
||||
or
|
||||
.Sq bogus ,
|
||||
which mentions those test programs that failed to execute by some reason.
|
||||
The reason field is only available in the last case.
|
||||
.Pp
|
||||
The time required to execute each test case and test program is
|
||||
also provided.
|
||||
You should not rely on the order of the entries in the resulting output.
|
||||
.It ticker
|
||||
A user-friendly report that shows the progress of the test suite's
|
||||
execution as it operates.
|
||||
This type of report should always be redirected to a virtual terminal,
|
||||
not a file, as it may use control sequences that will make the output
|
||||
unreadable in regular files.
|
||||
.It xml
|
||||
A report contained in a single XML file.
|
||||
Ideal for later processing with
|
||||
.Xr xsltproc 1
|
||||
to generate nice HTML reports.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The most simple way of running a test suite is to pipe the output of
|
||||
.Nm atf-run
|
||||
through
|
||||
.Nm
|
||||
without any additional flags.
|
||||
This will use the default output format, which is suitable to most users:
|
||||
.Bd -literal -offset indent
|
||||
atf-run | atf-report
|
||||
.Ed
|
||||
.Pp
|
||||
In some situations, it may be interesting to get a machine-parseable file
|
||||
aside from the standard report.
|
||||
This can be done as follows:
|
||||
.Bd -literal -offset indent
|
||||
atf-run | atf-report -o csv:testsuite.csv -o ticker:-
|
||||
.Ed
|
||||
.Pp
|
||||
Or if the standard report is not desired, thus achieving completely silent
|
||||
operation:
|
||||
atf-run | atf-report -o csv:testsuite.csv
|
||||
.Sh SEE ALSO
|
||||
.Xr atf-run 1 ,
|
||||
.Xr atf 7
|
@ -1,710 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/time.h>
|
||||
}
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "defs.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "reader.hpp"
|
||||
#include "text.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
typedef std::auto_ptr< std::ostream > ostream_ptr;
|
||||
|
||||
static ostream_ptr
|
||||
open_outfile(const tools::fs::path& path)
|
||||
{
|
||||
ostream_ptr osp;
|
||||
if (path.str() == "-")
|
||||
osp = ostream_ptr(new std::ofstream("/dev/stdout"));
|
||||
else
|
||||
osp = ostream_ptr(new std::ofstream(path.c_str()));
|
||||
if (!(*osp))
|
||||
throw std::runtime_error("Could not create file " + path.str());
|
||||
return osp;
|
||||
}
|
||||
|
||||
static std::string
|
||||
format_tv(struct timeval* tv)
|
||||
{
|
||||
std::ostringstream output;
|
||||
output << static_cast< long >(tv->tv_sec) << '.'
|
||||
<< std::setfill('0') << std::setw(6)
|
||||
<< static_cast< long >(tv->tv_usec);
|
||||
return output.str();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "writer" interface.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief A base class that defines an output format.
|
||||
//!
|
||||
//! The writer base class defines a generic interface to output formats.
|
||||
//! This is meant to be subclassed, and each subclass can redefine any
|
||||
//! method to format the information as it wishes.
|
||||
//!
|
||||
//! This class is not tied to a output stream nor a file because, depending
|
||||
//! on the output format, we will want to write to a single file or to
|
||||
//! multiple ones.
|
||||
//!
|
||||
class writer {
|
||||
public:
|
||||
writer(void) {}
|
||||
virtual ~writer(void) {}
|
||||
|
||||
virtual void write_info(const std::string&, const std::string&) {}
|
||||
virtual void write_ntps(size_t) {}
|
||||
virtual void write_tp_start(const std::string&, size_t) {}
|
||||
virtual void write_tp_end(struct timeval*, const std::string&) {}
|
||||
virtual void write_tc_start(const std::string&) {}
|
||||
virtual void write_tc_stdout_line(const std::string&) {}
|
||||
virtual void write_tc_stderr_line(const std::string&) {}
|
||||
virtual void write_tc_end(const std::string&, struct timeval*,
|
||||
const std::string&) {}
|
||||
virtual void write_eof(void) {}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "csv_writer" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief A very simple plain-text output format.
|
||||
//!
|
||||
//! The csv_writer class implements a very simple plain-text output
|
||||
//! format that summarizes the results of each executed test case. The
|
||||
//! results are meant to be easily parseable by third-party tools, hence
|
||||
//! they are formatted as a CSV file.
|
||||
//!
|
||||
class csv_writer : public writer {
|
||||
ostream_ptr m_os;
|
||||
bool m_failed;
|
||||
|
||||
std::string m_tpname;
|
||||
std::string m_tcname;
|
||||
|
||||
public:
|
||||
csv_writer(const tools::fs::path& p) :
|
||||
m_os(open_outfile(p))
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
void
|
||||
write_tp_start(const std::string& name,
|
||||
size_t ntcs ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
m_tpname = name;
|
||||
m_failed = false;
|
||||
}
|
||||
|
||||
virtual
|
||||
void
|
||||
write_tp_end(struct timeval* tv, const std::string& reason)
|
||||
{
|
||||
const std::string timestamp = format_tv(tv);
|
||||
|
||||
if (!reason.empty())
|
||||
(*m_os) << "tp, " << timestamp << ", " << m_tpname << ", bogus, "
|
||||
<< reason << "\n";
|
||||
else if (m_failed)
|
||||
(*m_os) << "tp, " << timestamp << ", "<< m_tpname << ", failed\n";
|
||||
else
|
||||
(*m_os) << "tp, " << timestamp << ", "<< m_tpname << ", passed\n";
|
||||
}
|
||||
|
||||
virtual
|
||||
void
|
||||
write_tc_start(const std::string& name)
|
||||
{
|
||||
m_tcname = name;
|
||||
}
|
||||
|
||||
virtual
|
||||
void
|
||||
write_tc_end(const std::string& state, struct timeval* tv,
|
||||
const std::string& reason)
|
||||
{
|
||||
std::string str = m_tpname + ", " + m_tcname + ", " + state;
|
||||
if (!reason.empty())
|
||||
str += ", " + reason;
|
||||
(*m_os) << "tc, " << format_tv(tv) << ", " << str << "\n";
|
||||
|
||||
if (state == "failed")
|
||||
m_failed = true;
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "ticker_writer" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief A console-friendly output format.
|
||||
//!
|
||||
//! The ticker_writer class implements a formatter that is user-friendly
|
||||
//! in the sense that it shows the execution of test cases in an easy to
|
||||
//! read format. It is not meant to be parseable and its format can
|
||||
//! freely change across releases.
|
||||
//!
|
||||
class ticker_writer : public writer {
|
||||
ostream_ptr m_os;
|
||||
|
||||
size_t m_curtp, m_ntps;
|
||||
size_t m_tcs_passed, m_tcs_failed, m_tcs_skipped, m_tcs_expected_failures;
|
||||
std::string m_tcname, m_tpname;
|
||||
std::vector< std::string > m_failed_tcs;
|
||||
std::map< std::string, std::string > m_expected_failures_tcs;
|
||||
std::vector< std::string > m_failed_tps;
|
||||
|
||||
void
|
||||
write_info(const std::string& what, const std::string& val)
|
||||
{
|
||||
if (what == "tests.root") {
|
||||
(*m_os) << "Tests root: " << val << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
write_ntps(size_t ntps)
|
||||
{
|
||||
m_curtp = 1;
|
||||
m_tcs_passed = 0;
|
||||
m_tcs_failed = 0;
|
||||
m_tcs_skipped = 0;
|
||||
m_tcs_expected_failures = 0;
|
||||
m_ntps = ntps;
|
||||
}
|
||||
|
||||
void
|
||||
write_tp_start(const std::string& tp, size_t ntcs)
|
||||
{
|
||||
using tools::text::to_string;
|
||||
using tools::ui::format_text;
|
||||
|
||||
m_tpname = tp;
|
||||
|
||||
(*m_os) << format_text(tp + " (" + to_string(m_curtp) +
|
||||
"/" + to_string(m_ntps) + "): " +
|
||||
to_string(ntcs) + " test cases")
|
||||
<< "\n";
|
||||
(*m_os).flush();
|
||||
}
|
||||
|
||||
void
|
||||
write_tp_end(struct timeval* tv, const std::string& reason)
|
||||
{
|
||||
using tools::ui::format_text_with_tag;
|
||||
|
||||
m_curtp++;
|
||||
|
||||
if (!reason.empty()) {
|
||||
(*m_os) << format_text_with_tag("BOGUS TEST PROGRAM: Cannot "
|
||||
"trust its results because "
|
||||
"of `" + reason + "'",
|
||||
m_tpname + ": ", false)
|
||||
<< "\n";
|
||||
m_failed_tps.push_back(m_tpname);
|
||||
}
|
||||
(*m_os) << "[" << format_tv(tv) << "s]\n\n";
|
||||
(*m_os).flush();
|
||||
|
||||
m_tpname.clear();
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_start(const std::string& tcname)
|
||||
{
|
||||
m_tcname = tcname;
|
||||
|
||||
(*m_os) << " " + tcname + ": ";
|
||||
(*m_os).flush();
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_end(const std::string& state, struct timeval* tv,
|
||||
const std::string& reason)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
(*m_os) << "[" << format_tv(tv) << "s] ";
|
||||
|
||||
if (state == "expected_death" || state == "expected_exit" ||
|
||||
state == "expected_failure" || state == "expected_signal" ||
|
||||
state == "expected_timeout") {
|
||||
str = "Expected failure: " + reason;
|
||||
m_tcs_expected_failures++;
|
||||
m_expected_failures_tcs[m_tpname + ":" + m_tcname] = reason;
|
||||
} else if (state == "failed") {
|
||||
str = "Failed: " + reason;
|
||||
m_tcs_failed++;
|
||||
m_failed_tcs.push_back(m_tpname + ":" + m_tcname);
|
||||
} else if (state == "passed") {
|
||||
str = "Passed.";
|
||||
m_tcs_passed++;
|
||||
} else if (state == "skipped") {
|
||||
str = "Skipped: " + reason;
|
||||
m_tcs_skipped++;
|
||||
} else
|
||||
std::abort();
|
||||
|
||||
// XXX Wrap text. format_text_with_tag does not currently allow
|
||||
// to specify the current column, which is needed because we have
|
||||
// already printed the tc's name.
|
||||
(*m_os) << str << '\n';
|
||||
|
||||
m_tcname = "";
|
||||
}
|
||||
|
||||
static void
|
||||
write_expected_failures(const std::map< std::string, std::string >& xfails,
|
||||
std::ostream& os)
|
||||
{
|
||||
using tools::ui::format_text;
|
||||
using tools::ui::format_text_with_tag;
|
||||
|
||||
os << format_text("Test cases for known bugs:") << "\n";
|
||||
|
||||
for (std::map< std::string, std::string >::const_iterator iter =
|
||||
xfails.begin(); iter != xfails.end(); iter++) {
|
||||
const std::string& name = (*iter).first;
|
||||
const std::string& reason = (*iter).second;
|
||||
|
||||
os << format_text_with_tag(reason, " " + name + ": ", false)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
write_eof(void)
|
||||
{
|
||||
using tools::text::join;
|
||||
using tools::text::to_string;
|
||||
using tools::ui::format_text;
|
||||
using tools::ui::format_text_with_tag;
|
||||
|
||||
if (!m_failed_tps.empty()) {
|
||||
(*m_os) << format_text("Failed (bogus) test programs:")
|
||||
<< "\n";
|
||||
(*m_os) << format_text_with_tag(join(m_failed_tps, ", "),
|
||||
" ", false) << "\n\n";
|
||||
}
|
||||
|
||||
if (!m_expected_failures_tcs.empty()) {
|
||||
write_expected_failures(m_expected_failures_tcs, *m_os);
|
||||
(*m_os) << "\n";
|
||||
}
|
||||
|
||||
if (!m_failed_tcs.empty()) {
|
||||
(*m_os) << format_text("Failed test cases:") << "\n";
|
||||
(*m_os) << format_text_with_tag(join(m_failed_tcs, ", "),
|
||||
" ", false) << "\n\n";
|
||||
}
|
||||
|
||||
(*m_os) << format_text("Summary for " + to_string(m_ntps) +
|
||||
" test programs:") << "\n";
|
||||
(*m_os) << format_text_with_tag(to_string(m_tcs_passed) +
|
||||
" passed test cases.",
|
||||
" ", false) << "\n";
|
||||
(*m_os) << format_text_with_tag(to_string(m_tcs_failed) +
|
||||
" failed test cases.",
|
||||
" ", false) << "\n";
|
||||
(*m_os) << format_text_with_tag(to_string(m_tcs_expected_failures) +
|
||||
" expected failed test cases.",
|
||||
" ", false) << "\n";
|
||||
(*m_os) << format_text_with_tag(to_string(m_tcs_skipped) +
|
||||
" skipped test cases.",
|
||||
" ", false) << "\n";
|
||||
}
|
||||
|
||||
public:
|
||||
ticker_writer(const tools::fs::path& p) :
|
||||
m_os(open_outfile(p))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "xml" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief A single-file XML output format.
|
||||
//!
|
||||
//! The xml_writer class implements a formatter that prints the results
|
||||
//! of test cases in an XML format easily parseable later on by other
|
||||
//! utilities.
|
||||
//!
|
||||
class xml_writer : public writer {
|
||||
ostream_ptr m_os;
|
||||
|
||||
std::string m_tcname, m_tpname;
|
||||
|
||||
static
|
||||
std::string
|
||||
attrval(const std::string& str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
elemval(const std::string& str)
|
||||
{
|
||||
std::ostringstream buf;
|
||||
for (std::string::const_iterator iter = str.begin();
|
||||
iter != str.end(); iter++) {
|
||||
const int character = static_cast< unsigned char >(*iter);
|
||||
if (character == '&') {
|
||||
buf << "&";
|
||||
} else if (character == '<') {
|
||||
buf << "<";
|
||||
} else if (character == '>') {
|
||||
buf << ">";
|
||||
} else if (std::isalnum(character) || std::ispunct(character) ||
|
||||
std::isspace(character)) {
|
||||
buf << static_cast< char >(character);
|
||||
} else {
|
||||
buf << "&#" << character << ";";
|
||||
}
|
||||
}
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
void
|
||||
write_info(const std::string& what, const std::string& val)
|
||||
{
|
||||
(*m_os) << "<info class=\"" << what << "\">" << val << "</info>\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tp_start(const std::string& tp,
|
||||
size_t ntcs ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
(*m_os) << "<tp id=\"" << attrval(tp) << "\">\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tp_end(struct timeval* tv, const std::string& reason)
|
||||
{
|
||||
if (!reason.empty())
|
||||
(*m_os) << "<failed>" << elemval(reason) << "</failed>\n";
|
||||
(*m_os) << "<tp-time>" << format_tv(tv) << "</tp-time>";
|
||||
(*m_os) << "</tp>\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_start(const std::string& tcname)
|
||||
{
|
||||
(*m_os) << "<tc id=\"" << attrval(tcname) << "\">\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_stdout_line(const std::string& line)
|
||||
{
|
||||
(*m_os) << "<so>" << elemval(line) << "</so>\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_stderr_line(const std::string& line)
|
||||
{
|
||||
(*m_os) << "<se>" << elemval(line) << "</se>\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_tc_end(const std::string& state, struct timeval* tv,
|
||||
const std::string& reason)
|
||||
{
|
||||
std::string str;
|
||||
|
||||
if (state == "expected_death" || state == "expected_exit" ||
|
||||
state == "expected_failure" || state == "expected_signal" ||
|
||||
state == "expected_timeout") {
|
||||
(*m_os) << "<" << state << ">" << elemval(reason)
|
||||
<< "</" << state << ">\n";
|
||||
} else if (state == "passed") {
|
||||
(*m_os) << "<passed />\n";
|
||||
} else if (state == "failed") {
|
||||
(*m_os) << "<failed>" << elemval(reason) << "</failed>\n";
|
||||
} else if (state == "skipped") {
|
||||
(*m_os) << "<skipped>" << elemval(reason) << "</skipped>\n";
|
||||
} else
|
||||
std::abort();
|
||||
(*m_os) << "<tc-time>" << format_tv(tv) << "</tc-time>";
|
||||
(*m_os) << "</tc>\n";
|
||||
}
|
||||
|
||||
void
|
||||
write_eof(void)
|
||||
{
|
||||
(*m_os) << "</tests-results>\n";
|
||||
}
|
||||
|
||||
public:
|
||||
xml_writer(const tools::fs::path& p) :
|
||||
m_os(open_outfile(p))
|
||||
{
|
||||
(*m_os) << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
|
||||
<< "<!DOCTYPE tests-results PUBLIC "
|
||||
"\"-//NetBSD//DTD ATF Tests Results 0.1//EN\" "
|
||||
"\"http://www.NetBSD.org/XML/atf/tests-results.dtd\">\n\n"
|
||||
"<tests-results>\n";
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "converter" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief A reader that redirects events to multiple writers.
|
||||
//!
|
||||
//! The converter class implements an atf_tps_reader that, for each event
|
||||
//! raised by the parser, redirects it to multiple writers so that they
|
||||
//! can reformat it according to their output rules.
|
||||
//!
|
||||
class converter : public tools::atf_report::atf_tps_reader {
|
||||
typedef std::vector< writer* > outs_vector;
|
||||
outs_vector m_outs;
|
||||
|
||||
void
|
||||
got_info(const std::string& what, const std::string& val)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_info(what, val);
|
||||
}
|
||||
|
||||
void
|
||||
got_ntps(size_t ntps)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_ntps(ntps);
|
||||
}
|
||||
|
||||
void
|
||||
got_tp_start(const std::string& tp, size_t ntcs)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tp_start(tp, ntcs);
|
||||
}
|
||||
|
||||
void
|
||||
got_tp_end(struct timeval* tv, const std::string& reason)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tp_end(tv, reason);
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_start(const std::string& tcname)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tc_start(tcname);
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_stdout_line(const std::string& line)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tc_stdout_line(line);
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_stderr_line(const std::string& line)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tc_stderr_line(line);
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_end(const std::string& state, struct timeval* tv,
|
||||
const std::string& reason)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_tc_end(state, tv, reason);
|
||||
}
|
||||
|
||||
void
|
||||
got_eof(void)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
(*iter)->write_eof();
|
||||
}
|
||||
|
||||
public:
|
||||
converter(std::istream& is) :
|
||||
tools::atf_report::atf_tps_reader(is)
|
||||
{
|
||||
}
|
||||
|
||||
~converter(void)
|
||||
{
|
||||
for (outs_vector::iterator iter = m_outs.begin();
|
||||
iter != m_outs.end(); iter++)
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
void
|
||||
add_output(const std::string& fmt, const tools::fs::path& p)
|
||||
{
|
||||
if (fmt == "csv") {
|
||||
m_outs.push_back(new csv_writer(p));
|
||||
} else if (fmt == "ticker") {
|
||||
m_outs.push_back(new ticker_writer(p));
|
||||
} else if (fmt == "xml") {
|
||||
m_outs.push_back(new xml_writer(p));
|
||||
} else
|
||||
throw std::runtime_error("Unknown format `" + fmt + "'");
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_report" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class atf_report : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
typedef std::pair< std::string, tools::fs::path > fmt_path_pair;
|
||||
std::vector< fmt_path_pair > m_oflags;
|
||||
|
||||
void process_option(int, const char*);
|
||||
options_set specific_options(void) const;
|
||||
|
||||
public:
|
||||
atf_report(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
const char* atf_report::m_description =
|
||||
"atf-report is a tool that parses the output of atf-run and "
|
||||
"generates user-friendly reports in multiple different formats.";
|
||||
|
||||
atf_report::atf_report(void) :
|
||||
app(m_description, "atf-report(1)", "atf(7)")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
atf_report::process_option(int ch, const char* arg)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
{
|
||||
std::string str(arg);
|
||||
std::string::size_type pos = str.find(':');
|
||||
if (pos == std::string::npos)
|
||||
throw std::runtime_error("Syntax error in -o option");
|
||||
else {
|
||||
std::string fmt = str.substr(0, pos);
|
||||
tools::fs::path path = tools::fs::path(str.substr(pos + 1));
|
||||
m_oflags.push_back(fmt_path_pair(fmt, path));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
atf_report::options_set
|
||||
atf_report::specific_options(void)
|
||||
const
|
||||
{
|
||||
using tools::application::option;
|
||||
options_set opts;
|
||||
opts.insert(option('o', "fmt:path", "Adds a new output file; multiple "
|
||||
"ones can be specified, and a - "
|
||||
"path means stdout"));
|
||||
return opts;
|
||||
}
|
||||
|
||||
int
|
||||
atf_report::main(void)
|
||||
{
|
||||
if (m_argc > 0)
|
||||
throw std::runtime_error("No arguments allowed");
|
||||
|
||||
if (m_oflags.empty())
|
||||
m_oflags.push_back(fmt_path_pair("ticker", tools::fs::path("-")));
|
||||
|
||||
// Look for path duplicates.
|
||||
std::set< tools::fs::path > paths;
|
||||
for (std::vector< fmt_path_pair >::const_iterator iter = m_oflags.begin();
|
||||
iter != m_oflags.end(); iter++) {
|
||||
tools::fs::path p = (*iter).second;
|
||||
if (p == tools::fs::path("/dev/stdout"))
|
||||
p = tools::fs::path("-");
|
||||
if (paths.find(p) != paths.end())
|
||||
throw std::runtime_error("The file `" + p.str() + "' was "
|
||||
"specified more than once");
|
||||
paths.insert((*iter).second);
|
||||
}
|
||||
|
||||
// Generate the output files.
|
||||
converter cnv(std::cin);
|
||||
for (std::vector< fmt_path_pair >::const_iterator iter = m_oflags.begin();
|
||||
iter != m_oflags.end(); iter++)
|
||||
cnv.add_output((*iter).first, (*iter).second);
|
||||
cnv.read();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return atf_report().run(argc, argv);
|
||||
}
|
@ -1,449 +0,0 @@
|
||||
#
|
||||
# Automated Testing Framework (atf)
|
||||
#
|
||||
# Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
create_helpers()
|
||||
{
|
||||
mkdir dir1
|
||||
cp $(atf_get_srcdir)/pass_helper dir1/tp1
|
||||
cp $(atf_get_srcdir)/fail_helper dir1/tp2
|
||||
cp $(atf_get_srcdir)/pass_helper tp3
|
||||
cp $(atf_get_srcdir)/fail_helper tp4
|
||||
|
||||
cat >tp5 <<EOF
|
||||
#! $(atf-config -t atf_shell)
|
||||
echo foo
|
||||
EOF
|
||||
chmod +x tp5
|
||||
|
||||
cat >Atffile <<EOF
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: dir1
|
||||
tp: tp3
|
||||
tp: tp4
|
||||
tp: tp5
|
||||
EOF
|
||||
|
||||
cat >dir1/Atffile <<EOF
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: tp1
|
||||
tp: tp2
|
||||
EOF
|
||||
}
|
||||
|
||||
run_helpers()
|
||||
{
|
||||
mkdir etc
|
||||
cat >etc/atf-run.hooks <<EOF
|
||||
#! $(atf-config -t atf_shell)
|
||||
|
||||
info_start_hook()
|
||||
{
|
||||
atf_tps_writer_info "startinfo" "A value"
|
||||
}
|
||||
|
||||
info_end_hook()
|
||||
{
|
||||
atf_tps_writer_info "endinfo" "Another value"
|
||||
}
|
||||
EOF
|
||||
echo "Using atf-run to run helpers"
|
||||
ATF_CONFDIR=$(pwd)/etc atf-run >tps.out 2>/dev/null
|
||||
rm -rf etc
|
||||
}
|
||||
|
||||
atf_test_case default
|
||||
default_head()
|
||||
{
|
||||
atf_set "descr" "Checks that the default output uses the ticker" \
|
||||
"format"
|
||||
}
|
||||
default_body()
|
||||
{
|
||||
create_helpers
|
||||
run_helpers
|
||||
|
||||
# Check that the default output uses the ticker format.
|
||||
atf_check -s eq:0 -o match:'test cases' -o match:'Failed test cases' \
|
||||
-o match:'Summary for' -e empty -x 'atf-report <tps.out'
|
||||
}
|
||||
|
||||
# XXX The test for all expect_ values should be intermixed with the other
|
||||
# tests. However, to do that, we need to migrate to using C helpers for
|
||||
# simplicity in raising signals...
|
||||
atf_test_case expect
|
||||
expect_body()
|
||||
{
|
||||
ln -s "$(atf_get_srcdir)/expect_helpers" .
|
||||
cat >Atffile <<EOF
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: expect_helpers
|
||||
EOF
|
||||
run_helpers
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
tc, #.#, expect_helpers, death_and_exit, expected_death, Exit case
|
||||
tc, #.#, expect_helpers, death_and_signal, expected_death, Signal case
|
||||
tc, #.#, expect_helpers, death_but_pass, failed, Test case was expected to terminate abruptly but it continued execution
|
||||
tc, #.#, expect_helpers, exit_any_and_exit, expected_exit, Call will exit
|
||||
tc, #.#, expect_helpers, exit_but_pass, failed, Test case was expected to exit cleanly but it continued execution
|
||||
tc, #.#, expect_helpers, exit_code_and_exit, expected_exit, Call will exit
|
||||
tc, #.#, expect_helpers, fail_and_fail_check, expected_failure, And fail again: 2 checks failed as expected; see output for more details
|
||||
tc, #.#, expect_helpers, fail_and_fail_requirement, expected_failure, Fail reason: The failure
|
||||
tc, #.#, expect_helpers, fail_but_pass, failed, Test case was expecting a failure but none were raised
|
||||
tc, #.#, expect_helpers, pass_and_pass, passed
|
||||
tc, #.#, expect_helpers, pass_but_fail_check, failed, 1 checks failed; see output for more details
|
||||
tc, #.#, expect_helpers, pass_but_fail_requirement, failed, Some reason
|
||||
tc, #.#, expect_helpers, signal_any_and_signal, expected_signal, Call will signal
|
||||
tc, #.#, expect_helpers, signal_but_pass, failed, Test case was expected to receive a termination signal but it continued execution
|
||||
tc, #.#, expect_helpers, signal_no_and_signal, expected_signal, Call will signal
|
||||
tc, #.#, expect_helpers, timeout_and_hang, expected_timeout, Will overrun
|
||||
tc, #.#, expect_helpers, timeout_but_pass, failed, Test case was expected to hang but it continued execution
|
||||
tp, #.#, expect_helpers, failed
|
||||
EOF
|
||||
# NO_CHECK_STYLE_END
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o csv:- <tps.out | " \
|
||||
"sed -E -e 's/[0-9]+.[0-9]{6}, /#.#, /'"
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
expect_helpers (1/1): 17 test cases
|
||||
death_and_exit: [#.#s] Expected failure: Exit case
|
||||
death_and_signal: [#.#s] Expected failure: Signal case
|
||||
death_but_pass: [#.#s] Failed: Test case was expected to terminate abruptly but it continued execution
|
||||
exit_any_and_exit: [#.#s] Expected failure: Call will exit
|
||||
exit_but_pass: [#.#s] Failed: Test case was expected to exit cleanly but it continued execution
|
||||
exit_code_and_exit: [#.#s] Expected failure: Call will exit
|
||||
fail_and_fail_check: [#.#s] Expected failure: And fail again: 2 checks failed as expected; see output for more details
|
||||
fail_and_fail_requirement: [#.#s] Expected failure: Fail reason: The failure
|
||||
fail_but_pass: [#.#s] Failed: Test case was expecting a failure but none were raised
|
||||
pass_and_pass: [#.#s] Passed.
|
||||
pass_but_fail_check: [#.#s] Failed: 1 checks failed; see output for more details
|
||||
pass_but_fail_requirement: [#.#s] Failed: Some reason
|
||||
signal_any_and_signal: [#.#s] Expected failure: Call will signal
|
||||
signal_but_pass: [#.#s] Failed: Test case was expected to receive a termination signal but it continued execution
|
||||
signal_no_and_signal: [#.#s] Expected failure: Call will signal
|
||||
timeout_and_hang: [#.#s] Expected failure: Will overrun
|
||||
timeout_but_pass: [#.#s] Failed: Test case was expected to hang but it continued execution
|
||||
[#.#s]
|
||||
|
||||
Test cases for known bugs:
|
||||
expect_helpers:death_and_exit: Exit case
|
||||
expect_helpers:death_and_signal: Signal case
|
||||
expect_helpers:exit_any_and_exit: Call will exit
|
||||
expect_helpers:exit_code_and_exit: Call will exit
|
||||
expect_helpers:fail_and_fail_check: And fail again: 2 checks failed as expected; see output for more details
|
||||
expect_helpers:fail_and_fail_requirement: Fail reason: The failure
|
||||
expect_helpers:signal_any_and_signal: Call will signal
|
||||
expect_helpers:signal_no_and_signal: Call will signal
|
||||
expect_helpers:timeout_and_hang: Will overrun
|
||||
|
||||
Failed test cases:
|
||||
expect_helpers:death_but_pass, expect_helpers:exit_but_pass, expect_helpers:fail_but_pass, expect_helpers:pass_but_fail_check, expect_helpers:pass_but_fail_requirement, expect_helpers:signal_but_pass, expect_helpers:timeout_but_pass
|
||||
|
||||
Summary for 1 test programs:
|
||||
1 passed test cases.
|
||||
7 failed test cases.
|
||||
9 expected failed test cases.
|
||||
0 skipped test cases.
|
||||
EOF
|
||||
# NO_CHECK_STYLE_END
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o ticker:- <tps.out | " \
|
||||
"sed -E -e 's/[0-9]+.[0-9]{6}/#.#/'"
|
||||
|
||||
# Just ensure that this does not crash for now...
|
||||
atf_check -s eq:0 -o ignore -e empty -x "atf-report -o xml:- <tps.out"
|
||||
}
|
||||
|
||||
atf_test_case oflag
|
||||
oflag_head()
|
||||
{
|
||||
atf_set "descr" "Checks that the -o flag works"
|
||||
}
|
||||
oflag_body()
|
||||
{
|
||||
create_helpers
|
||||
run_helpers
|
||||
|
||||
# Get the default output.
|
||||
atf_check -s eq:0 -o save:stdout -e empty -x 'atf-report <tps.out'
|
||||
mv stdout defout
|
||||
|
||||
# Check that changing the stdout output works.
|
||||
atf_check -s eq:0 -o save:stdout -e empty -x 'atf-report -o csv:- <tps.out'
|
||||
atf_check -s eq:1 -o empty -e empty cmp -s defout stdout
|
||||
cp stdout expcsv
|
||||
|
||||
# Check that sending the output to a file does not write to stdout.
|
||||
atf_check -s eq:0 -o empty -e empty -x 'atf-report -o csv:fmt.out <tps.out'
|
||||
atf_check -s eq:0 -o empty -e empty cmp -s expcsv fmt.out
|
||||
rm -f fmt.out
|
||||
|
||||
# Check that defining two outputs using the same format works.
|
||||
atf_check -s eq:0 -o empty -e empty -x \
|
||||
'atf-report -o csv:fmt.out -o csv:fmt2.out <tps.out'
|
||||
atf_check -s eq:0 -o empty -e empty cmp -s expcsv fmt.out
|
||||
atf_check -s eq:0 -o empty -e empty cmp -s fmt.out fmt2.out
|
||||
rm -f fmt.out fmt2.out
|
||||
|
||||
# Check that defining two outputs using different formats works.
|
||||
atf_check -s eq:0 -o empty -e empty -x \
|
||||
'atf-report -o csv:fmt.out -o ticker:fmt2.out <tps.out'
|
||||
atf_check -s eq:0 -o empty -e empty cmp -s expcsv fmt.out
|
||||
atf_check -s eq:1 -o empty -e empty cmp -s fmt.out fmt2.out
|
||||
atf_check -s eq:0 -o ignore -e empty grep "test cases" fmt2.out
|
||||
atf_check -s eq:0 -o ignore -e empty grep "Failed test cases" fmt2.out
|
||||
atf_check -s eq:0 -o ignore -e empty grep "Summary for" fmt2.out
|
||||
rm -f fmt.out fmt2.out
|
||||
|
||||
# Check that defining two outputs over the same file does not work.
|
||||
atf_check -s eq:1 -o empty -e match:'more than once' -x \
|
||||
'atf-report -o csv:fmt.out -o ticker:fmt.out <tps.out'
|
||||
rm -f fmt.out
|
||||
|
||||
# Check that defining two outputs over stdout (but using different
|
||||
# paths) does not work.
|
||||
atf_check -s eq:1 -o empty -e match:'more than once' -x \
|
||||
'atf-report -o csv:- -o ticker:/dev/stdout <tps.out'
|
||||
rm -f fmt.out
|
||||
}
|
||||
|
||||
atf_test_case output_csv
|
||||
output_csv_head()
|
||||
{
|
||||
atf_set "descr" "Checks the CSV output format"
|
||||
}
|
||||
output_csv_body()
|
||||
{
|
||||
create_helpers
|
||||
run_helpers
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
tc, #.#, dir1/tp1, main, passed
|
||||
tp, #.#, dir1/tp1, passed
|
||||
tc, #.#, dir1/tp2, main, failed, This always fails
|
||||
tp, #.#, dir1/tp2, failed
|
||||
tc, #.#, tp3, main, passed
|
||||
tp, #.#, tp3, passed
|
||||
tc, #.#, tp4, main, failed, This always fails
|
||||
tp, #.#, tp4, failed
|
||||
tp, #.#, tp5, bogus, Invalid format for test case list: 1: Unexpected token \`<<NEWLINE>>'; expected \`:'
|
||||
EOF
|
||||
# NO_CHECK_STYLE_END
|
||||
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o csv:- <tps.out | sed -E -e 's/[0-9]+.[0-9]{6}, /#.#, /'"
|
||||
}
|
||||
|
||||
atf_test_case output_ticker
|
||||
output_ticker_head()
|
||||
{
|
||||
atf_set "descr" "Checks the ticker output format"
|
||||
}
|
||||
output_ticker_body()
|
||||
{
|
||||
create_helpers
|
||||
run_helpers
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
dir1/tp1 (1/5): 1 test cases
|
||||
main: [#.#s] Passed.
|
||||
[#.#s]
|
||||
|
||||
dir1/tp2 (2/5): 1 test cases
|
||||
main: [#.#s] Failed: This always fails
|
||||
[#.#s]
|
||||
|
||||
tp3 (3/5): 1 test cases
|
||||
main: [#.#s] Passed.
|
||||
[#.#s]
|
||||
|
||||
tp4 (4/5): 1 test cases
|
||||
main: [#.#s] Failed: This always fails
|
||||
[#.#s]
|
||||
|
||||
tp5 (5/5): 0 test cases
|
||||
tp5: BOGUS TEST PROGRAM: Cannot trust its results because of \`Invalid format for test case list: 1: Unexpected token \`<<NEWLINE>>'; expected \`:''
|
||||
[#.#s]
|
||||
|
||||
Failed (bogus) test programs:
|
||||
tp5
|
||||
|
||||
Failed test cases:
|
||||
dir1/tp2:main, tp4:main
|
||||
|
||||
Summary for 5 test programs:
|
||||
2 passed test cases.
|
||||
2 failed test cases.
|
||||
0 expected failed test cases.
|
||||
0 skipped test cases.
|
||||
EOF
|
||||
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o ticker:- <tps.out | sed -E -e 's/[0-9]+.[0-9]{6}/#.#/'"
|
||||
}
|
||||
# NO_CHECK_STYLE_END
|
||||
|
||||
atf_test_case output_xml
|
||||
output_xml_head()
|
||||
{
|
||||
atf_set "descr" "Checks the XML output format"
|
||||
}
|
||||
output_xml_body()
|
||||
{
|
||||
create_helpers
|
||||
run_helpers
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE tests-results PUBLIC "-//NetBSD//DTD ATF Tests Results 0.1//EN" "http://www.NetBSD.org/XML/atf/tests-results.dtd">
|
||||
|
||||
<tests-results>
|
||||
<info class="startinfo">A value</info>
|
||||
<tp id="dir1/tp1">
|
||||
<tc id="main">
|
||||
<passed />
|
||||
<tc-time>#.#</tc-time></tc>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<tp id="dir1/tp2">
|
||||
<tc id="main">
|
||||
<failed>This always fails</failed>
|
||||
<tc-time>#.#</tc-time></tc>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<tp id="tp3">
|
||||
<tc id="main">
|
||||
<passed />
|
||||
<tc-time>#.#</tc-time></tc>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<tp id="tp4">
|
||||
<tc id="main">
|
||||
<failed>This always fails</failed>
|
||||
<tc-time>#.#</tc-time></tc>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<tp id="tp5">
|
||||
<failed>Invalid format for test case list: 1: Unexpected token \`<<NEWLINE>>'; expected \`:'</failed>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<info class="endinfo">Another value</info>
|
||||
</tests-results>
|
||||
EOF
|
||||
# NO_CHECK_STYLE_END
|
||||
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o xml:- < tps.out | sed -E -e 's/>[0-9]+.[0-9]{6}</>#.#</'"
|
||||
}
|
||||
|
||||
atf_test_case output_xml_space
|
||||
output_xml_space_head()
|
||||
{
|
||||
atf_set "descr" "Checks that the XML output format properly preserves" \
|
||||
"leading and trailing whitespace in stdout and stderr" \
|
||||
"lines"
|
||||
}
|
||||
output_xml_space_body()
|
||||
{
|
||||
export TESTCASE=diff
|
||||
cp $(atf_get_srcdir)/misc_helpers .
|
||||
cat >Atffile <<EOF
|
||||
Content-Type: application/X-atf-atffile; version="1"
|
||||
|
||||
prop: test-suite = atf
|
||||
|
||||
tp: misc_helpers
|
||||
EOF
|
||||
|
||||
# NO_CHECK_STYLE_BEGIN
|
||||
cat >expout <<EOF
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE tests-results PUBLIC "-//NetBSD//DTD ATF Tests Results 0.1//EN" "http://www.NetBSD.org/XML/atf/tests-results.dtd">
|
||||
|
||||
<tests-results>
|
||||
<info class="startinfo">A value</info>
|
||||
<tp id="misc_helpers">
|
||||
<tc id="diff">
|
||||
<so>--- a 2007-11-04 14:00:41.000000000 +0100</so>
|
||||
<so>+++ b 2007-11-04 14:00:48.000000000 +0100</so>
|
||||
<so>@@ -1,7 +1,7 @@</so>
|
||||
<so> This test is meant to simulate a diff.</so>
|
||||
<so> Blank space at beginning of context lines must be preserved.</so>
|
||||
<so> </so>
|
||||
<so>-First original line.</so>
|
||||
<so>-Second original line.</so>
|
||||
<so>+First modified line.</so>
|
||||
<so>+Second modified line.</so>
|
||||
<so> </so>
|
||||
<so> EOF</so>
|
||||
<passed />
|
||||
<tc-time>#.#</tc-time></tc>
|
||||
<tp-time>#.#</tp-time></tp>
|
||||
<info class="endinfo">Another value</info>
|
||||
</tests-results>
|
||||
EOF
|
||||
# NO_CHECK_STYLE_END
|
||||
|
||||
run_helpers
|
||||
atf_check -s eq:0 -o file:expout -e empty -x \
|
||||
"atf-report -o xml:- <tps.out | sed -E -e 's/>[0-9]+.[0-9]{6}</>#.#</'"
|
||||
}
|
||||
|
||||
atf_test_case too_many_args
|
||||
too_many_args_body()
|
||||
{
|
||||
cat >experr <<EOF
|
||||
atf-report: ERROR: No arguments allowed
|
||||
EOF
|
||||
atf_check -s eq:1 -o empty -e file:experr atf-report foo
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case default
|
||||
atf_add_test_case expect
|
||||
atf_add_test_case oflag
|
||||
atf_add_test_case output_csv
|
||||
atf_add_test_case output_ticker
|
||||
atf_add_test_case output_xml
|
||||
atf_add_test_case output_xml_space
|
||||
atf_add_test_case too_many_args
|
||||
}
|
||||
|
||||
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
|
202
tools/atf-run.1
202
tools/atf-run.1
@ -1,202 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd November 1, 2010
|
||||
.Dt ATF-RUN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm atf-run
|
||||
.Nd executes a collection of test programs
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl v Ar var1=value1 Op .. Fl v Ar varN=valueN
|
||||
.Op Ar test_program1 Op Ar .. test_programN
|
||||
.Nm
|
||||
.Fl h
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
executes a collection of test programs or, in other words, a complete
|
||||
test suite.
|
||||
The results of each test program are collected by the tool, and are then
|
||||
multiplexed into a single machine-parseable report; see
|
||||
.Xr atf-formats 5
|
||||
for more details.
|
||||
This report can later be transformed into many different and saner formats
|
||||
using the
|
||||
.Nm atf-report
|
||||
tool.
|
||||
.Pp
|
||||
The list of test programs to execute is read from an
|
||||
.Pa Atffile
|
||||
present in the current directory.
|
||||
This file describes the test suite stored in the directory it lives in,
|
||||
which aside from the list of test programs also includes meta-data and
|
||||
configuration variables.
|
||||
.Pp
|
||||
.Nm
|
||||
is also in charge of reading the configuration files that tune the behavior
|
||||
of each test program and passing down the necessary variables to them.
|
||||
More details on how this is done are given in the
|
||||
.Sx Configuration
|
||||
section.
|
||||
.Pp
|
||||
In the first synopsis form,
|
||||
.Nm
|
||||
parses the
|
||||
.Pa Atffile
|
||||
in the current directory and runs all the test programs specified in it.
|
||||
If any test program names are given as part of the command line, those are
|
||||
the ones executed instead of the complete list.
|
||||
.Pp
|
||||
In the second synopsis form,
|
||||
.Nm
|
||||
will print information about all supported options and their purpose.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width XvXvarXvalueXX
|
||||
.It Fl h
|
||||
Shows a short summary of all available options and their purpose.
|
||||
.It Fl v Ar var=value
|
||||
Sets the configuration variable
|
||||
.Ar var
|
||||
to the given value
|
||||
.Ar value .
|
||||
.El
|
||||
.Ss Configuration
|
||||
.Nm
|
||||
reads configuration data from multiple places.
|
||||
After all of these places have been analyzed, a list of variable-value
|
||||
pairs are passed to the test programs to be run.
|
||||
.Pp
|
||||
The following locations are scanned for configuration data, in order.
|
||||
Items down the list override values defined above them:
|
||||
.Bl -enum
|
||||
.It
|
||||
Configuration variables defined in the
|
||||
.Pa Atffile .
|
||||
.It
|
||||
Configuration variables defined in the system-wide configuration file
|
||||
shared among all test suites.
|
||||
This lives in
|
||||
.Pa ${ATF_CONFDIR}/common.conf .
|
||||
.It
|
||||
Configuration variables defined in the system-wide test-suite-specific
|
||||
configuration file.
|
||||
This lives in
|
||||
.Pa ${ATF_CONFDIR}/<test-suite>.conf .
|
||||
.It
|
||||
Configuration variables defined in the user-specific configuration file
|
||||
shared among all test suites.
|
||||
This lives in
|
||||
.Pa ${HOME}/.atf/common.conf .
|
||||
.It
|
||||
Configuration variables defined in the user-specific test-suite-specific
|
||||
configuration file.
|
||||
This lives in
|
||||
.Pa ${HOME}/.atf/<test-suite>.conf .
|
||||
.It
|
||||
Configuration variables provided as part of the command line through the
|
||||
.Fl v
|
||||
option.
|
||||
.El
|
||||
.Pp
|
||||
The value of
|
||||
.Va ATF_CONFDIR
|
||||
in the above list determined as detailed in
|
||||
.Xr atf-config 1 .
|
||||
.Pp
|
||||
The following configuration variables are globally recognized:
|
||||
.Bl -tag -width XunprivilegedXuserXX
|
||||
.It Va unprivileged-user
|
||||
The name of the system user that atf-run will drop root privileges into
|
||||
for test cases defining
|
||||
.Sq require.user=unprivileged .
|
||||
Note that this is
|
||||
.Em not provided for security purposes ;
|
||||
this feature is only for the convenience of the user.
|
||||
.El
|
||||
.Ss Hooks
|
||||
.Nm Ns 's
|
||||
internal behavior can be customized by the system administrator and the
|
||||
user by means of hooks.
|
||||
These hooks are written in the shell script language for simplicity and
|
||||
are stored in the following files, which are read in the order provided
|
||||
below:
|
||||
.Bl -enum
|
||||
.It
|
||||
${ATF_CONFDIR}/atf-run.hooks
|
||||
.It
|
||||
${HOME}/.atf/atf-run.hooks
|
||||
.El
|
||||
.Pp
|
||||
The following hooks are supported:
|
||||
.Bl -tag -width infoXstartXhookXX
|
||||
.It info_start_hook
|
||||
Called before
|
||||
.Nm
|
||||
executes any test program.
|
||||
The purpose of this hook is to write additional
|
||||
.Sq info
|
||||
stanzas to the top of the output report; these are defined by the
|
||||
.Sq application/X-atf-tps format
|
||||
described in
|
||||
.Xr atf-formats 5 .
|
||||
Always use the
|
||||
.Sq atf_tps_writer_info
|
||||
function to print these.
|
||||
.Pp
|
||||
This takes no parameters.
|
||||
.It info_end_hook
|
||||
Similar to
|
||||
.Sq info_start_hook
|
||||
but executed after all test programs have been run so that additional
|
||||
.Sq info
|
||||
stanzas can be added to the bottom of the output report.
|
||||
.Pp
|
||||
This takes no parameters.
|
||||
.El
|
||||
.Pp
|
||||
All hooks are accompanied by a function named
|
||||
.Sq default_<hook_name>
|
||||
that can be executed by them to invoke the default behavior built into
|
||||
.Nm .
|
||||
For example, in order to extend the default
|
||||
.Sq info_start_hook
|
||||
hook, we could write the following function:
|
||||
.Bd -literal -offset indent
|
||||
info_start_hook()
|
||||
{
|
||||
default_info_start_hook "${@}"
|
||||
|
||||
atf_tps_writer_info "uptime" "$(uptime)"
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr atf-report 1 ,
|
||||
.Xr atf-test-program 1 ,
|
||||
.Xr atf 7
|
@ -1,567 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "bconfig.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "atffile.hpp"
|
||||
#include "config.hpp"
|
||||
#include "config_file.hpp"
|
||||
#include "env.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "process.hpp"
|
||||
#include "requirements.hpp"
|
||||
#include "test-program.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#if defined(MAXCOMLEN)
|
||||
static const std::string::size_type max_core_name_length = MAXCOMLEN;
|
||||
#else
|
||||
static const std::string::size_type max_core_name_length = std::string::npos;
|
||||
#endif
|
||||
|
||||
class atf_run : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
vars_map m_cmdline_vars;
|
||||
|
||||
static vars_map::value_type parse_var(const std::string&);
|
||||
|
||||
void process_option(int, const char*);
|
||||
std::string specific_args(void) const;
|
||||
options_set specific_options(void) const;
|
||||
|
||||
void parse_vflag(const std::string&);
|
||||
|
||||
std::vector< std::string > conf_args(void) const;
|
||||
|
||||
size_t count_tps(std::vector< std::string >) const;
|
||||
|
||||
int run_test(const tools::fs::path&, tools::test_program::atf_tps_writer&,
|
||||
const vars_map&);
|
||||
int run_test_directory(const tools::fs::path&,
|
||||
tools::test_program::atf_tps_writer&);
|
||||
int run_test_program(const tools::fs::path&,
|
||||
tools::test_program::atf_tps_writer&,
|
||||
const vars_map&);
|
||||
|
||||
tools::test_program::test_case_result get_test_case_result(
|
||||
const std::string&, const tools::process::status&,
|
||||
const tools::fs::path&) const;
|
||||
|
||||
public:
|
||||
atf_run(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
static void
|
||||
sanitize_gdb_env(void)
|
||||
{
|
||||
try {
|
||||
tools::env::unset("TERM");
|
||||
} catch (...) {
|
||||
// Just swallow exceptions here; they cannot propagate into C, which
|
||||
// is where this function is called from, and even if these exceptions
|
||||
// appear they are benign.
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_stacktrace(const tools::fs::path& tp, const tools::process::status& s,
|
||||
const tools::fs::path& workdir,
|
||||
tools::test_program::atf_tps_writer& w)
|
||||
{
|
||||
assert(s.signaled() && s.coredump());
|
||||
|
||||
w.stderr_tc("Test program crashed; attempting to get stack trace");
|
||||
|
||||
const tools::fs::path corename = workdir /
|
||||
(tp.leaf_name().substr(0, max_core_name_length) + ".core");
|
||||
if (!tools::fs::exists(corename)) {
|
||||
w.stderr_tc("Expected file " + corename.str() + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
const tools::fs::path gdb(GDB);
|
||||
const tools::fs::path gdbout = workdir / "gdb.out";
|
||||
const tools::process::argv_array args(gdb.leaf_name().c_str(), "-batch",
|
||||
"-q", "-ex", "bt", tp.c_str(),
|
||||
corename.c_str(), NULL);
|
||||
tools::process::status status = tools::process::exec(
|
||||
gdb, args,
|
||||
tools::process::stream_redirect_path(gdbout),
|
||||
tools::process::stream_redirect_path(tools::fs::path("/dev/null")),
|
||||
sanitize_gdb_env);
|
||||
if (!status.exited() || status.exitstatus() != EXIT_SUCCESS) {
|
||||
w.stderr_tc("Execution of " GDB " failed");
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream input(gdbout.c_str());
|
||||
if (input) {
|
||||
std::string line;
|
||||
while (std::getline(input, line).good())
|
||||
w.stderr_tc(line);
|
||||
input.close();
|
||||
}
|
||||
|
||||
w.stderr_tc("Stack trace complete");
|
||||
}
|
||||
|
||||
const char* atf_run::m_description =
|
||||
"atf-run is a tool that runs tests programs and collects their "
|
||||
"results.";
|
||||
|
||||
atf_run::atf_run(void) :
|
||||
app(m_description, "atf-run(1)", "atf(7)")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
atf_run::process_option(int ch, const char* arg)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
parse_vflag(arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
atf_run::specific_args(void)
|
||||
const
|
||||
{
|
||||
return "[test-program1 .. test-programN]";
|
||||
}
|
||||
|
||||
atf_run::options_set
|
||||
atf_run::specific_options(void)
|
||||
const
|
||||
{
|
||||
using tools::application::option;
|
||||
options_set opts;
|
||||
opts.insert(option('v', "var=value", "Sets the configuration variable "
|
||||
"`var' to `value'; overrides "
|
||||
"values in configuration files"));
|
||||
return opts;
|
||||
}
|
||||
|
||||
void
|
||||
atf_run::parse_vflag(const std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
throw std::runtime_error("-v requires a non-empty argument");
|
||||
|
||||
std::vector< std::string > ws = tools::text::split(str, "=");
|
||||
if (ws.size() == 1 && str[str.length() - 1] == '=') {
|
||||
m_cmdline_vars[ws[0]] = "";
|
||||
} else {
|
||||
if (ws.size() != 2)
|
||||
throw std::runtime_error("-v requires an argument of the form "
|
||||
"var=value");
|
||||
|
||||
m_cmdline_vars[ws[0]] = ws[1];
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
atf_run::run_test(const tools::fs::path& tp,
|
||||
tools::test_program::atf_tps_writer& w,
|
||||
const vars_map& config)
|
||||
{
|
||||
tools::fs::file_info fi(tp);
|
||||
|
||||
int errcode;
|
||||
if (fi.get_type() == tools::fs::file_info::dir_type)
|
||||
errcode = run_test_directory(tp, w);
|
||||
else {
|
||||
const vars_map effective_config =
|
||||
tools::config_file::merge_configs(config, m_cmdline_vars);
|
||||
|
||||
errcode = run_test_program(tp, w, effective_config);
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int
|
||||
atf_run::run_test_directory(const tools::fs::path& tp,
|
||||
tools::test_program::atf_tps_writer& w)
|
||||
{
|
||||
tools::atffile af = tools::read_atffile(tp / "Atffile");
|
||||
|
||||
vars_map test_suite_vars;
|
||||
{
|
||||
vars_map::const_iterator iter = af.props().find("test-suite");
|
||||
assert(iter != af.props().end());
|
||||
test_suite_vars = tools::config_file::read_config_files((*iter).second);
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
for (std::vector< std::string >::const_iterator iter = af.tps().begin();
|
||||
iter != af.tps().end(); iter++) {
|
||||
const bool result = run_test(tp / *iter, w,
|
||||
tools::config_file::merge_configs(af.conf(), test_suite_vars));
|
||||
ok &= (result == EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tools::test_program::test_case_result
|
||||
atf_run::get_test_case_result(const std::string& broken_reason,
|
||||
const tools::process::status& s,
|
||||
const tools::fs::path& resfile)
|
||||
const
|
||||
{
|
||||
using tools::text::to_string;
|
||||
using tools::test_program::read_test_case_result;
|
||||
using tools::test_program::test_case_result;
|
||||
|
||||
if (!broken_reason.empty()) {
|
||||
test_case_result tcr;
|
||||
|
||||
try {
|
||||
tcr = read_test_case_result(resfile);
|
||||
|
||||
if (tcr.state() == "expected_timeout") {
|
||||
return tcr;
|
||||
} else {
|
||||
return test_case_result("failed", -1, broken_reason);
|
||||
}
|
||||
} catch (const std::runtime_error&) {
|
||||
return test_case_result("failed", -1, broken_reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (s.exited()) {
|
||||
test_case_result tcr;
|
||||
|
||||
try {
|
||||
tcr = read_test_case_result(resfile);
|
||||
} catch (const std::runtime_error& e) {
|
||||
return test_case_result("failed", -1, "Test case exited "
|
||||
"normally but failed to create the results file: " +
|
||||
std::string(e.what()));
|
||||
}
|
||||
|
||||
if (tcr.state() == "expected_death") {
|
||||
return tcr;
|
||||
} else if (tcr.state() == "expected_exit") {
|
||||
if (tcr.value() == -1 || s.exitstatus() == tcr.value())
|
||||
return tcr;
|
||||
else
|
||||
return test_case_result("failed", -1, "Test case was "
|
||||
"expected to exit with a " + to_string(tcr.value()) +
|
||||
" error code but returned " + to_string(s.exitstatus()));
|
||||
} else if (tcr.state() == "expected_failure") {
|
||||
if (s.exitstatus() == EXIT_SUCCESS)
|
||||
return tcr;
|
||||
else
|
||||
return test_case_result("failed", -1, "Test case returned an "
|
||||
"error in expected_failure mode but it should not have");
|
||||
} else if (tcr.state() == "expected_signal") {
|
||||
return test_case_result("failed", -1, "Test case exited cleanly "
|
||||
"but was expected to receive a signal");
|
||||
} else if (tcr.state() == "failed") {
|
||||
if (s.exitstatus() == EXIT_SUCCESS)
|
||||
return test_case_result("failed", -1, "Test case "
|
||||
"exited successfully but reported failure");
|
||||
else
|
||||
return tcr;
|
||||
} else if (tcr.state() == "passed") {
|
||||
if (s.exitstatus() == EXIT_SUCCESS)
|
||||
return tcr;
|
||||
else
|
||||
return test_case_result("failed", -1, "Test case exited as "
|
||||
"passed but reported an error");
|
||||
} else if (tcr.state() == "skipped") {
|
||||
if (s.exitstatus() == EXIT_SUCCESS)
|
||||
return tcr;
|
||||
else
|
||||
return test_case_result("failed", -1, "Test case exited as "
|
||||
"skipped but reported an error");
|
||||
}
|
||||
} else if (s.signaled()) {
|
||||
test_case_result tcr;
|
||||
|
||||
try {
|
||||
tcr = read_test_case_result(resfile);
|
||||
} catch (const std::runtime_error&) {
|
||||
return test_case_result("failed", -1, "Test program received "
|
||||
"signal " + tools::text::to_string(s.termsig()) +
|
||||
(s.coredump() ? " (core dumped)" : ""));
|
||||
}
|
||||
|
||||
if (tcr.state() == "expected_death") {
|
||||
return tcr;
|
||||
} else if (tcr.state() == "expected_signal") {
|
||||
if (tcr.value() == -1 || s.termsig() == tcr.value())
|
||||
return tcr;
|
||||
else
|
||||
return test_case_result("failed", -1, "Test case was "
|
||||
"expected to exit due to a " + to_string(tcr.value()) +
|
||||
" signal but got " + to_string(s.termsig()));
|
||||
} else {
|
||||
return test_case_result("failed", -1, "Test program received "
|
||||
"signal " + tools::text::to_string(s.termsig()) +
|
||||
(s.coredump() ? " (core dumped)" : "") + " and created a "
|
||||
"bogus results file");
|
||||
}
|
||||
}
|
||||
std::abort();
|
||||
return test_case_result();
|
||||
}
|
||||
|
||||
int
|
||||
atf_run::run_test_program(const tools::fs::path& tp,
|
||||
tools::test_program::atf_tps_writer& w,
|
||||
const vars_map& config)
|
||||
{
|
||||
int errcode = EXIT_SUCCESS;
|
||||
|
||||
tools::test_program::metadata md;
|
||||
try {
|
||||
md = tools::test_program::get_metadata(tp, config);
|
||||
} catch (const tools::parser::format_error& e) {
|
||||
w.start_tp(tp.str(), 0);
|
||||
w.end_tp("Invalid format for test case list: " + std::string(e.what()));
|
||||
return EXIT_FAILURE;
|
||||
} catch (const tools::parser::parse_errors& e) {
|
||||
const std::string reason = tools::text::join(e, "; ");
|
||||
w.start_tp(tp.str(), 0);
|
||||
w.end_tp("Invalid format for test case list: " + reason);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tools::fs::temp_dir resdir(
|
||||
tools::fs::path(tools::config::get("atf_workdir")) / "atf-run.XXXXXX");
|
||||
|
||||
w.start_tp(tp.str(), md.test_cases.size());
|
||||
if (md.test_cases.empty()) {
|
||||
w.end_tp("Bogus test program: reported 0 test cases");
|
||||
errcode = EXIT_FAILURE;
|
||||
} else {
|
||||
for (std::map< std::string, vars_map >::const_iterator iter
|
||||
= md.test_cases.begin(); iter != md.test_cases.end(); iter++) {
|
||||
const std::string& tcname = (*iter).first;
|
||||
const vars_map& tcmd = (*iter).second;
|
||||
|
||||
w.start_tc(tcname);
|
||||
|
||||
try {
|
||||
const std::string& reqfail = tools::check_requirements(
|
||||
tcmd, config);
|
||||
if (!reqfail.empty()) {
|
||||
w.end_tc("skipped", reqfail);
|
||||
continue;
|
||||
}
|
||||
} catch (const std::runtime_error& e) {
|
||||
w.end_tc("failed", e.what());
|
||||
errcode = EXIT_FAILURE;
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::pair< int, int > user = tools::get_required_user(
|
||||
tcmd, config);
|
||||
|
||||
tools::fs::path resfile = resdir.get_path() / "tcr";
|
||||
assert(!tools::fs::exists(resfile));
|
||||
try {
|
||||
const bool has_cleanup = tools::text::to_bool(
|
||||
(*tcmd.find("has.cleanup")).second);
|
||||
|
||||
tools::fs::temp_dir workdir(tools::fs::path(tools::config::get(
|
||||
"atf_workdir")) / "atf-run.XXXXXX");
|
||||
if (user.first != -1 && user.second != -1) {
|
||||
if (::chown(workdir.get_path().c_str(), user.first,
|
||||
user.second) == -1) {
|
||||
throw tools::system_error("chown(" +
|
||||
workdir.get_path().str() + ")", "chown(2) failed",
|
||||
errno);
|
||||
}
|
||||
resfile = workdir.get_path() / "tcr";
|
||||
}
|
||||
|
||||
std::pair< std::string, const tools::process::status > s =
|
||||
tools::test_program::run_test_case(
|
||||
tp, tcname, "body", tcmd, config,
|
||||
resfile, workdir.get_path(), w);
|
||||
if (s.second.signaled() && s.second.coredump())
|
||||
dump_stacktrace(tp, s.second, workdir.get_path(), w);
|
||||
if (has_cleanup)
|
||||
(void)tools::test_program::run_test_case(
|
||||
tp, tcname, "cleanup", tcmd,
|
||||
config, resfile, workdir.get_path(), w);
|
||||
|
||||
// TODO: Force deletion of workdir.
|
||||
|
||||
tools::test_program::test_case_result tcr =
|
||||
get_test_case_result(s.first, s.second, resfile);
|
||||
|
||||
w.end_tc(tcr.state(), tcr.reason());
|
||||
if (tcr.state() == "failed")
|
||||
errcode = EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
if (tools::fs::exists(resfile))
|
||||
tools::fs::remove(resfile);
|
||||
throw;
|
||||
}
|
||||
if (tools::fs::exists(resfile))
|
||||
tools::fs::remove(resfile);
|
||||
|
||||
}
|
||||
w.end_tp("");
|
||||
}
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
size_t
|
||||
atf_run::count_tps(std::vector< std::string > tps)
|
||||
const
|
||||
{
|
||||
size_t ntps = 0;
|
||||
|
||||
for (std::vector< std::string >::const_iterator iter = tps.begin();
|
||||
iter != tps.end(); iter++) {
|
||||
tools::fs::path tp(*iter);
|
||||
tools::fs::file_info fi(tp);
|
||||
|
||||
if (fi.get_type() == tools::fs::file_info::dir_type) {
|
||||
tools::atffile af = tools::read_atffile(tp / "Atffile");
|
||||
std::vector< std::string > aux = af.tps();
|
||||
for (std::vector< std::string >::iterator i2 = aux.begin();
|
||||
i2 != aux.end(); i2++)
|
||||
*i2 = (tp / *i2).str();
|
||||
ntps += count_tps(aux);
|
||||
} else
|
||||
ntps++;
|
||||
}
|
||||
|
||||
return ntps;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
call_hook(const std::string& tool, const std::string& hook)
|
||||
{
|
||||
const tools::fs::path sh(tools::config::get("atf_shell"));
|
||||
const tools::fs::path hooks =
|
||||
tools::fs::path(tools::config::get("atf_pkgdatadir")) / (tool + ".hooks");
|
||||
|
||||
const tools::process::status s =
|
||||
tools::process::exec(sh,
|
||||
tools::process::argv_array(sh.c_str(), hooks.c_str(),
|
||||
hook.c_str(), NULL),
|
||||
tools::process::stream_inherit(),
|
||||
tools::process::stream_inherit());
|
||||
|
||||
|
||||
if (!s.exited() || s.exitstatus() != EXIT_SUCCESS)
|
||||
throw std::runtime_error("Failed to run the '" + hook + "' hook "
|
||||
"for '" + tool + "'");
|
||||
}
|
||||
|
||||
int
|
||||
atf_run::main(void)
|
||||
{
|
||||
tools::atffile af = tools::read_atffile(tools::fs::path("Atffile"));
|
||||
|
||||
std::vector< std::string > tps;
|
||||
tps = af.tps();
|
||||
if (m_argc >= 1) {
|
||||
// TODO: Ensure that the given test names are listed in the
|
||||
// Atffile. Take into account that the file can be using globs.
|
||||
tps.clear();
|
||||
for (int i = 0; i < m_argc; i++)
|
||||
tps.push_back(m_argv[i]);
|
||||
}
|
||||
|
||||
// Read configuration data for this test suite.
|
||||
vars_map test_suite_vars;
|
||||
{
|
||||
vars_map::const_iterator iter = af.props().find("test-suite");
|
||||
assert(iter != af.props().end());
|
||||
test_suite_vars = tools::config_file::read_config_files((*iter).second);
|
||||
}
|
||||
|
||||
tools::test_program::atf_tps_writer w(std::cout);
|
||||
call_hook("atf-run", "info_start_hook");
|
||||
w.ntps(count_tps(tps));
|
||||
|
||||
bool ok = true;
|
||||
for (std::vector< std::string >::const_iterator iter = tps.begin();
|
||||
iter != tps.end(); iter++) {
|
||||
const bool result = run_test(tools::fs::path(*iter), w,
|
||||
tools::config_file::merge_configs(af.conf(), test_suite_vars));
|
||||
ok &= (result == EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
call_hook("atf-run", "info_end_hook");
|
||||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return atf_run().run(argc, argv);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 16, 2007
|
||||
.Dt ATF-VERSION 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm atf-version
|
||||
.Nd shows information about the installed ATF version
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Nm
|
||||
.Fl h
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a utility that prints information about the version of ATF currently
|
||||
installed in the system.
|
||||
.Pp
|
||||
In the first synopsis form,
|
||||
.Nm
|
||||
shows the release version of the ATF package installed in the system (the
|
||||
installation that corresponds to the instance of
|
||||
.Nm
|
||||
being executed) and also shows information related to the repository
|
||||
revision used to build that package.
|
||||
.Pp
|
||||
In the second synopsis form,
|
||||
.Nm
|
||||
will print information about all supported options and their purpose.
|
||||
.Sh SEE ALSO
|
||||
.Xr atf 7
|
@ -1,91 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "bconfig.h"
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "application.hpp"
|
||||
#include "revision.h"
|
||||
#include "ui.hpp"
|
||||
|
||||
class atf_version : public tools::application::app {
|
||||
static const char* m_description;
|
||||
|
||||
public:
|
||||
atf_version(void);
|
||||
|
||||
int main(void);
|
||||
};
|
||||
|
||||
const char* atf_version::m_description =
|
||||
"atf-version is a tool that shows information about the currently "
|
||||
"installed version of ATF.";
|
||||
|
||||
atf_version::atf_version(void) :
|
||||
app(m_description, "atf-version(1)", "atf(7)")
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
atf_version::main(void)
|
||||
{
|
||||
using tools::ui::format_text;
|
||||
using tools::ui::format_text_with_tag;
|
||||
|
||||
std::cout << PACKAGE_STRING " (" PACKAGE_TARNAME "-" PACKAGE_VERSION
|
||||
")\n" PACKAGE_COPYRIGHT "\n\n";
|
||||
|
||||
#if defined(PACKAGE_REVISION_TYPE_DIST)
|
||||
std::cout << format_text("Built from a distribution file; no revision "
|
||||
"information available.") << "\n";
|
||||
#elif defined(PACKAGE_REVISION_TYPE_GIT)
|
||||
std::cout << format_text_with_tag(PACKAGE_REVISION_BRANCH, "Branch: ",
|
||||
false) << "\n";
|
||||
std::cout << format_text_with_tag(PACKAGE_REVISION_BASE
|
||||
# if PACKAGE_REVISION_MODIFIED
|
||||
" (locally modified)"
|
||||
# endif
|
||||
" " PACKAGE_REVISION_DATE,
|
||||
"Base revision: ", false) << "\n";
|
||||
#else
|
||||
# error "Unknown PACKAGE_REVISION_TYPE value"
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* const* argv)
|
||||
{
|
||||
return atf_version().run(argc, argv);
|
||||
}
|
192
tools/atf.7.in
192
tools/atf.7.in
@ -1,192 +0,0 @@
|
||||
.\"
|
||||
.\" Automated Testing Framework (atf)
|
||||
.\"
|
||||
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd August 28, 2010
|
||||
.Dt ATF 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ATF
|
||||
.Nd introduction to the Automated Testing Framework
|
||||
.Sh DESCRIPTION
|
||||
.Em IMPORTANT: If you are here because you want to know how to run the tests in
|
||||
.Pa __TESTSDIR__ ,
|
||||
.Em you most likely want to read the
|
||||
.Xr tests 7
|
||||
.Em manual page instead.
|
||||
.Pp
|
||||
The Automated Testing Framework
|
||||
.Pf ( Nm )
|
||||
is a collection of libraries and utilities designed to ease unattended
|
||||
application testing in the hands of developers and end users of a specific
|
||||
piece of software.
|
||||
.Pp
|
||||
As regards developers,
|
||||
.Nm
|
||||
provides the necessary means to easily create
|
||||
test suites composed of multiple test programs, which in turn are a
|
||||
collection of test cases.
|
||||
It also attempts to simplify the debugging of problems when these test
|
||||
cases detect an error by providing as much information as possible
|
||||
about the failure.
|
||||
.Pp
|
||||
As regards users, it simplifies the process of running the test suites and,
|
||||
in special, encourages end users to run them often: they do not need to
|
||||
have source trees around nor any other development tools installed to be
|
||||
able to certify that a given piece of software works on their machine as
|
||||
advertised.
|
||||
.Pp
|
||||
If your operating systems distributes
|
||||
.Nm ,
|
||||
it is possible that it provides an introductory
|
||||
.Xr tests 7
|
||||
manual page.
|
||||
You are encouraged to read it now.
|
||||
.Ss License
|
||||
.Nm
|
||||
is distributed under the terms of the TNF License, a 2-clause BSD license.
|
||||
For more details please see:
|
||||
.Bd -literal -offset indent
|
||||
.Pa __DOCDIR__/COPYING
|
||||
.Ed
|
||||
.Ss Components
|
||||
.Nm
|
||||
is a highly modular piece of software.
|
||||
It provides a couple of libraries to ease the implementation of test
|
||||
programs: one for the C and C++ languages and another one for shell
|
||||
scripts.
|
||||
It also includes multiple small utilities that follow the principle of
|
||||
doing a single thing but doing it right.
|
||||
This section outlines which these components are.
|
||||
.Pp
|
||||
Public utilities:
|
||||
.Bl -tag -width atfXtestXprogramXXXXX
|
||||
.It Xr atf-check 1
|
||||
Executes a command and checks that its exit code, its standard output
|
||||
and its standard error output match pre-specified expected values.
|
||||
.It Xr atf-config 1
|
||||
Queries static configuration information.
|
||||
.It Xr atf-report 1
|
||||
Converts the output of
|
||||
.Nm atf-run
|
||||
to user-friendly and/or machine-parseable reports.
|
||||
.It Xr atf-run 1
|
||||
Automates the execution of a series of test programs and collects their
|
||||
results in a unified report.
|
||||
.It Xr atf-sh 1
|
||||
Shell interpreter for shell-based test programs.
|
||||
.El
|
||||
.Pp
|
||||
Programming interfaces:
|
||||
.Bl -tag -width atfXtestXprogramXXXXX
|
||||
.It Xr atf-c-api 3
|
||||
C programming interface for test programs.
|
||||
.It Xr atf-c++-api 3
|
||||
C++ programming interface for test programs.
|
||||
.It Xr atf-sh-api 3
|
||||
POSIX shell programming interface for test programs.
|
||||
.El
|
||||
.Pp
|
||||
Other:
|
||||
.Bl -tag -width atfXtestXprogramXXXXX
|
||||
.It Xr atf-formats 5
|
||||
Description of the machine-parseable data formats used by the tools.
|
||||
.It Xr atf-test-case 4
|
||||
Generic description of test cases, independent of the language they are
|
||||
implemented in.
|
||||
.It Xr atf-test-program 1
|
||||
Common interface provided by the test programs written using the
|
||||
.Nm
|
||||
libraries.
|
||||
.El
|
||||
.Ss Recommended reading order
|
||||
For end users wishing to run tests:
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
.Xr tests 7
|
||||
(only if provided by your operating system).
|
||||
.It
|
||||
.Xr atf-test-program 1
|
||||
.It
|
||||
.Xr atf-run 1
|
||||
.It
|
||||
.Xr atf-report 1
|
||||
.It
|
||||
.Xr atf-config 1
|
||||
.El
|
||||
.Pp
|
||||
For developers wanting to write their own tests:
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
Everything recommended to users.
|
||||
.It
|
||||
.Xr atf-test-case 4
|
||||
.It
|
||||
.Xr atf-c-api 3
|
||||
.It
|
||||
.Xr atf-c++-api 3
|
||||
.It
|
||||
.Xr atf-sh-api 3
|
||||
.It
|
||||
.Xr atf-sh 1
|
||||
.It
|
||||
.Xr atf-check 1
|
||||
.El
|
||||
.Pp
|
||||
For those interested in
|
||||
.Nm
|
||||
internals:
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
Everything recommended to users.
|
||||
.It
|
||||
Everything recommended to developers.
|
||||
.It
|
||||
.Xr atf-formats 5
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr tests 7
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
started as a Google Summer of Code 2007 project mentored by The NetBSD
|
||||
Foundation.
|
||||
Its original goal was to provide a testing framework for The NetBSD
|
||||
Operating System, but it grew as an independent project because the
|
||||
framework itself did not need to be tied to a specific operating system.
|
||||
.Pp
|
||||
For more details on this subject, please see:
|
||||
.Bd -literal -offset indent
|
||||
.Pa __DOCDIR__/NEWS
|
||||
.Pa __DOCDIR__/ROADMAP
|
||||
.Ed
|
||||
.Sh AUTHORS
|
||||
For more details on the people that made
|
||||
.Nm
|
||||
possible, please see:
|
||||
.Bd -literal -offset indent
|
||||
.Pa __DOCDIR__/AUTHORS
|
||||
.Ed
|
@ -1,348 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
|
||||
#include "atffile.hpp"
|
||||
#include "defs.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "expand.hpp"
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace impl = tools;
|
||||
namespace detail = tools::detail;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_atffile" auxiliary parser.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace atf_atffile {
|
||||
|
||||
static const tools::parser::token_type eof_type = 0;
|
||||
static const tools::parser::token_type nl_type = 1;
|
||||
static const tools::parser::token_type text_type = 2;
|
||||
static const tools::parser::token_type colon_type = 3;
|
||||
static const tools::parser::token_type conf_type = 4;
|
||||
static const tools::parser::token_type dblquote_type = 5;
|
||||
static const tools::parser::token_type equal_type = 6;
|
||||
static const tools::parser::token_type hash_type = 7;
|
||||
static const tools::parser::token_type prop_type = 8;
|
||||
static const tools::parser::token_type tp_type = 9;
|
||||
static const tools::parser::token_type tp_glob_type = 10;
|
||||
|
||||
class tokenizer : public tools::parser::tokenizer< std::istream > {
|
||||
public:
|
||||
tokenizer(std::istream& is, size_t curline) :
|
||||
tools::parser::tokenizer< std::istream >
|
||||
(is, true, eof_type, nl_type, text_type, curline)
|
||||
{
|
||||
add_delim(':', colon_type);
|
||||
add_delim('=', equal_type);
|
||||
add_delim('#', hash_type);
|
||||
add_quote('"', dblquote_type);
|
||||
add_keyword("conf", conf_type);
|
||||
add_keyword("prop", prop_type);
|
||||
add_keyword("tp", tp_type);
|
||||
add_keyword("tp-glob", tp_glob_type);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace atf_atffile
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_atffile_reader" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
detail::atf_atffile_reader::atf_atffile_reader(std::istream& is) :
|
||||
m_is(is)
|
||||
{
|
||||
}
|
||||
|
||||
detail::atf_atffile_reader::~atf_atffile_reader(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_atffile_reader::got_conf(
|
||||
const std::string& name ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_atffile_reader::got_prop(
|
||||
const std::string& name ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_atffile_reader::got_tp(
|
||||
const std::string& name ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
bool isglob ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_atffile_reader::got_eof(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_atffile_reader::read(void)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_atffile;
|
||||
|
||||
std::pair< size_t, tools::parser::headers_map > hml =
|
||||
tools::parser::read_headers(m_is, 1);
|
||||
tools::parser::validate_content_type(hml.second,
|
||||
"application/X-atf-atffile", 1);
|
||||
|
||||
tokenizer tkz(m_is, hml.first);
|
||||
tools::parser::parser< tokenizer > p(tkz);
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
tools::parser::token t =
|
||||
p.expect(conf_type, hash_type, prop_type, tp_type,
|
||||
tp_glob_type, nl_type, eof_type,
|
||||
"conf, #, prop, tp, tp-glob, a new line or eof");
|
||||
if (t.type() == eof_type)
|
||||
break;
|
||||
|
||||
if (t.type() == conf_type) {
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
t = p.expect(text_type, "variable name");
|
||||
std::string var = t.text();
|
||||
|
||||
t = p.expect(equal_type, "equal sign");
|
||||
|
||||
t = p.expect(text_type, "word or quoted string");
|
||||
ATF_PARSER_CALLBACK(p, got_conf(var, t.text()));
|
||||
} else if (t.type() == hash_type) {
|
||||
(void)p.rest_of_line();
|
||||
} else if (t.type() == prop_type) {
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
t = p.expect(text_type, "property name");
|
||||
std::string name = t.text();
|
||||
|
||||
t = p.expect(equal_type, "equale sign");
|
||||
|
||||
t = p.expect(text_type, "word or quoted string");
|
||||
ATF_PARSER_CALLBACK(p, got_prop(name, t.text()));
|
||||
} else if (t.type() == tp_type) {
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
t = p.expect(text_type, "word or quoted string");
|
||||
ATF_PARSER_CALLBACK(p, got_tp(t.text(), false));
|
||||
} else if (t.type() == tp_glob_type) {
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
t = p.expect(text_type, "word or quoted string");
|
||||
ATF_PARSER_CALLBACK(p, got_tp(t.text(), true));
|
||||
} else if (t.type() == nl_type) {
|
||||
continue;
|
||||
} else
|
||||
std::abort();
|
||||
|
||||
t = p.expect(nl_type, hash_type, eof_type,
|
||||
"new line or comment");
|
||||
if (t.type() == hash_type) {
|
||||
(void)p.rest_of_line();
|
||||
t = p.next();
|
||||
} else if (t.type() == eof_type)
|
||||
break;
|
||||
} catch (const parse_error& pe) {
|
||||
p.add_error(pe);
|
||||
p.reset(nl_type);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_PARSER_CALLBACK(p, got_eof());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "reader" helper class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class reader : public detail::atf_atffile_reader {
|
||||
const tools::fs::directory& m_dir;
|
||||
vars_map m_conf, m_props;
|
||||
std::vector< std::string > m_tps;
|
||||
|
||||
void
|
||||
got_tp(const std::string& name, bool isglob)
|
||||
{
|
||||
if (isglob) {
|
||||
std::vector< std::string > ms =
|
||||
tools::expand::expand_glob(name, m_dir.names());
|
||||
// Cannot use m_tps.insert(iterator, begin, end) here because it
|
||||
// does not work under Solaris.
|
||||
for (std::vector< std::string >::const_iterator iter = ms.begin();
|
||||
iter != ms.end(); iter++)
|
||||
m_tps.push_back(*iter);
|
||||
} else {
|
||||
if (m_dir.find(name) == m_dir.end())
|
||||
throw tools::not_found_error< tools::fs::path >
|
||||
("Cannot locate the " + name + " file",
|
||||
tools::fs::path(name));
|
||||
m_tps.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
got_prop(const std::string& name, const std::string& val)
|
||||
{
|
||||
m_props[name] = val;
|
||||
}
|
||||
|
||||
void
|
||||
got_conf(const std::string& var, const std::string& val)
|
||||
{
|
||||
m_conf[var] = val;
|
||||
}
|
||||
|
||||
public:
|
||||
reader(std::istream& is, const tools::fs::directory& dir) :
|
||||
detail::atf_atffile_reader(is),
|
||||
m_dir(dir)
|
||||
{
|
||||
}
|
||||
|
||||
const vars_map&
|
||||
conf(void)
|
||||
const
|
||||
{
|
||||
return m_conf;
|
||||
}
|
||||
|
||||
const vars_map&
|
||||
props(void)
|
||||
const
|
||||
{
|
||||
return m_props;
|
||||
}
|
||||
|
||||
const std::vector< std::string >&
|
||||
tps(void)
|
||||
const
|
||||
{
|
||||
return m_tps;
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atffile" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::atffile::atffile(const vars_map& config_vars,
|
||||
const std::vector< std::string >& test_program_names,
|
||||
const vars_map& properties) :
|
||||
m_conf(config_vars),
|
||||
m_tps(test_program_names),
|
||||
m_props(properties)
|
||||
{
|
||||
assert(properties.find("test-suite") != properties.end());
|
||||
}
|
||||
|
||||
const std::vector< std::string >&
|
||||
impl::atffile::tps(void)
|
||||
const
|
||||
{
|
||||
return m_tps;
|
||||
}
|
||||
|
||||
const vars_map&
|
||||
impl::atffile::conf(void)
|
||||
const
|
||||
{
|
||||
return m_conf;
|
||||
}
|
||||
|
||||
const vars_map&
|
||||
impl::atffile::props(void)
|
||||
const
|
||||
{
|
||||
return m_props;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Free functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// XXX Glob expansion and file existance checks certainly do not belong in
|
||||
// a *parser*. This needs to be taken out...
|
||||
impl::atffile
|
||||
impl::read_atffile(const tools::fs::path& filename)
|
||||
{
|
||||
// Scan the directory where the atffile lives in to gather a list of
|
||||
// all possible test programs in it.
|
||||
tools::fs::directory dir(filename.branch_path());
|
||||
dir.erase(filename.leaf_name());
|
||||
tools::fs::directory::iterator iter = dir.begin();
|
||||
while (iter != dir.end()) {
|
||||
const std::string& name = (*iter).first;
|
||||
const tools::fs::file_info& fi = (*iter).second;
|
||||
|
||||
// Discard hidden files and non-executable ones so that they are
|
||||
// not candidates for glob matching.
|
||||
if (name[0] == '.' || (!fi.is_owner_executable() &&
|
||||
!fi.is_group_executable()))
|
||||
dir.erase(iter++);
|
||||
else
|
||||
iter++;
|
||||
}
|
||||
|
||||
// Parse the atffile.
|
||||
std::ifstream is(filename.c_str());
|
||||
if (!is)
|
||||
throw tools::not_found_error< tools::fs::path >
|
||||
("Cannot open Atffile", filename);
|
||||
reader r(is, dir);
|
||||
r.read();
|
||||
is.close();
|
||||
|
||||
// Sanity checks.
|
||||
if (r.props().find("test-suite") == r.props().end())
|
||||
throw tools::not_found_error< std::string >
|
||||
("Undefined property `test-suite'", "test-suite");
|
||||
|
||||
return atffile(r.conf(), r.tps(), r.props());
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_ATFFILE_HPP)
|
||||
#define TOOLS_ATFFILE_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "fs.hpp"
|
||||
|
||||
namespace tools {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_atffile_reader" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
class atf_atffile_reader {
|
||||
std::istream& m_is;
|
||||
|
||||
protected:
|
||||
virtual void got_conf(const std::string&, const std::string &);
|
||||
virtual void got_prop(const std::string&, const std::string &);
|
||||
virtual void got_tp(const std::string&, bool);
|
||||
virtual void got_eof(void);
|
||||
|
||||
public:
|
||||
atf_atffile_reader(std::istream&);
|
||||
virtual ~atf_atffile_reader(void);
|
||||
|
||||
void read(void);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atffile" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class atffile {
|
||||
std::map< std::string, std::string > m_conf;
|
||||
std::vector< std::string > m_tps;
|
||||
std::map< std::string, std::string > m_props;
|
||||
|
||||
public:
|
||||
atffile(const std::map< std::string, std::string >&,
|
||||
const std::vector< std::string >&,
|
||||
const std::map< std::string, std::string >&);
|
||||
|
||||
const std::map< std::string, std::string >& conf(void) const;
|
||||
const std::vector< std::string >& tps(void) const;
|
||||
const std::map< std::string, std::string >& props(void) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Free functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
atffile read_atffile(const tools::fs::path&);
|
||||
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_ATFFILE_HPP)
|
@ -1,636 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "atffile.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
namespace detail = tools::detail;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
static
|
||||
std::auto_ptr< std::ofstream >
|
||||
new_atffile(void)
|
||||
{
|
||||
std::auto_ptr< std::ofstream > os(new std::ofstream("Atffile"));
|
||||
ATF_REQUIRE(*os);
|
||||
|
||||
(*os) << "Content-Type: application/X-atf-atffile; version=\"1\"\n\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
touch_exec(const char* name)
|
||||
{
|
||||
std::ofstream os(name);
|
||||
ATF_REQUIRE(os);
|
||||
os.close();
|
||||
ATF_REQUIRE(::chmod(name, S_IRWXU) != -1);
|
||||
}
|
||||
|
||||
static inline
|
||||
bool
|
||||
is_in(const std::string& value, const std::vector< std::string >& v)
|
||||
{
|
||||
return std::find(v.begin(), v.end(), value) != v.end();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests cases for the "atffile" parser.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class atffile_reader : protected detail::atf_atffile_reader {
|
||||
void
|
||||
got_conf(const std::string& name, const std::string& val)
|
||||
{
|
||||
m_calls.push_back("got_conf(" + name + ", " + val + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_prop(const std::string& name, const std::string& val)
|
||||
{
|
||||
m_calls.push_back("got_prop(" + name + ", " + val + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tp(const std::string& name, bool isglob)
|
||||
{
|
||||
m_calls.push_back("got_tp(" + name + ", " + (isglob ? "true" : "false")
|
||||
+ ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_eof(void)
|
||||
{
|
||||
m_calls.push_back("got_eof()");
|
||||
}
|
||||
|
||||
public:
|
||||
atffile_reader(std::istream& is) :
|
||||
detail::atf_atffile_reader(is)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
read(void)
|
||||
{
|
||||
atf_atffile_reader::read();
|
||||
}
|
||||
|
||||
std::vector< std::string > m_calls;
|
||||
};
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_1);
|
||||
ATF_TEST_CASE_BODY(atffile_1)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_2);
|
||||
ATF_TEST_CASE_BODY(atffile_2)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"# This is a comment on a line of its own.\n"
|
||||
"# And this is another one.\n"
|
||||
"\n"
|
||||
" # Another after some whitespace.\n"
|
||||
"\n"
|
||||
"# The last one after an empty line.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_3);
|
||||
ATF_TEST_CASE_BODY(atffile_3)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"conf: var1=value1\n"
|
||||
"conf: var2 = value2\n"
|
||||
"conf: var3 = value3\n"
|
||||
"conf: var4 = value4\n"
|
||||
"\n"
|
||||
"conf:var5=value5\n"
|
||||
" conf:var6=value6\n"
|
||||
"\n"
|
||||
"conf: var7 = \"This is a long value.\"\n"
|
||||
"conf: var8 = \"Single-word\"\n"
|
||||
"conf: var9 = \" Single-word \"\n"
|
||||
"conf: var10 = Single-word\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_conf(var1, value1)",
|
||||
"got_conf(var2, value2)",
|
||||
"got_conf(var3, value3)",
|
||||
"got_conf(var4, value4)",
|
||||
"got_conf(var5, value5)",
|
||||
"got_conf(var6, value6)",
|
||||
"got_conf(var7, This is a long value.)",
|
||||
"got_conf(var8, Single-word)",
|
||||
"got_conf(var9, Single-word )",
|
||||
"got_conf(var10, Single-word)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_4);
|
||||
ATF_TEST_CASE_BODY(atffile_4)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"prop: var1=value1\n"
|
||||
"prop: var2 = value2\n"
|
||||
"prop: var3 = value3\n"
|
||||
"prop: var4 = value4\n"
|
||||
"\n"
|
||||
"prop:var5=value5\n"
|
||||
" prop:var6=value6\n"
|
||||
"\n"
|
||||
"prop: var7 = \"This is a long value.\"\n"
|
||||
"prop: var8 = \"Single-word\"\n"
|
||||
"prop: var9 = \" Single-word \"\n"
|
||||
"prop: var10 = Single-word\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_prop(var1, value1)",
|
||||
"got_prop(var2, value2)",
|
||||
"got_prop(var3, value3)",
|
||||
"got_prop(var4, value4)",
|
||||
"got_prop(var5, value5)",
|
||||
"got_prop(var6, value6)",
|
||||
"got_prop(var7, This is a long value.)",
|
||||
"got_prop(var8, Single-word)",
|
||||
"got_prop(var9, Single-word )",
|
||||
"got_prop(var10, Single-word)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_5);
|
||||
ATF_TEST_CASE_BODY(atffile_5)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"tp:foo\n"
|
||||
"tp: foo\n"
|
||||
"tp: foo\n"
|
||||
"tp: foo\n"
|
||||
"tp: foo\n"
|
||||
"tp: \"name with spaces\"\n"
|
||||
"tp: \"single-word\"\n"
|
||||
"tp: single-word\n"
|
||||
"\n"
|
||||
"tp-glob:foo*?bar\n"
|
||||
"tp-glob: foo*?bar\n"
|
||||
"tp-glob: foo*?bar\n"
|
||||
"tp-glob: foo*?bar\n"
|
||||
"tp-glob: foo*?bar\n"
|
||||
"tp-glob: \"glob * with ? spaces\"\n"
|
||||
"tp-glob: \"single-*-word\"\n"
|
||||
"tp-glob: single-*-word\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(name with spaces, false)",
|
||||
"got_tp(single-word, false)",
|
||||
"got_tp(single-word, false)",
|
||||
"got_tp(foo*?bar, true)",
|
||||
"got_tp(foo*?bar, true)",
|
||||
"got_tp(foo*?bar, true)",
|
||||
"got_tp(foo*?bar, true)",
|
||||
"got_tp(foo*?bar, true)",
|
||||
"got_tp(glob * with ? spaces, true)",
|
||||
"got_tp(single-*-word, true)",
|
||||
"got_tp(single-*-word, true)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_6);
|
||||
ATF_TEST_CASE_BODY(atffile_6)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"prop: foo = bar # A comment.\n"
|
||||
"conf: foo = bar # A comment.\n"
|
||||
"tp: foo # A comment.\n"
|
||||
"tp-glob: foo # A comment.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_prop(foo, bar)",
|
||||
"got_conf(foo, bar)",
|
||||
"got_tp(foo, false)",
|
||||
"got_tp(foo, true)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_50);
|
||||
ATF_TEST_CASE_BODY(atffile_50)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `foo'; expected conf, #, prop, tp, tp-glob, a new line or eof",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_51);
|
||||
ATF_TEST_CASE_BODY(atffile_51)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo bar\n"
|
||||
"baz\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `foo'; expected conf, #, prop, tp, tp-glob, a new line or eof",
|
||||
"4: Unexpected token `baz'; expected conf, #, prop, tp, tp-glob, a new line or eof",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_52);
|
||||
ATF_TEST_CASE_BODY(atffile_52)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"conf\n"
|
||||
"conf:\n"
|
||||
"conf: foo =\n"
|
||||
"conf: bar = # A comment.\n"
|
||||
"\n"
|
||||
"prop\n"
|
||||
"prop:\n"
|
||||
"prop: foo =\n"
|
||||
"prop: bar = # A comment.\n"
|
||||
"\n"
|
||||
"tp\n"
|
||||
"tp:\n"
|
||||
"tp: # A comment.\n"
|
||||
"\n"
|
||||
"tp-glob\n"
|
||||
"tp-glob:\n"
|
||||
"tp-glob: # A comment.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"4: Unexpected token `<<NEWLINE>>'; expected variable name",
|
||||
"5: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
|
||||
"6: Unexpected token `#'; expected word or quoted string",
|
||||
"8: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"9: Unexpected token `<<NEWLINE>>'; expected property name",
|
||||
"10: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
|
||||
"11: Unexpected token `#'; expected word or quoted string",
|
||||
"13: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"14: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
|
||||
"15: Unexpected token `#'; expected word or quoted string",
|
||||
"17: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"18: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
|
||||
"19: Unexpected token `#'; expected word or quoted string",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_53);
|
||||
ATF_TEST_CASE_BODY(atffile_53)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"prop: foo = \"Correct value\" # With comment.\n"
|
||||
"\n"
|
||||
"prop: bar = # A comment.\n"
|
||||
"\n"
|
||||
"prop: baz = \"Last variable\"\n"
|
||||
"\n"
|
||||
"# End of file.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_prop(foo, Correct value)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"5: Unexpected token `#'; expected word or quoted string",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(atffile_54);
|
||||
ATF_TEST_CASE_BODY(atffile_54)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-atffile; version=\"1\"\n"
|
||||
"\n"
|
||||
"prop: foo = \"\n"
|
||||
"prop: bar = \"text\n"
|
||||
"prop: baz = \"te\\\"xt\n"
|
||||
"prop: last = \"\\\"\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Missing double quotes before end of line",
|
||||
"4: Missing double quotes before end of line",
|
||||
"5: Missing double quotes before end of line",
|
||||
"6: Missing double quotes before end of line",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< atffile_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests cases for the "atffile" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(atffile_getters);
|
||||
ATF_TEST_CASE_HEAD(atffile_getters) {}
|
||||
ATF_TEST_CASE_BODY(atffile_getters) {
|
||||
vars_map config_vars;
|
||||
config_vars["config-var-1"] = "value 1";
|
||||
|
||||
std::vector< std::string > test_program_names;
|
||||
test_program_names.push_back("test-program-1");
|
||||
|
||||
vars_map properties;
|
||||
properties["test-suite"] = "a test name";
|
||||
|
||||
const tools::atffile atffile(config_vars, test_program_names, properties);
|
||||
ATF_REQUIRE(config_vars == atffile.conf());
|
||||
ATF_REQUIRE(test_program_names == atffile.tps());
|
||||
ATF_REQUIRE(properties == atffile.props());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests cases for the free functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(read_ok_simple);
|
||||
ATF_TEST_CASE_BODY(read_ok_simple) {
|
||||
std::auto_ptr< std::ofstream > os = new_atffile();
|
||||
(*os) << "prop: test-suite = foo\n";
|
||||
(*os) << "tp: tp-1\n";
|
||||
(*os) << "conf: var1 = value1\n";
|
||||
(*os) << "tp: tp-2\n";
|
||||
(*os) << "tp: tp-3\n";
|
||||
(*os) << "prop: prop1 = propvalue1\n";
|
||||
(*os) << "conf: var2 = value2\n";
|
||||
(*os).close();
|
||||
|
||||
touch_exec("tp-1");
|
||||
touch_exec("tp-2");
|
||||
touch_exec("tp-3");
|
||||
|
||||
const tools::atffile atffile = tools::read_atffile(
|
||||
tools::fs::path("Atffile"));
|
||||
ATF_REQUIRE_EQ(2, atffile.conf().size());
|
||||
ATF_REQUIRE_EQ("value1", atffile.conf().find("var1")->second);
|
||||
ATF_REQUIRE_EQ("value2", atffile.conf().find("var2")->second);
|
||||
ATF_REQUIRE_EQ(3, atffile.tps().size());
|
||||
ATF_REQUIRE(is_in("tp-1", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("tp-2", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("tp-3", atffile.tps()));
|
||||
ATF_REQUIRE_EQ(2, atffile.props().size());
|
||||
ATF_REQUIRE_EQ("foo", atffile.props().find("test-suite")->second);
|
||||
ATF_REQUIRE_EQ("propvalue1", atffile.props().find("prop1")->second);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(read_ok_some_globs);
|
||||
ATF_TEST_CASE_BODY(read_ok_some_globs) {
|
||||
std::auto_ptr< std::ofstream > os = new_atffile();
|
||||
(*os) << "prop: test-suite = foo\n";
|
||||
(*os) << "tp: foo\n";
|
||||
(*os) << "tp-glob: *K*\n";
|
||||
(*os) << "tp: bar\n";
|
||||
(*os) << "tp-glob: t_*\n";
|
||||
(*os).close();
|
||||
|
||||
touch_exec("foo");
|
||||
touch_exec("bar");
|
||||
touch_exec("aK");
|
||||
touch_exec("KKKKK");
|
||||
touch_exec("t_hello");
|
||||
touch_exec("zzzt_hello");
|
||||
|
||||
const tools::atffile atffile = tools::read_atffile(
|
||||
tools::fs::path("Atffile"));
|
||||
ATF_REQUIRE_EQ(5, atffile.tps().size());
|
||||
ATF_REQUIRE(is_in("foo", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("bar", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("aK", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("KKKKK", atffile.tps()));
|
||||
ATF_REQUIRE(is_in("t_hello", atffile.tps()));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(read_missing_test_suite);
|
||||
ATF_TEST_CASE_BODY(read_missing_test_suite) {
|
||||
std::auto_ptr< std::ofstream > os = new_atffile();
|
||||
(*os).close();
|
||||
|
||||
try {
|
||||
(void)tools::read_atffile(tools::fs::path("Atffile"));
|
||||
ATF_FAIL("Missing property 'test-suite' did not raise an error");
|
||||
} catch (const tools::not_found_error< std::string >& e) {
|
||||
ATF_REQUIRE_EQ("test-suite", e.get_value());
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(read_missing_test_program);
|
||||
ATF_TEST_CASE_BODY(read_missing_test_program) {
|
||||
std::auto_ptr< std::ofstream > os = new_atffile();
|
||||
(*os) << "tp: foo\n";
|
||||
(*os) << "tp: bar\n";
|
||||
(*os) << "tp: baz\n";
|
||||
(*os).close();
|
||||
|
||||
touch_exec("foo");
|
||||
touch_exec("baz");
|
||||
|
||||
try {
|
||||
(void)tools::read_atffile(tools::fs::path("Atffile"));
|
||||
ATF_FAIL("Missing file 'bar' did not raise an error");
|
||||
} catch (const tools::not_found_error< tools::fs::path >& e) {
|
||||
ATF_REQUIRE_EQ("bar", e.get_value().str());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Main.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
// Add the test cases for the parser class.
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_1);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_2);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_3);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_4);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_5);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_6);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_50);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_51);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_52);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_53);
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_54);
|
||||
|
||||
// Add the test cases for the atffile class.
|
||||
ATF_ADD_TEST_CASE(tcs, atffile_getters);
|
||||
|
||||
// Add the test cases for the free functions.
|
||||
ATF_ADD_TEST_CASE(tcs, read_ok_simple);
|
||||
ATF_ADD_TEST_CASE(tcs, read_ok_some_globs);
|
||||
ATF_ADD_TEST_CASE(tcs, read_missing_test_suite);
|
||||
ATF_ADD_TEST_CASE(tcs, read_missing_test_program);
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_AUTO_ARRAY_HPP)
|
||||
#define TOOLS_AUTO_ARRAY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace tools {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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());
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_AUTO_ARRAY_HPP)
|
@ -1,303 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "auto_array.hpp"
|
||||
#include "defs.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests for the "auto_array" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class test_array {
|
||||
public:
|
||||
int m_value;
|
||||
|
||||
static ssize_t m_nblocks;
|
||||
|
||||
static
|
||||
tools::auto_array< test_array >
|
||||
do_copy(tools::auto_array< test_array >& ta)
|
||||
{
|
||||
return tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Automated Testing Framework (atf)
|
||||
*
|
||||
* Copyright (c) 2010 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("incorrectly formatted metadata\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
135
tools/config.cpp
135
tools/config.cpp
@ -1,135 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "env.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
static std::map< std::string, std::string > m_variables;
|
||||
|
||||
static struct var {
|
||||
const char *name;
|
||||
const char *default_value;
|
||||
bool can_be_empty;
|
||||
} 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, },
|
||||
};
|
||||
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
assert(m_variables.empty());
|
||||
|
||||
for (struct var* v = vars; v->name != NULL; v++) {
|
||||
const std::string varname = tools::text::to_lower(v->name);
|
||||
|
||||
if (tools::env::has(v->name)) {
|
||||
const std::string envval = tools::env::get(v->name);
|
||||
if (envval.empty() && !v->can_be_empty)
|
||||
m_variables[varname] = v->default_value;
|
||||
else
|
||||
m_variables[varname] = envval;
|
||||
} else {
|
||||
m_variables[varname] = v->default_value;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!m_variables.empty());
|
||||
}
|
||||
|
||||
const std::string&
|
||||
tools::config::get(const std::string& varname)
|
||||
{
|
||||
if (m_variables.empty())
|
||||
init_variables();
|
||||
|
||||
assert(has(varname));
|
||||
return m_variables[varname];
|
||||
}
|
||||
|
||||
const std::map< std::string, std::string >&
|
||||
tools::config::get_all(void)
|
||||
{
|
||||
if (m_variables.empty())
|
||||
init_variables();
|
||||
|
||||
return m_variables;
|
||||
}
|
||||
|
||||
bool
|
||||
tools::config::has(const std::string& varname)
|
||||
{
|
||||
if (m_variables.empty())
|
||||
init_variables();
|
||||
|
||||
return m_variables.find(varname) != m_variables.end();
|
||||
}
|
||||
|
||||
namespace tools {
|
||||
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)
|
||||
{
|
||||
m_variables.clear();
|
||||
}
|
||||
} // namespace config
|
||||
} // namespace tools
|
@ -1,75 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_CONFIG_HPP)
|
||||
#define TOOLS_CONFIG_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
|
||||
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 tools
|
||||
|
||||
#endif // !defined(TOOLS_CONFIG_HPP)
|
@ -1,223 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "config_file.hpp"
|
||||
#include "defs.hpp"
|
||||
#include "env.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace impl = tools::config_file;
|
||||
namespace detail = tools::config_file::detail;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
namespace atf_config {
|
||||
|
||||
static const tools::parser::token_type eof_type = 0;
|
||||
static const tools::parser::token_type nl_type = 1;
|
||||
static const tools::parser::token_type text_type = 2;
|
||||
static const tools::parser::token_type dblquote_type = 3;
|
||||
static const tools::parser::token_type equal_type = 4;
|
||||
static const tools::parser::token_type hash_type = 5;
|
||||
|
||||
class tokenizer : public tools::parser::tokenizer< std::istream > {
|
||||
public:
|
||||
tokenizer(std::istream& is, size_t curline) :
|
||||
tools::parser::tokenizer< std::istream >
|
||||
(is, true, eof_type, nl_type, text_type, curline)
|
||||
{
|
||||
add_delim('=', equal_type);
|
||||
add_delim('#', hash_type);
|
||||
add_quote('"', dblquote_type);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace atf_config
|
||||
|
||||
class config_reader : public detail::atf_config_reader {
|
||||
vars_map m_vars;
|
||||
|
||||
void
|
||||
got_var(const std::string& var, const std::string& name)
|
||||
{
|
||||
m_vars[var] = name;
|
||||
}
|
||||
|
||||
public:
|
||||
config_reader(std::istream& is) :
|
||||
atf_config_reader(is)
|
||||
{
|
||||
}
|
||||
|
||||
const vars_map&
|
||||
get_vars(void)
|
||||
const
|
||||
{
|
||||
return m_vars;
|
||||
}
|
||||
};
|
||||
|
||||
template< class K, class V >
|
||||
static
|
||||
void
|
||||
merge_maps(std::map< K, V >& dest, const std::map< K, V >& src)
|
||||
{
|
||||
for (typename std::map< K, V >::const_iterator iter = src.begin();
|
||||
iter != src.end(); iter++)
|
||||
dest[(*iter).first] = (*iter).second;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
merge_config_file(const tools::fs::path& config_path,
|
||||
vars_map& config)
|
||||
{
|
||||
std::ifstream is(config_path.c_str());
|
||||
if (is) {
|
||||
config_reader reader(is);
|
||||
reader.read();
|
||||
merge_maps(config, reader.get_vars());
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
std::vector< tools::fs::path >
|
||||
get_config_dirs(void)
|
||||
{
|
||||
std::vector< tools::fs::path > dirs;
|
||||
dirs.push_back(tools::fs::path(tools::config::get("atf_confdir")));
|
||||
if (tools::env::has("HOME"))
|
||||
dirs.push_back(tools::fs::path(tools::env::get("HOME")) / ".atf");
|
||||
return dirs;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
detail::atf_config_reader::atf_config_reader(std::istream& is) :
|
||||
m_is(is)
|
||||
{
|
||||
}
|
||||
|
||||
detail::atf_config_reader::~atf_config_reader(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_config_reader::got_var(
|
||||
const std::string& var ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_config_reader::got_eof(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
detail::atf_config_reader::read(void)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_config;
|
||||
|
||||
std::pair< size_t, tools::parser::headers_map > hml =
|
||||
tools::parser::read_headers(m_is, 1);
|
||||
tools::parser::validate_content_type(hml.second,
|
||||
"application/X-atf-config", 1);
|
||||
|
||||
tokenizer tkz(m_is, hml.first);
|
||||
tools::parser::parser< tokenizer > p(tkz);
|
||||
|
||||
for (;;) {
|
||||
try {
|
||||
tools::parser::token t = p.expect(eof_type, hash_type, text_type,
|
||||
nl_type,
|
||||
"eof, #, new line or text");
|
||||
if (t.type() == eof_type)
|
||||
break;
|
||||
|
||||
if (t.type() == hash_type) {
|
||||
(void)p.rest_of_line();
|
||||
t = p.expect(nl_type, "new line");
|
||||
} else if (t.type() == text_type) {
|
||||
std::string name = t.text();
|
||||
|
||||
t = p.expect(equal_type, "equal sign");
|
||||
|
||||
t = p.expect(text_type, "word or quoted string");
|
||||
ATF_PARSER_CALLBACK(p, got_var(name, t.text()));
|
||||
|
||||
t = p.expect(nl_type, hash_type, "new line or comment");
|
||||
if (t.type() == hash_type) {
|
||||
(void)p.rest_of_line();
|
||||
t = p.expect(nl_type, "new line");
|
||||
}
|
||||
} else if (t.type() == nl_type) {
|
||||
} else
|
||||
std::abort();
|
||||
} catch (const parse_error& pe) {
|
||||
p.add_error(pe);
|
||||
p.reset(nl_type);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_PARSER_CALLBACK(p, got_eof());
|
||||
}
|
||||
|
||||
vars_map
|
||||
impl::merge_configs(const vars_map& lower,
|
||||
const vars_map& upper)
|
||||
{
|
||||
vars_map merged = lower;
|
||||
merge_maps(merged, upper);
|
||||
return merged;
|
||||
}
|
||||
|
||||
vars_map
|
||||
impl::read_config_files(const std::string& test_suite_name)
|
||||
{
|
||||
vars_map config;
|
||||
|
||||
const std::vector< tools::fs::path > dirs = get_config_dirs();
|
||||
for (std::vector< tools::fs::path >::const_iterator iter = dirs.begin();
|
||||
iter != dirs.end(); iter++) {
|
||||
merge_config_file((*iter) / "common.conf", config);
|
||||
merge_config_file((*iter) / (test_suite_name + ".conf"), config);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2010 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(TOOLS_CONFIG_FILE_HPP)
|
||||
#define TOOLS_CONFIG_FILE_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tools {
|
||||
namespace config_file {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class atf_config_reader {
|
||||
std::istream& m_is;
|
||||
|
||||
protected:
|
||||
virtual void got_var(const std::string&, const std::string &);
|
||||
virtual void got_eof(void);
|
||||
|
||||
public:
|
||||
atf_config_reader(std::istream&);
|
||||
virtual ~atf_config_reader(void);
|
||||
|
||||
void read(void);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::map< std::string, std::string > merge_configs(
|
||||
const std::map< std::string, std::string >&,
|
||||
const std::map< std::string, std::string >&);
|
||||
std::map< std::string, std::string > read_config_files(const std::string&);
|
||||
|
||||
} // namespace config_file
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_CONFIG_FILE_HPP)
|
@ -1,395 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2010 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++.hpp>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "config_file.hpp"
|
||||
#include "env.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
namespace impl = tools::config_file;
|
||||
namespace detail = tools::config_file::detail;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace atf {
|
||||
namespace config {
|
||||
|
||||
void __reinit(void);
|
||||
|
||||
} // namespace config
|
||||
} // namespace atf
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the "config" parser.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class config_reader : protected detail::atf_config_reader {
|
||||
void
|
||||
got_var(const std::string& name, const std::string& val)
|
||||
{
|
||||
m_calls.push_back("got_var(" + name + ", " + val + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_eof(void)
|
||||
{
|
||||
m_calls.push_back("got_eof()");
|
||||
}
|
||||
|
||||
public:
|
||||
config_reader(std::istream& is) :
|
||||
detail::atf_config_reader(is)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
read(void)
|
||||
{
|
||||
atf_config_reader::read();
|
||||
}
|
||||
|
||||
std::vector< std::string > m_calls;
|
||||
};
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_1);
|
||||
ATF_TEST_CASE_BODY(config_1)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_2);
|
||||
ATF_TEST_CASE_BODY(config_2)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"# This is a comment on a line of its own.\n"
|
||||
"# And this is another one.\n"
|
||||
"\n"
|
||||
" # Another after some whitespace.\n"
|
||||
"\n"
|
||||
"# The last one after an empty line.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_3);
|
||||
ATF_TEST_CASE_BODY(config_3)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"var1=value1\n"
|
||||
"var2 = value2\n"
|
||||
"var3 = value3\n"
|
||||
"var4 = value4\n"
|
||||
"\n"
|
||||
"var5=value5\n"
|
||||
" var6=value6\n"
|
||||
"\n"
|
||||
"var7 = \"This is a long value.\"\n"
|
||||
"var8 = \"Single-word\"\n"
|
||||
"var9 = \" Single-word \"\n"
|
||||
"var10 = Single-word\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_var(var1, value1)",
|
||||
"got_var(var2, value2)",
|
||||
"got_var(var3, value3)",
|
||||
"got_var(var4, value4)",
|
||||
"got_var(var5, value5)",
|
||||
"got_var(var6, value6)",
|
||||
"got_var(var7, This is a long value.)",
|
||||
"got_var(var8, Single-word)",
|
||||
"got_var(var9, Single-word )",
|
||||
"got_var(var10, Single-word)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_4);
|
||||
ATF_TEST_CASE_BODY(config_4)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo = bar # A comment.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_var(foo, bar)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_50);
|
||||
ATF_TEST_CASE_BODY(config_50)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected equal sign",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_51);
|
||||
ATF_TEST_CASE_BODY(config_51)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo bar\n"
|
||||
"baz\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `bar'; expected equal sign",
|
||||
"4: Unexpected token `<<NEWLINE>>'; expected equal sign",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_52);
|
||||
ATF_TEST_CASE_BODY(config_52)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo =\n"
|
||||
"bar = # A comment.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected word or quoted string",
|
||||
"4: Unexpected token `#'; expected word or quoted string",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_53);
|
||||
ATF_TEST_CASE_BODY(config_53)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo = \"Correct value\" # With comment.\n"
|
||||
"\n"
|
||||
"bar = # A comment.\n"
|
||||
"\n"
|
||||
"baz = \"Last variable\"\n"
|
||||
"\n"
|
||||
"# End of file.\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_var(foo, Correct value)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"5: Unexpected token `#'; expected word or quoted string",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(config_54);
|
||||
ATF_TEST_CASE_BODY(config_54)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-config; version=\"1\"\n"
|
||||
"\n"
|
||||
"foo = \"\n"
|
||||
"bar = \"text\n"
|
||||
"baz = \"te\\\"xt\n"
|
||||
"last = \"\\\"\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Missing double quotes before end of line",
|
||||
"4: Missing double quotes before end of line",
|
||||
"5: Missing double quotes before end of line",
|
||||
"6: Missing double quotes before end of line",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< config_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the free functions.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(merge_configs_both_empty);
|
||||
ATF_TEST_CASE_HEAD(merge_configs_both_empty) {}
|
||||
ATF_TEST_CASE_BODY(merge_configs_both_empty) {
|
||||
vars_map lower, upper;
|
||||
|
||||
ATF_REQUIRE(impl::merge_configs(lower, upper).empty());
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(merge_configs_lower_empty);
|
||||
ATF_TEST_CASE_HEAD(merge_configs_lower_empty) {}
|
||||
ATF_TEST_CASE_BODY(merge_configs_lower_empty) {
|
||||
vars_map lower, upper;
|
||||
upper["var"] = "value";
|
||||
|
||||
vars_map merged = impl::merge_configs(lower, upper);
|
||||
ATF_REQUIRE_EQ("value", merged["var"]);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(merge_configs_upper_empty);
|
||||
ATF_TEST_CASE_HEAD(merge_configs_upper_empty) {}
|
||||
ATF_TEST_CASE_BODY(merge_configs_upper_empty) {
|
||||
vars_map lower, upper;
|
||||
lower["var"] = "value";
|
||||
|
||||
vars_map merged = impl::merge_configs(lower, upper);
|
||||
ATF_REQUIRE_EQ("value", merged["var"]);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(merge_configs_mixed);
|
||||
ATF_TEST_CASE_HEAD(merge_configs_mixed) {}
|
||||
ATF_TEST_CASE_BODY(merge_configs_mixed) {
|
||||
vars_map lower, upper;
|
||||
lower["var1"] = "value1";
|
||||
lower["var2"] = "value2-l";
|
||||
upper["var2"] = "value2-u";
|
||||
upper["var3"] = "value3";
|
||||
|
||||
vars_map merged = impl::merge_configs(lower, upper);
|
||||
ATF_REQUIRE_EQ("value1", merged["var1"]);
|
||||
ATF_REQUIRE_EQ("value2-u", merged["var2"]);
|
||||
ATF_REQUIRE_EQ("value3", merged["var3"]);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(read_config_files_none);
|
||||
ATF_TEST_CASE_HEAD(read_config_files_none) {}
|
||||
ATF_TEST_CASE_BODY(read_config_files_none) {
|
||||
tools::env::set("ATF_CONFDIR", ".");
|
||||
atf::config::__reinit();
|
||||
ATF_REQUIRE(vars_map() == impl::read_config_files("test-suite"));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Main.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
ATF_ADD_TEST_CASE(tcs, config_1);
|
||||
ATF_ADD_TEST_CASE(tcs, config_2);
|
||||
ATF_ADD_TEST_CASE(tcs, config_3);
|
||||
ATF_ADD_TEST_CASE(tcs, config_4);
|
||||
ATF_ADD_TEST_CASE(tcs, config_50);
|
||||
ATF_ADD_TEST_CASE(tcs, config_51);
|
||||
ATF_ADD_TEST_CASE(tcs, config_52);
|
||||
ATF_ADD_TEST_CASE(tcs, config_53);
|
||||
ATF_ADD_TEST_CASE(tcs, config_54);
|
||||
|
||||
ATF_ADD_TEST_CASE(tcs, merge_configs_both_empty);
|
||||
ATF_ADD_TEST_CASE(tcs, merge_configs_lower_empty);
|
||||
ATF_ADD_TEST_CASE(tcs, merge_configs_upper_empty);
|
||||
ATF_ADD_TEST_CASE(tcs, merge_configs_mixed);
|
||||
|
||||
ATF_ADD_TEST_CASE(tcs, read_config_files_none);
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "env.hpp"
|
||||
#include "exceptions.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 tools {
|
||||
namespace config {
|
||||
void __reinit(void);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
set_env_var(const char* name, const char* val)
|
||||
{
|
||||
try {
|
||||
tools::env::set(name, val);
|
||||
} catch (const tools::system_error&) {
|
||||
ATF_FAIL(std::string("set_env_var(") + name + ", " + val +
|
||||
") failed");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
unset_env_var(const char* name)
|
||||
{
|
||||
try {
|
||||
tools::env::unset(name);
|
||||
} catch (const tools::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(tools::config::get(v->lc), test_value);
|
||||
else
|
||||
ATF_REQUIRE(tools::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();
|
||||
tools::config::__reinit();
|
||||
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
|
||||
ATF_REQUIRE(tools::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 (!tools::config::get(v->lc).empty()) {
|
||||
set_env_var(v->uc, "");
|
||||
tools::config::__reinit();
|
||||
if (v->can_be_empty)
|
||||
ATF_REQUIRE(tools::config::get(v->lc).empty());
|
||||
else
|
||||
ATF_REQUIRE(!tools::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);
|
||||
tools::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)
|
||||
{
|
||||
tools::config::__reinit();
|
||||
|
||||
// Check that the valid variables, and only those, are returned.
|
||||
std::map< std::string, std::string > vars = tools::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)
|
||||
{
|
||||
tools::config::__reinit();
|
||||
|
||||
// Check for all the variables that must exist.
|
||||
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
|
||||
ATF_REQUIRE(tools::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(!tools::config::has(v->uc));
|
||||
|
||||
// Check for some other variables that cannot exist.
|
||||
ATF_REQUIRE(!tools::config::has("foo"));
|
||||
ATF_REQUIRE(!tools::config::has("BAR"));
|
||||
ATF_REQUIRE(!tools::config::has("atf_foo"));
|
||||
ATF_REQUIRE(!tools::config::has("ATF_BAR"));
|
||||
ATF_REQUIRE(!tools::config::has("atf_shel"));
|
||||
ATF_REQUIRE(!tools::config::has("atf_shells"));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
//
|
||||
// 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(TOOLS_DEFS_HPP)
|
||||
#define TOOLS_DEFS_HPP
|
||||
|
||||
#define ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(a, b) @ATTRIBUTE_FORMAT_PRINTF@
|
||||
#define ATF_DEFS_ATTRIBUTE_NORETURN @ATTRIBUTE_NORETURN@
|
||||
#define ATF_DEFS_ATTRIBUTE_UNUSED @ATTRIBUTE_UNUSED@
|
||||
|
||||
#endif /* !defined(TOOLS_DEFS_HPP) */
|
102
tools/env.cpp
102
tools/env.cpp
@ -1,102 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "bconfig.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "env.hpp"
|
||||
#include "exceptions.hpp"
|
||||
|
||||
namespace impl = tools::env;
|
||||
#define IMPL_NAME "tools::env"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Free functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
std::string
|
||||
impl::get(const std::string& name)
|
||||
{
|
||||
const char* val = getenv(name.c_str());
|
||||
assert(val != NULL);
|
||||
return val;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::has(const std::string& name)
|
||||
{
|
||||
return getenv(name.c_str()) != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
impl::set(const std::string& name, const std::string& val)
|
||||
{
|
||||
#if defined(HAVE_SETENV)
|
||||
if (setenv(name.c_str(), val.c_str(), 1) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::set",
|
||||
"Cannot set environment variable '" + name +
|
||||
"' to '" + val + "'",
|
||||
errno);
|
||||
#elif defined(HAVE_PUTENV)
|
||||
const std::string buf = name + "=" + val;
|
||||
if (putenv(strdup(buf.c_str())) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::set",
|
||||
"Cannot set environment variable '" + name +
|
||||
"' to '" + val + "'",
|
||||
errno);
|
||||
#else
|
||||
# error "Don't know how to set an environment variable."
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
impl::unset(const std::string& name)
|
||||
{
|
||||
#if defined(HAVE_UNSETENV)
|
||||
unsetenv(name.c_str());
|
||||
#elif defined(HAVE_PUTENV)
|
||||
const std::string buf = name + "=";
|
||||
|
||||
if (putenv(strdup(buf.c_str())) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::unset",
|
||||
"Cannot unset environment variable '" +
|
||||
name + "'", errno);
|
||||
#else
|
||||
# error "Don't know how to unset an environment variable."
|
||||
#endif
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_ENV_HPP)
|
||||
#define TOOLS_ENV_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
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 tools
|
||||
|
||||
#endif // !defined(TOOLS_ENV_HPP)
|
@ -1,91 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <atf-c++.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(tools::env::has("PATH"));
|
||||
ATF_REQUIRE(!tools::env::get("PATH").empty());
|
||||
|
||||
ATF_REQUIRE(!tools::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(tools::env::has("PATH"));
|
||||
const std::string& oldval = tools::env::get("PATH");
|
||||
tools::env::set("PATH", "foo-bar");
|
||||
ATF_REQUIRE(tools::env::get("PATH") != oldval);
|
||||
ATF_REQUIRE_EQ(tools::env::get("PATH"), "foo-bar");
|
||||
|
||||
ATF_REQUIRE(!tools::env::has("_UNDEFINED_VARIABLE_"));
|
||||
tools::env::set("_UNDEFINED_VARIABLE_", "foo2-bar2");
|
||||
ATF_REQUIRE_EQ(tools::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(tools::env::has("PATH"));
|
||||
tools::env::unset("PATH");
|
||||
ATF_REQUIRE(!tools::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);
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "exceptions.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "system_error" type.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
tools::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)
|
||||
{
|
||||
}
|
||||
|
||||
tools::system_error::~system_error(void)
|
||||
throw()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
tools::system_error::code(void)
|
||||
const
|
||||
throw()
|
||||
{
|
||||
return m_sys_err;
|
||||
}
|
||||
|
||||
const char*
|
||||
tools::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";
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_EXCEPTIONS_HPP)
|
||||
#define TOOLS_EXCEPTIONS_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_EXCEPTIONS_HPP)
|
@ -1,81 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "expand.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace impl = tools::expand;
|
||||
#define IMPL_NAME "tools::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 tools::text::match(candidate, glob_to_regex(glob));
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_EXPAND_HPP)
|
||||
#define TOOLS_EXPAND_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tools {
|
||||
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 tools
|
||||
|
||||
#endif // !defined(TOOLS_EXPAND_HPP)
|
@ -1,272 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <atf-c++.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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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);
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Automated Testing Framework (atf)
|
||||
*
|
||||
* Copyright (c) 2010 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 <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(pass_and_pass);
|
||||
ATF_TC_BODY(pass_and_pass, tc)
|
||||
{
|
||||
atf_tc_expect_pass();
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(pass_but_fail_requirement);
|
||||
ATF_TC_BODY(pass_but_fail_requirement, tc)
|
||||
{
|
||||
atf_tc_expect_pass();
|
||||
atf_tc_fail("Some reason");
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(pass_but_fail_check);
|
||||
ATF_TC_BODY(pass_but_fail_check, tc)
|
||||
{
|
||||
atf_tc_expect_pass();
|
||||
atf_tc_fail_nonfatal("Some reason");
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(fail_and_fail_requirement);
|
||||
ATF_TC_BODY(fail_and_fail_requirement, tc)
|
||||
{
|
||||
atf_tc_expect_fail("Fail %s", "reason");
|
||||
atf_tc_fail("The failure");
|
||||
atf_tc_expect_pass();
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(fail_and_fail_check);
|
||||
ATF_TC_BODY(fail_and_fail_check, tc)
|
||||
{
|
||||
atf_tc_expect_fail("Fail first");
|
||||
atf_tc_fail_nonfatal("abc");
|
||||
atf_tc_expect_pass();
|
||||
|
||||
atf_tc_expect_fail("And fail again");
|
||||
atf_tc_fail_nonfatal("def");
|
||||
atf_tc_expect_pass();
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(fail_but_pass);
|
||||
ATF_TC_BODY(fail_but_pass, tc)
|
||||
{
|
||||
atf_tc_expect_fail("Fail first");
|
||||
atf_tc_fail_nonfatal("abc");
|
||||
atf_tc_expect_pass();
|
||||
|
||||
atf_tc_expect_fail("Will not fail");
|
||||
atf_tc_expect_pass();
|
||||
|
||||
atf_tc_expect_fail("And fail again");
|
||||
atf_tc_fail_nonfatal("def");
|
||||
atf_tc_expect_pass();
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(exit_any_and_exit);
|
||||
ATF_TC_BODY(exit_any_and_exit, tc)
|
||||
{
|
||||
atf_tc_expect_exit(-1, "Call will exit");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(exit_code_and_exit);
|
||||
ATF_TC_BODY(exit_code_and_exit, tc)
|
||||
{
|
||||
atf_tc_expect_exit(123, "Call will exit");
|
||||
exit(123);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(exit_but_pass);
|
||||
ATF_TC_BODY(exit_but_pass, tc)
|
||||
{
|
||||
atf_tc_expect_exit(-1, "Call won't exit");
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(signal_any_and_signal);
|
||||
ATF_TC_BODY(signal_any_and_signal, tc)
|
||||
{
|
||||
atf_tc_expect_signal(-1, "Call will signal");
|
||||
kill(getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(signal_no_and_signal);
|
||||
ATF_TC_BODY(signal_no_and_signal, tc)
|
||||
{
|
||||
atf_tc_expect_signal(SIGHUP, "Call will signal");
|
||||
kill(getpid(), SIGHUP);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(signal_but_pass);
|
||||
ATF_TC_BODY(signal_but_pass, tc)
|
||||
{
|
||||
atf_tc_expect_signal(-1, "Call won't signal");
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(death_and_exit);
|
||||
ATF_TC_BODY(death_and_exit, tc)
|
||||
{
|
||||
atf_tc_expect_death("Exit case");
|
||||
exit(123);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(death_and_signal);
|
||||
ATF_TC_BODY(death_and_signal, tc)
|
||||
{
|
||||
atf_tc_expect_death("Signal case");
|
||||
kill(getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
ATF_TC_WITHOUT_HEAD(death_but_pass);
|
||||
ATF_TC_BODY(death_but_pass, tc)
|
||||
{
|
||||
atf_tc_expect_death("Call won't die");
|
||||
}
|
||||
|
||||
ATF_TC(timeout_and_hang);
|
||||
ATF_TC_HEAD(timeout_and_hang, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "timeout", "1");
|
||||
}
|
||||
ATF_TC_BODY(timeout_and_hang, tc)
|
||||
{
|
||||
atf_tc_expect_timeout("Will overrun");
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
ATF_TC(timeout_but_pass);
|
||||
ATF_TC_HEAD(timeout_but_pass, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "timeout", "1");
|
||||
}
|
||||
ATF_TC_BODY(timeout_but_pass, tc)
|
||||
{
|
||||
atf_tc_expect_timeout("Will just exit");
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, pass_and_pass);
|
||||
ATF_TP_ADD_TC(tp, pass_but_fail_requirement);
|
||||
ATF_TP_ADD_TC(tp, pass_but_fail_check);
|
||||
ATF_TP_ADD_TC(tp, fail_and_fail_requirement);
|
||||
ATF_TP_ADD_TC(tp, fail_and_fail_check);
|
||||
ATF_TP_ADD_TC(tp, fail_but_pass);
|
||||
ATF_TP_ADD_TC(tp, exit_any_and_exit);
|
||||
ATF_TP_ADD_TC(tp, exit_code_and_exit);
|
||||
ATF_TP_ADD_TC(tp, exit_but_pass);
|
||||
ATF_TP_ADD_TC(tp, signal_any_and_signal);
|
||||
ATF_TP_ADD_TC(tp, signal_no_and_signal);
|
||||
ATF_TP_ADD_TC(tp, signal_but_pass);
|
||||
ATF_TP_ADD_TC(tp, death_and_exit);
|
||||
ATF_TP_ADD_TC(tp, death_and_signal);
|
||||
ATF_TP_ADD_TC(tp, death_but_pass);
|
||||
ATF_TP_ADD_TC(tp, timeout_and_hang);
|
||||
ATF_TP_ADD_TC(tp, timeout_but_pass);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
ATF_TEST_CASE(main);
|
||||
ATF_TEST_CASE_HEAD(main)
|
||||
{
|
||||
set_md_var("descr", "Helper test case that always fails");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(main)
|
||||
{
|
||||
fail("This always fails");
|
||||
}
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
ATF_ADD_TEST_CASE(tcs, main);
|
||||
}
|
744
tools/fs.cpp
744
tools/fs.cpp
@ -1,744 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#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 <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "auto_array.hpp"
|
||||
#include "env.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "process.hpp"
|
||||
#include "text.hpp"
|
||||
#include "user.hpp"
|
||||
|
||||
namespace impl = tools::fs;
|
||||
#define IMPL_NAME "tools::fs"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static void cleanup_aux(const impl::path&, dev_t, bool);
|
||||
static void cleanup_aux_dir(const impl::path&, const impl::file_info&,
|
||||
bool);
|
||||
static void do_unmount(const impl::path&);
|
||||
static bool safe_access(const impl::path&, int, int);
|
||||
|
||||
static const int access_f = 1 << 0;
|
||||
static const int access_r = 1 << 1;
|
||||
static const int access_w = 1 << 2;
|
||||
static const int access_x = 1 << 3;
|
||||
|
||||
//!
|
||||
//! An implementation of access(2) but using the effective user value
|
||||
//! instead of the real one. Also avoids false positives for root when
|
||||
//! asking for execute permissions, which appear in SunOS.
|
||||
//!
|
||||
static
|
||||
void
|
||||
eaccess(const tools::fs::path& p, int mode)
|
||||
{
|
||||
assert(mode & access_f || mode & access_r ||
|
||||
mode & access_w || mode & access_x);
|
||||
|
||||
struct stat st;
|
||||
if (lstat(p.c_str(), &st) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::eaccess",
|
||||
"Cannot get information from file " +
|
||||
p.str(), errno);
|
||||
|
||||
/* Early return if we are only checking for existence and the file
|
||||
* exists (stat call returned). */
|
||||
if (mode & access_f)
|
||||
return;
|
||||
|
||||
bool ok = false;
|
||||
if (tools::user::is_root()) {
|
||||
if (!ok && !(mode & access_x)) {
|
||||
/* Allow root to read/write any file. */
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
|
||||
/* Allow root to execute the file if any of its execution bits
|
||||
* are set. */
|
||||
ok = true;
|
||||
}
|
||||
} else {
|
||||
if (!ok && (tools::user::euid() == st.st_uid)) {
|
||||
ok = ((mode & access_r) && (st.st_mode & S_IRUSR)) ||
|
||||
((mode & access_w) && (st.st_mode & S_IWUSR)) ||
|
||||
((mode & access_x) && (st.st_mode & S_IXUSR));
|
||||
}
|
||||
if (!ok && tools::user::is_member_of_group(st.st_gid)) {
|
||||
ok = ((mode & access_r) && (st.st_mode & S_IRGRP)) ||
|
||||
((mode & access_w) && (st.st_mode & S_IWGRP)) ||
|
||||
((mode & access_x) && (st.st_mode & S_IXGRP));
|
||||
}
|
||||
if (!ok && ((tools::user::euid() != st.st_uid) &&
|
||||
!tools::user::is_member_of_group(st.st_gid))) {
|
||||
ok = ((mode & access_r) && (st.st_mode & S_IROTH)) ||
|
||||
((mode & access_w) && (st.st_mode & S_IWOTH)) ||
|
||||
((mode & access_x) && (st.st_mode & S_IXOTH));
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
throw tools::system_error(IMPL_NAME "::eaccess", "Access check failed",
|
||||
EACCES);
|
||||
}
|
||||
|
||||
//!
|
||||
//! \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)
|
||||
{
|
||||
try {
|
||||
eaccess(p, mode);
|
||||
return true;
|
||||
} catch (const tools::system_error& e) {
|
||||
if (e.code() == experr)
|
||||
return false;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// The cleanup routines below are tricky: they are executed immediately after
|
||||
// a test case's death, and after we have forcibly killed any stale processes.
|
||||
// However, even if the processes are dead, this does not mean that the file
|
||||
// system we are scanning is stable. In particular, if the test case has
|
||||
// mounted file systems through fuse/puffs, the fact that the processes died
|
||||
// does not mean that the file system is truly unmounted.
|
||||
//
|
||||
// The code below attempts to cope with this by catching errors and either
|
||||
// ignoring them or retrying the actions on the same file/directory a few times
|
||||
// before giving up.
|
||||
static const int max_retries = 5;
|
||||
static const int retry_delay_in_seconds = 1;
|
||||
|
||||
// The erase parameter in this routine is to control nested mount points.
|
||||
// We want to descend into a mount point to unmount anything that is
|
||||
// mounted under it, but we do not want to delete any files while doing
|
||||
// this traversal. In other words, we erase files until we cross the
|
||||
// first mount point, and after that point we only scan and unmount.
|
||||
static
|
||||
void
|
||||
cleanup_aux(const impl::path& p, dev_t parent_device, bool erase)
|
||||
{
|
||||
try {
|
||||
impl::file_info fi(p);
|
||||
|
||||
if (fi.get_type() == impl::file_info::dir_type)
|
||||
cleanup_aux_dir(p, fi, fi.get_device() == parent_device);
|
||||
|
||||
if (fi.get_device() != parent_device)
|
||||
do_unmount(p);
|
||||
|
||||
if (erase) {
|
||||
if (fi.get_type() == impl::file_info::dir_type)
|
||||
impl::rmdir(p);
|
||||
else
|
||||
impl::remove(p);
|
||||
}
|
||||
} catch (const tools::system_error& e) {
|
||||
if (e.code() != ENOENT && e.code() != ENOTDIR)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
cleanup_aux_dir(const impl::path& p, const impl::file_info& fi,
|
||||
bool erase)
|
||||
{
|
||||
if (erase && ((fi.get_mode() & S_IRWXU) != S_IRWXU)) {
|
||||
int retries = max_retries;
|
||||
retry_chmod:
|
||||
if (chmod(p.c_str(), fi.get_mode() | S_IRWXU) == -1) {
|
||||
if (retries > 0) {
|
||||
retries--;
|
||||
::sleep(retry_delay_in_seconds);
|
||||
goto retry_chmod;
|
||||
} else {
|
||||
throw tools::system_error(IMPL_NAME "::cleanup(" +
|
||||
p.str() + ")", "chmod(2) failed",
|
||||
errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set< std::string > subdirs;
|
||||
{
|
||||
bool ok = false;
|
||||
int retries = max_retries;
|
||||
while (!ok) {
|
||||
assert(retries > 0);
|
||||
try {
|
||||
const impl::directory d(p);
|
||||
subdirs = d.names();
|
||||
ok = true;
|
||||
} catch (const tools::system_error& e) {
|
||||
retries--;
|
||||
if (retries == 0)
|
||||
throw e;
|
||||
::sleep(retry_delay_in_seconds);
|
||||
}
|
||||
}
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
for (std::set< std::string >::const_iterator iter = subdirs.begin();
|
||||
iter != subdirs.end(); iter++) {
|
||||
const std::string& name = *iter;
|
||||
if (name != "." && name != "..")
|
||||
cleanup_aux(p / name, fi.get_device(), erase);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
do_unmount(const impl::path& in_path)
|
||||
{
|
||||
// At least, FreeBSD's unmount(2) requires the path to be absolute.
|
||||
// Let's make it absolute in all cases just to be safe that this does
|
||||
// not affect other systems.
|
||||
const impl::path& abs_path = in_path.is_absolute() ?
|
||||
in_path : in_path.to_absolute();
|
||||
|
||||
#if defined(HAVE_UNMOUNT)
|
||||
int retries = max_retries;
|
||||
retry_unmount:
|
||||
if (unmount(abs_path.c_str(), 0) == -1) {
|
||||
if (errno == EBUSY && retries > 0) {
|
||||
retries--;
|
||||
::sleep(retry_delay_in_seconds);
|
||||
goto retry_unmount;
|
||||
} else {
|
||||
throw tools::system_error(IMPL_NAME "::cleanup(" + in_path.str() +
|
||||
")", "unmount(2) failed", errno);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// We could use umount(2) instead if it was available... but
|
||||
// trying to do so under, e.g. Linux, is a nightmare because we
|
||||
// also have to update /etc/mtab to match what we did. It is
|
||||
// stools::fser to just leave the system-specific umount(8) tool deal
|
||||
// with it, at least for now.
|
||||
|
||||
const impl::path prog("umount");
|
||||
tools::process::argv_array argv("umount", abs_path.c_str(), NULL);
|
||||
|
||||
tools::process::status s = tools::process::exec(prog, argv,
|
||||
tools::process::stream_inherit(), tools::process::stream_inherit());
|
||||
if (!s.exited() || s.exitstatus() != EXIT_SUCCESS)
|
||||
throw std::runtime_error("Call to unmount failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
normalize(const std::string& in)
|
||||
{
|
||||
assert(!in.empty());
|
||||
|
||||
std::string out;
|
||||
|
||||
std::string::size_type pos = 0;
|
||||
do {
|
||||
const std::string::size_type next_pos = in.find('/', pos);
|
||||
|
||||
const std::string component = in.substr(pos, next_pos - pos);
|
||||
if (!component.empty()) {
|
||||
if (pos == 0)
|
||||
out += component;
|
||||
else if (component != ".")
|
||||
out += "/" + component;
|
||||
}
|
||||
|
||||
if (next_pos == std::string::npos)
|
||||
pos = next_pos;
|
||||
else
|
||||
pos = next_pos + 1;
|
||||
} while (pos != std::string::npos);
|
||||
|
||||
return out.empty() ? "/" : out;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "path" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::path::path(const std::string& s) :
|
||||
m_data(normalize(s))
|
||||
{
|
||||
}
|
||||
|
||||
impl::path::~path(void)
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
impl::path::c_str(void)
|
||||
const
|
||||
{
|
||||
return m_data.c_str();
|
||||
}
|
||||
|
||||
std::string
|
||||
impl::path::str(void)
|
||||
const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::path::is_absolute(void)
|
||||
const
|
||||
{
|
||||
return !m_data.empty() && m_data[0] == '/';
|
||||
}
|
||||
|
||||
bool
|
||||
impl::path::is_root(void)
|
||||
const
|
||||
{
|
||||
return m_data == "/";
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::path::branch_path(void)
|
||||
const
|
||||
{
|
||||
const std::string::size_type endpos = m_data.rfind('/');
|
||||
if (endpos == std::string::npos)
|
||||
return path(".");
|
||||
else if (endpos == 0)
|
||||
return path("/");
|
||||
else
|
||||
return path(m_data.substr(0, endpos));
|
||||
}
|
||||
|
||||
std::string
|
||||
impl::path::leaf_name(void)
|
||||
const
|
||||
{
|
||||
std::string::size_type begpos = m_data.rfind('/');
|
||||
if (begpos == std::string::npos)
|
||||
begpos = 0;
|
||||
else
|
||||
begpos++;
|
||||
|
||||
return m_data.substr(begpos);
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::path::to_absolute(void)
|
||||
const
|
||||
{
|
||||
assert(!is_absolute());
|
||||
return get_current_dir() / m_data;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::path::operator==(const path& p)
|
||||
const
|
||||
{
|
||||
return m_data == p.m_data;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::path::operator!=(const path& p)
|
||||
const
|
||||
{
|
||||
return m_data != p.m_data;
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::path::operator/(const std::string& p)
|
||||
const
|
||||
{
|
||||
return path(m_data + "/" + normalize(p));
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::path::operator/(const path& p)
|
||||
const
|
||||
{
|
||||
return path(m_data) / p.m_data;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::path::operator<(const path& p)
|
||||
const
|
||||
{
|
||||
return std::strcmp(m_data.c_str(), p.m_data.c_str()) < 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "file_info" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
const int impl::file_info::blk_type = 1;
|
||||
const int impl::file_info::chr_type = 2;
|
||||
const int impl::file_info::dir_type = 3;
|
||||
const int impl::file_info::fifo_type = 4;
|
||||
const int impl::file_info::lnk_type = 5;
|
||||
const int impl::file_info::reg_type = 6;
|
||||
const int impl::file_info::sock_type = 7;
|
||||
const int impl::file_info::wht_type = 8;
|
||||
|
||||
impl::file_info::file_info(const path& p)
|
||||
{
|
||||
if (lstat(p.c_str(), &m_sb) == -1)
|
||||
throw system_error(IMPL_NAME "::file_info",
|
||||
"Cannot get information of " + p.str() + "; " +
|
||||
"lstat(2) failed", errno);
|
||||
|
||||
int type = m_sb.st_mode & S_IFMT;
|
||||
switch (type) {
|
||||
case S_IFBLK: m_type = blk_type; break;
|
||||
case S_IFCHR: m_type = chr_type; break;
|
||||
case S_IFDIR: m_type = dir_type; break;
|
||||
case S_IFIFO: m_type = fifo_type; break;
|
||||
case S_IFLNK: m_type = lnk_type; break;
|
||||
case S_IFREG: m_type = reg_type; break;
|
||||
case S_IFSOCK: m_type = sock_type; break;
|
||||
#if defined(S_IFWHT)
|
||||
case S_IFWHT: m_type = wht_type; break;
|
||||
#endif
|
||||
default:
|
||||
throw system_error(IMPL_NAME "::file_info", "Unknown file type "
|
||||
"error", EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
impl::file_info::~file_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
dev_t
|
||||
impl::file_info::get_device(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_dev;
|
||||
}
|
||||
|
||||
ino_t
|
||||
impl::file_info::get_inode(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_ino;
|
||||
}
|
||||
|
||||
mode_t
|
||||
impl::file_info::get_mode(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & ~S_IFMT;
|
||||
}
|
||||
|
||||
off_t
|
||||
impl::file_info::get_size(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_size;
|
||||
}
|
||||
|
||||
int
|
||||
impl::file_info::get_type(void)
|
||||
const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_owner_readable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IRUSR;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_owner_writable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IWUSR;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_owner_executable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IXUSR;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_group_readable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IRGRP;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_group_writable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IWGRP;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_group_executable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IXGRP;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_other_readable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IROTH;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_other_writable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IWOTH;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_info::is_other_executable(void)
|
||||
const
|
||||
{
|
||||
return m_sb.st_mode & S_IXOTH;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "temp_dir" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::temp_dir::temp_dir(const path& p)
|
||||
{
|
||||
tools::auto_array< char > buf(new char[p.str().length() + 1]);
|
||||
std::strcpy(buf.get(), p.c_str());
|
||||
if (::mkdtemp(buf.get()) == NULL)
|
||||
throw tools::system_error(IMPL_NAME "::temp_dir::temp_dir(" +
|
||||
p.str() + ")", "mkdtemp(3) failed",
|
||||
errno);
|
||||
|
||||
m_path.reset(new path(buf.get()));
|
||||
}
|
||||
|
||||
impl::temp_dir::~temp_dir(void)
|
||||
{
|
||||
cleanup(*m_path);
|
||||
}
|
||||
|
||||
const impl::path&
|
||||
impl::temp_dir::get_path(void)
|
||||
const
|
||||
{
|
||||
return *m_path;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Free functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
impl::exists(const path& p)
|
||||
{
|
||||
try {
|
||||
eaccess(p, access_f);
|
||||
return true;
|
||||
} catch (const system_error& e) {
|
||||
if (e.code() == ENOENT)
|
||||
return false;
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
impl::have_prog_in_path(const std::string& prog)
|
||||
{
|
||||
assert(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 (!tools::env::has("PATH"))
|
||||
throw std::runtime_error("PATH not defined in the environment");
|
||||
std::vector< std::string > dirs =
|
||||
tools::text::split(tools::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, access_x, EACCES);
|
||||
}
|
||||
|
||||
void
|
||||
impl::remove(const path& p)
|
||||
{
|
||||
if (file_info(p).get_type() == file_info::dir_type)
|
||||
throw tools::system_error(IMPL_NAME "::remove(" + p.str() + ")",
|
||||
"Is a directory",
|
||||
EPERM);
|
||||
if (::unlink(p.c_str()) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::remove(" + p.str() + ")",
|
||||
"unlink(" + p.str() + ") failed",
|
||||
errno);
|
||||
}
|
||||
|
||||
void
|
||||
impl::rmdir(const path& p)
|
||||
{
|
||||
if (::rmdir(p.c_str())) {
|
||||
if (errno == EEXIST) {
|
||||
/* Some operating systems (e.g. OpenSolaris 200906) return
|
||||
* EEXIST instead of ENOTEMPTY for non-empty directories.
|
||||
* Homogenize the return value so that callers don't need
|
||||
* to bother about differences in operating systems. */
|
||||
errno = ENOTEMPTY;
|
||||
}
|
||||
throw system_error(IMPL_NAME "::rmdir", "Cannot remove directory",
|
||||
errno);
|
||||
}
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::change_directory(const path& dir)
|
||||
{
|
||||
path olddir = get_current_dir();
|
||||
|
||||
if (olddir != dir) {
|
||||
if (::chdir(dir.c_str()) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::chdir(" + dir.str() + ")",
|
||||
"chdir(2) failed", errno);
|
||||
}
|
||||
|
||||
return olddir;
|
||||
}
|
||||
|
||||
void
|
||||
impl::cleanup(const path& p)
|
||||
{
|
||||
impl::file_info fi(p);
|
||||
cleanup_aux(p, fi.get_device(), true);
|
||||
}
|
||||
|
||||
impl::path
|
||||
impl::get_current_dir(void)
|
||||
{
|
||||
std::auto_ptr< char > cwd;
|
||||
#if defined(HAVE_GETCWD_DYN)
|
||||
cwd.reset(getcwd(NULL, 0));
|
||||
#else
|
||||
cwd.reset(getcwd(NULL, MAXPATHLEN));
|
||||
#endif
|
||||
if (cwd.get() == NULL)
|
||||
throw tools::system_error(IMPL_NAME "::get_current_dir()",
|
||||
"getcwd() failed", errno);
|
||||
|
||||
return path(cwd.get());
|
||||
}
|
377
tools/fs.hpp
377
tools/fs.hpp
@ -1,377 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_FS_HPP)
|
||||
#define TOOLS_FS_HPP
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
}
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
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.
|
||||
//!
|
||||
std::string m_data;
|
||||
|
||||
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 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 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 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 {
|
||||
int m_type;
|
||||
struct stat m_sb;
|
||||
|
||||
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 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;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "temp_dir" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class temp_dir {
|
||||
std::auto_ptr< tools::fs::path > m_path;
|
||||
|
||||
public:
|
||||
temp_dir(const tools::fs::path&);
|
||||
~temp_dir(void);
|
||||
|
||||
const tools::fs::path& get_path(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&);
|
||||
|
||||
tools::fs::path change_directory(const tools::fs::path&);
|
||||
void cleanup(const tools::fs::path&);
|
||||
tools::fs::path get_current_dir(void);
|
||||
|
||||
} // namespace fs
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_FS_HPP)
|
@ -1,743 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
}
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "exceptions.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "user.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static
|
||||
void
|
||||
create_file(const char *name)
|
||||
{
|
||||
std::ofstream os(name);
|
||||
os.close();
|
||||
}
|
||||
|
||||
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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::fs::file_info;
|
||||
using tools::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 tools::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 tools::fs::directory;
|
||||
using tools::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 tools::fs::directory;
|
||||
using tools::fs::file_info;
|
||||
using tools::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 tools::fs::directory;
|
||||
using tools::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 tools::fs::file_info;
|
||||
using tools::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 tools::fs::file_info;
|
||||
using tools::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 "temp_dir" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(temp_dir_raii);
|
||||
ATF_TEST_CASE_HEAD(temp_dir_raii)
|
||||
{
|
||||
set_md_var("descr", "Tests the RAII behavior of the temp_dir class");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(temp_dir_raii)
|
||||
{
|
||||
tools::fs::path t1("non-existent");
|
||||
tools::fs::path t2("non-existent");
|
||||
|
||||
{
|
||||
tools::fs::path tmpl("testdir.XXXXXX");
|
||||
tools::fs::temp_dir td1(tmpl);
|
||||
tools::fs::temp_dir td2(tmpl);
|
||||
t1 = td1.get_path();
|
||||
t2 = td2.get_path();
|
||||
ATF_REQUIRE(t1.str().find("XXXXXX") == std::string::npos);
|
||||
ATF_REQUIRE(t2.str().find("XXXXXX") == std::string::npos);
|
||||
ATF_REQUIRE(t1 != t2);
|
||||
ATF_REQUIRE(!tools::fs::exists(tmpl));
|
||||
ATF_REQUIRE( tools::fs::exists(t1));
|
||||
ATF_REQUIRE( tools::fs::exists(t2));
|
||||
|
||||
tools::fs::file_info fi1(t1);
|
||||
ATF_REQUIRE( fi1.is_owner_readable());
|
||||
ATF_REQUIRE( fi1.is_owner_writable());
|
||||
ATF_REQUIRE( fi1.is_owner_executable());
|
||||
ATF_REQUIRE(!fi1.is_group_readable());
|
||||
ATF_REQUIRE(!fi1.is_group_writable());
|
||||
ATF_REQUIRE(!fi1.is_group_executable());
|
||||
ATF_REQUIRE(!fi1.is_other_readable());
|
||||
ATF_REQUIRE(!fi1.is_other_writable());
|
||||
ATF_REQUIRE(!fi1.is_other_executable());
|
||||
|
||||
tools::fs::file_info fi2(t2);
|
||||
ATF_REQUIRE( fi2.is_owner_readable());
|
||||
ATF_REQUIRE( fi2.is_owner_writable());
|
||||
ATF_REQUIRE( fi2.is_owner_executable());
|
||||
ATF_REQUIRE(!fi2.is_group_readable());
|
||||
ATF_REQUIRE(!fi2.is_group_writable());
|
||||
ATF_REQUIRE(!fi2.is_group_executable());
|
||||
ATF_REQUIRE(!fi2.is_other_readable());
|
||||
ATF_REQUIRE(!fi2.is_other_writable());
|
||||
ATF_REQUIRE(!fi2.is_other_executable());
|
||||
}
|
||||
|
||||
ATF_REQUIRE(t1.str() != "non-existent");
|
||||
ATF_REQUIRE(!tools::fs::exists(t1));
|
||||
ATF_REQUIRE(t2.str() != "non-existent");
|
||||
ATF_REQUIRE(!tools::fs::exists(t2));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 tools::fs::exists;
|
||||
using tools::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 tools::fs::is_executable;
|
||||
using tools::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 tools::fs::exists;
|
||||
using tools::fs::path;
|
||||
using tools::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(tools::system_error, remove(path("files/dir")));
|
||||
ATF_REQUIRE( exists(path("files/dir")));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(cleanup);
|
||||
ATF_TEST_CASE_HEAD(cleanup)
|
||||
{
|
||||
set_md_var("descr", "Tests the cleanup function");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(cleanup)
|
||||
{
|
||||
using tools::fs::cleanup;
|
||||
|
||||
::mkdir("root", 0755);
|
||||
::mkdir("root/dir", 0755);
|
||||
::mkdir("root/dir/1", 0100);
|
||||
::mkdir("root/dir/2", 0644);
|
||||
create_file("root/reg");
|
||||
|
||||
tools::fs::path p("root");
|
||||
ATF_REQUIRE(tools::fs::exists(p));
|
||||
ATF_REQUIRE(tools::fs::exists(p / "dir"));
|
||||
ATF_REQUIRE(tools::fs::exists(p / "dir/1"));
|
||||
ATF_REQUIRE(tools::fs::exists(p / "dir/2"));
|
||||
ATF_REQUIRE(tools::fs::exists(p / "reg"));
|
||||
cleanup(p);
|
||||
ATF_REQUIRE(!tools::fs::exists(p));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(cleanup_eacces_on_root);
|
||||
ATF_TEST_CASE_HEAD(cleanup_eacces_on_root)
|
||||
{
|
||||
set_md_var("descr", "Tests the cleanup function");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(cleanup_eacces_on_root)
|
||||
{
|
||||
using tools::fs::cleanup;
|
||||
|
||||
::mkdir("aux", 0755);
|
||||
::mkdir("aux/root", 0755);
|
||||
ATF_REQUIRE(::chmod("aux", 0555) != -1);
|
||||
|
||||
try {
|
||||
cleanup(tools::fs::path("aux/root"));
|
||||
ATF_REQUIRE(tools::user::is_root());
|
||||
} catch (const tools::system_error& e) {
|
||||
ATF_REQUIRE(!tools::user::is_root());
|
||||
ATF_REQUIRE_EQ(EACCES, e.code());
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(cleanup_eacces_on_subdir);
|
||||
ATF_TEST_CASE_HEAD(cleanup_eacces_on_subdir)
|
||||
{
|
||||
set_md_var("descr", "Tests the cleanup function");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(cleanup_eacces_on_subdir)
|
||||
{
|
||||
using tools::fs::cleanup;
|
||||
|
||||
::mkdir("root", 0755);
|
||||
::mkdir("root/1", 0755);
|
||||
::mkdir("root/1/2", 0755);
|
||||
::mkdir("root/1/2/3", 0755);
|
||||
ATF_REQUIRE(::chmod("root/1/2", 0555) != -1);
|
||||
ATF_REQUIRE(::chmod("root/1", 0555) != -1);
|
||||
|
||||
const tools::fs::path p("root");
|
||||
cleanup(p);
|
||||
ATF_REQUIRE(!tools::fs::exists(p));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(change_directory);
|
||||
ATF_TEST_CASE_HEAD(change_directory)
|
||||
{
|
||||
set_md_var("descr", "Tests the change_directory function");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(change_directory)
|
||||
{
|
||||
using tools::fs::change_directory;
|
||||
using tools::fs::get_current_dir;
|
||||
|
||||
::mkdir("files", 0755);
|
||||
::mkdir("files/dir", 0755);
|
||||
create_file("files/reg");
|
||||
|
||||
const tools::fs::path old = get_current_dir();
|
||||
|
||||
ATF_REQUIRE_THROW(tools::system_error,
|
||||
change_directory(tools::fs::path("files/reg")));
|
||||
ATF_REQUIRE(get_current_dir() == old);
|
||||
|
||||
tools::fs::path old2 = change_directory(tools::fs::path("files"));
|
||||
ATF_REQUIRE(old2 == old);
|
||||
tools::fs::path old3 = change_directory(tools::fs::path("dir"));
|
||||
ATF_REQUIRE(old3 == old2 / "files");
|
||||
tools::fs::path old4 = change_directory(tools::fs::path("../.."));
|
||||
ATF_REQUIRE(old4 == old3 / "dir");
|
||||
ATF_REQUIRE(get_current_dir() == old);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(get_current_dir);
|
||||
ATF_TEST_CASE_HEAD(get_current_dir)
|
||||
{
|
||||
set_md_var("descr", "Tests the get_current_dir function");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(get_current_dir)
|
||||
{
|
||||
using tools::fs::change_directory;
|
||||
using tools::fs::get_current_dir;
|
||||
|
||||
::mkdir("files", 0755);
|
||||
::mkdir("files/dir", 0755);
|
||||
create_file("files/reg");
|
||||
|
||||
tools::fs::path curdir = get_current_dir();
|
||||
change_directory(tools::fs::path("."));
|
||||
ATF_REQUIRE(get_current_dir() == curdir);
|
||||
change_directory(tools::fs::path("files"));
|
||||
ATF_REQUIRE(get_current_dir() == curdir / "files");
|
||||
change_directory(tools::fs::path("dir"));
|
||||
ATF_REQUIRE(get_current_dir() == curdir / "files/dir");
|
||||
change_directory(tools::fs::path(".."));
|
||||
ATF_REQUIRE(get_current_dir() == curdir / "files");
|
||||
change_directory(tools::fs::path(".."));
|
||||
ATF_REQUIRE(get_current_dir() == curdir);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 "temp_dir" class.
|
||||
ATF_ADD_TEST_CASE(tcs, temp_dir_raii);
|
||||
|
||||
// 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);
|
||||
ATF_ADD_TEST_CASE(tcs, cleanup);
|
||||
ATF_ADD_TEST_CASE(tcs, cleanup_eacces_on_root);
|
||||
ATF_ADD_TEST_CASE(tcs, cleanup_eacces_on_subdir);
|
||||
ATF_ADD_TEST_CASE(tcs, change_directory);
|
||||
ATF_ADD_TEST_CASE(tcs, get_current_dir);
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Generates a header file with information about the revision used to
|
||||
# build ATF.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
Prog_Name=${0##*/}
|
||||
|
||||
GIT=
|
||||
ROOT=
|
||||
|
||||
#
|
||||
# err message
|
||||
#
|
||||
err() {
|
||||
echo "${Prog_Name}: ${@}" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
#
|
||||
# call_git args
|
||||
#
|
||||
call_git() {
|
||||
( cd "${ROOT}" && "${GIT}" "${@}" )
|
||||
}
|
||||
|
||||
#
|
||||
# generate_from_dist revfile version
|
||||
#
|
||||
generate_from_dist() {
|
||||
revfile=${1}; shift
|
||||
version=${1}; shift
|
||||
|
||||
>${revfile}
|
||||
|
||||
echo "#define PACKAGE_REVISION_TYPE_DIST" >>${revfile}
|
||||
}
|
||||
|
||||
#
|
||||
# generate_from_git revfile
|
||||
#
|
||||
generate_from_git() {
|
||||
revfile=${1}
|
||||
|
||||
rev_base_id=$(call_git rev-parse HEAD)
|
||||
rev_branch=$(call_git branch | grep '^\* ' | cut -d ' ' -f 2-)
|
||||
rev_date=$(call_git log -1 | grep '^Date:' | sed -e 's,^Date:[ \t]*,,')
|
||||
if [ -z "$(call_git status -s)" ]; then
|
||||
rev_modified=false
|
||||
else
|
||||
rev_modified=true
|
||||
fi
|
||||
|
||||
>${revfile}
|
||||
|
||||
echo "#define PACKAGE_REVISION_TYPE_GIT" >>${revfile}
|
||||
|
||||
echo "#define PACKAGE_REVISION_BRANCH \"${rev_branch}\"" >>${revfile}
|
||||
echo "#define PACKAGE_REVISION_BASE \"${rev_base_id}\"" >>${revfile}
|
||||
|
||||
if [ ${rev_modified} = true ]; then
|
||||
echo "#define PACKAGE_REVISION_MODIFIED 1" >>${revfile}
|
||||
fi
|
||||
|
||||
echo "#define PACKAGE_REVISION_DATE \"${rev_date}\"" >>${revfile}
|
||||
}
|
||||
|
||||
#
|
||||
# main
|
||||
#
|
||||
# Entry point.
|
||||
#
|
||||
main() {
|
||||
outfile=
|
||||
version=
|
||||
while getopts :g:r:o:v: arg; do
|
||||
case ${arg} in
|
||||
g)
|
||||
GIT=${OPTARG}
|
||||
;;
|
||||
o)
|
||||
outfile=${OPTARG}
|
||||
;;
|
||||
r)
|
||||
ROOT=${OPTARG}
|
||||
;;
|
||||
v)
|
||||
version=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
err "Unknown option ${arg}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[ -n "${ROOT}" ] || \
|
||||
err "Must specify the top-level source directory with -r"
|
||||
[ -n "${outfile}" ] || \
|
||||
err "Must specify an output file with -o"
|
||||
[ -n "${version}" ] || \
|
||||
err "Must specify a version number with -v"
|
||||
|
||||
if [ -n "${GIT}" -a -d ${ROOT}/.git ]; then
|
||||
generate_from_git ${outfile}
|
||||
else
|
||||
generate_from_dist ${outfile} ${version}
|
||||
fi
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
|
||||
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4
|
356
tools/io.cpp
356
tools/io.cpp
@ -1,356 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#include "auto_array.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
namespace impl = tools::io;
|
||||
#define IMPL_NAME "tools::io"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "file_handle" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::file_handle::file_handle(void) :
|
||||
m_handle(invalid_value())
|
||||
{
|
||||
}
|
||||
|
||||
impl::file_handle::file_handle(handle_type h) :
|
||||
m_handle(h)
|
||||
{
|
||||
assert(m_handle != invalid_value());
|
||||
}
|
||||
|
||||
impl::file_handle::file_handle(const file_handle& fh) :
|
||||
m_handle(fh.m_handle)
|
||||
{
|
||||
fh.m_handle = invalid_value();
|
||||
}
|
||||
|
||||
impl::file_handle::~file_handle(void)
|
||||
{
|
||||
if (is_valid())
|
||||
close();
|
||||
}
|
||||
|
||||
impl::file_handle&
|
||||
impl::file_handle::operator=(const file_handle& fh)
|
||||
{
|
||||
m_handle = fh.m_handle;
|
||||
fh.m_handle = invalid_value();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
impl::file_handle::is_valid(void)
|
||||
const
|
||||
{
|
||||
return m_handle != invalid_value();
|
||||
}
|
||||
|
||||
void
|
||||
impl::file_handle::close(void)
|
||||
{
|
||||
assert(is_valid());
|
||||
|
||||
::close(m_handle);
|
||||
|
||||
m_handle = invalid_value();
|
||||
}
|
||||
|
||||
impl::file_handle::handle_type
|
||||
impl::file_handle::disown(void)
|
||||
{
|
||||
assert(is_valid());
|
||||
|
||||
handle_type h = m_handle;
|
||||
m_handle = invalid_value();
|
||||
return h;
|
||||
}
|
||||
|
||||
impl::file_handle::handle_type
|
||||
impl::file_handle::get(void)
|
||||
const
|
||||
{
|
||||
assert(is_valid());
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
void
|
||||
impl::file_handle::posix_remap(handle_type h)
|
||||
{
|
||||
assert(is_valid());
|
||||
|
||||
if (m_handle == h)
|
||||
return;
|
||||
|
||||
if (::dup2(m_handle, h) == -1)
|
||||
throw tools::system_error(IMPL_NAME "::file_handle::posix_remap",
|
||||
"dup2(2) failed", errno);
|
||||
|
||||
if (::close(m_handle) == -1) {
|
||||
::close(h);
|
||||
throw tools::system_error(IMPL_NAME "::file_handle::posix_remap",
|
||||
"close(2) failed", errno);
|
||||
}
|
||||
|
||||
m_handle = h;
|
||||
}
|
||||
|
||||
impl::file_handle::handle_type
|
||||
impl::file_handle::invalid_value(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "systembuf" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::systembuf::systembuf(handle_type h, std::size_t bufsize) :
|
||||
m_handle(h),
|
||||
m_bufsize(bufsize),
|
||||
m_read_buf(NULL),
|
||||
m_write_buf(NULL)
|
||||
{
|
||||
assert(m_handle >= 0);
|
||||
assert(m_bufsize > 0);
|
||||
|
||||
try {
|
||||
m_read_buf = new char[bufsize];
|
||||
m_write_buf = new char[bufsize];
|
||||
} catch (...) {
|
||||
if (m_read_buf != NULL)
|
||||
delete [] m_read_buf;
|
||||
if (m_write_buf != NULL)
|
||||
delete [] m_write_buf;
|
||||
throw;
|
||||
}
|
||||
|
||||
setp(m_write_buf, m_write_buf + m_bufsize);
|
||||
}
|
||||
|
||||
impl::systembuf::~systembuf(void)
|
||||
{
|
||||
delete [] m_read_buf;
|
||||
delete [] m_write_buf;
|
||||
}
|
||||
|
||||
impl::systembuf::int_type
|
||||
impl::systembuf::underflow(void)
|
||||
{
|
||||
assert(gptr() >= egptr());
|
||||
|
||||
bool ok;
|
||||
ssize_t cnt = ::read(m_handle, m_read_buf, m_bufsize);
|
||||
ok = (cnt != -1 && cnt != 0);
|
||||
|
||||
if (!ok)
|
||||
return traits_type::eof();
|
||||
else {
|
||||
setg(m_read_buf, m_read_buf, m_read_buf + cnt);
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
}
|
||||
|
||||
impl::systembuf::int_type
|
||||
impl::systembuf::overflow(int c)
|
||||
{
|
||||
assert(pptr() >= epptr());
|
||||
if (sync() == -1)
|
||||
return traits_type::eof();
|
||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
traits_type::assign(*pptr(), c);
|
||||
pbump(1);
|
||||
}
|
||||
return traits_type::not_eof(c);
|
||||
}
|
||||
|
||||
int
|
||||
impl::systembuf::sync(void)
|
||||
{
|
||||
ssize_t cnt = pptr() - pbase();
|
||||
|
||||
bool ok;
|
||||
ok = ::write(m_handle, pbase(), cnt) == cnt;
|
||||
|
||||
if (ok)
|
||||
pbump(-cnt);
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "pistream" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::pistream::pistream(const int fd) :
|
||||
std::istream(NULL),
|
||||
m_systembuf(fd)
|
||||
{
|
||||
rdbuf(&m_systembuf);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "muxer" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static int
|
||||
safe_poll(struct pollfd fds[], nfds_t nfds, int timeout)
|
||||
{
|
||||
int ret = ::poll(fds, nfds, timeout);
|
||||
if (ret == -1) {
|
||||
if (errno == EINTR)
|
||||
ret = 0;
|
||||
else
|
||||
throw tools::system_error(IMPL_NAME "::safe_poll", "poll(2) failed",
|
||||
errno);
|
||||
}
|
||||
assert(ret >= 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t
|
||||
safe_read(const int fd, void* buffer, const size_t nbytes,
|
||||
const bool report_errors)
|
||||
{
|
||||
int ret;
|
||||
while ((ret = ::read(fd, buffer, nbytes)) == -1 && errno == EINTR) {}
|
||||
if (ret == -1) {
|
||||
assert(errno != EINTR);
|
||||
|
||||
if (report_errors)
|
||||
throw tools::system_error(IMPL_NAME "::safe_read", "read(2) failed",
|
||||
errno);
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
assert(ret >= 0);
|
||||
return static_cast< size_t >(ret);
|
||||
}
|
||||
|
||||
impl::muxer::muxer(const int* fds, const size_t nfds, const size_t bufsize) :
|
||||
m_fds(fds),
|
||||
m_nfds(nfds),
|
||||
m_bufsize(bufsize),
|
||||
m_buffers(new std::string[nfds])
|
||||
{
|
||||
}
|
||||
|
||||
impl::muxer::~muxer(void)
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
impl::muxer::read_one(const size_t index, const int fd, std::string& accum,
|
||||
const bool report_errors)
|
||||
{
|
||||
tools::auto_array< char > buffer(new char[m_bufsize]);
|
||||
const size_t nbytes = safe_read(fd, buffer.get(), m_bufsize - 1,
|
||||
report_errors);
|
||||
assert(nbytes < m_bufsize);
|
||||
buffer[nbytes] = '\0';
|
||||
|
||||
std::string line(accum);
|
||||
|
||||
size_t line_start = 0;
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
line_callback(index, line);
|
||||
line.clear();
|
||||
accum.clear();
|
||||
line_start = i + 1;
|
||||
} else if (buffer[i] == '\r') {
|
||||
// Do nothing.
|
||||
} else {
|
||||
line.append(1, buffer[i]);
|
||||
}
|
||||
}
|
||||
accum.append(&buffer[line_start]);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
void
|
||||
impl::muxer::mux(volatile const bool& terminate)
|
||||
{
|
||||
tools::auto_array< struct pollfd > poll_fds(new struct pollfd[m_nfds]);
|
||||
for (size_t i = 0; i < m_nfds; i++) {
|
||||
poll_fds[i].fd = m_fds[i];
|
||||
poll_fds[i].events = POLLIN;
|
||||
}
|
||||
|
||||
size_t nactive = m_nfds;
|
||||
while (nactive > 0 && !terminate) {
|
||||
int ret;
|
||||
while (!terminate && (ret = safe_poll(poll_fds.get(), 2, 250)) == 0) {}
|
||||
|
||||
for (size_t i = 0; !terminate && i < m_nfds; i++) {
|
||||
if (poll_fds[i].events == 0)
|
||||
continue;
|
||||
|
||||
if (poll_fds[i].revents & POLLHUP) {
|
||||
// Any data still available at this point will be processed by
|
||||
// a call to the flush method.
|
||||
poll_fds[i].events = 0;
|
||||
|
||||
assert(nactive >= 1);
|
||||
nactive--;
|
||||
} else if (poll_fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND |
|
||||
POLLPRI)) {
|
||||
(void)read_one(i, poll_fds[i].fd, m_buffers[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
impl::muxer::flush(void)
|
||||
{
|
||||
for (size_t i = 0; i < m_nfds; i++) {
|
||||
while (read_one(i, m_fds[i], m_buffers[i], false) > 0) {}
|
||||
|
||||
if (!m_buffers[i].empty())
|
||||
line_callback(i, m_buffers[i]);
|
||||
}
|
||||
}
|
436
tools/io.hpp
436
tools/io.hpp
@ -1,436 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_IO_HPP)
|
||||
#define TOOLS_IO_HPP
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
#include "auto_array.hpp"
|
||||
#include "fs.hpp"
|
||||
|
||||
namespace tools {
|
||||
namespace io {
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "file_handle" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief Simple RAII model for system file handles.
|
||||
//!
|
||||
//! The \a file_handle class is a simple RAII model for native system file
|
||||
//! handles. This class wraps one of such handles grabbing its ownership,
|
||||
//! and automaticaly closes it upon destruction. It is basically used
|
||||
//! inside the library to avoid leaking open file handles, shall an
|
||||
//! unexpected execution trace occur.
|
||||
//!
|
||||
//! A \a file_handle object can be copied but doing so invalidates the
|
||||
//! source object. There can only be a single valid \a file_handle object
|
||||
//! for a given system file handle. This is similar to std::auto_ptr\<\>'s
|
||||
//! semantics.
|
||||
//!
|
||||
//! This class also provides some convenience methods to issue special file
|
||||
//! operations under their respective platforms.
|
||||
//!
|
||||
class file_handle
|
||||
{
|
||||
public:
|
||||
//!
|
||||
//! \brief Opaque name for the native handle type.
|
||||
//!
|
||||
//! Each operating system identifies file handles using a specific type.
|
||||
//! The \a handle_type type is used to transparently refer to file
|
||||
//! handles regarless of the operating system in which this class is
|
||||
//! used.
|
||||
//!
|
||||
//! If this class is used in a POSIX system, \a NativeSystemHandle is
|
||||
//! an integer type while it is a \a HANDLE in a Win32 system.
|
||||
//!
|
||||
typedef int handle_type;
|
||||
|
||||
//!
|
||||
//! \brief Constructs an invalid file handle.
|
||||
//!
|
||||
//! This constructor creates a new \a file_handle object that represents
|
||||
//! an invalid file handle. An invalid file handle can be copied but
|
||||
//! cannot be manipulated in any way (except checking for its validity).
|
||||
//!
|
||||
//! \see is_valid()
|
||||
//!
|
||||
file_handle(void);
|
||||
|
||||
//!
|
||||
//! \brief Constructs a new file handle from a native file handle.
|
||||
//!
|
||||
//! This constructor creates a new \a file_handle object that takes
|
||||
//! ownership of the given \a h native file handle. The user must not
|
||||
//! close \a h on his own during the lifetime of the new object.
|
||||
//! Ownership can be reclaimed using disown().
|
||||
//!
|
||||
//! \pre The native file handle must be valid; a close operation must
|
||||
//! succeed on it.
|
||||
//!
|
||||
//! \see disown()
|
||||
//!
|
||||
file_handle(handle_type h);
|
||||
|
||||
//!
|
||||
//! \brief Copy constructor; invalidates the source handle.
|
||||
//!
|
||||
//! This copy constructor creates a new file handle from a given one.
|
||||
//! Ownership of the native file handle is transferred to the new
|
||||
//! object, effectively invalidating the source file handle. This
|
||||
//! avoids having two live \a file_handle objects referring to the
|
||||
//! same native file handle. The source file handle need not be
|
||||
//! valid in the name of simplicity.
|
||||
//!
|
||||
//! \post The source file handle is invalid.
|
||||
//! \post The new file handle owns the source's native file handle.
|
||||
//!
|
||||
file_handle(const file_handle& fh);
|
||||
|
||||
//!
|
||||
//! \brief Releases resources if the handle is valid.
|
||||
//!
|
||||
//! If the file handle is valid, the destructor closes it.
|
||||
//!
|
||||
//! \see is_valid()
|
||||
//!
|
||||
~file_handle(void);
|
||||
|
||||
//!
|
||||
//! \brief Assignment operator; invalidates the source handle.
|
||||
//!
|
||||
//! This assignment operator transfers ownership of the RHS file
|
||||
//! handle to the LHS one, effectively invalidating the source file
|
||||
//! handle. This avoids having two live \a file_handle objects
|
||||
//! referring to the same native file handle. The source file
|
||||
//! handle need not be valid in the name of simplicity.
|
||||
//!
|
||||
//! \post The RHS file handle is invalid.
|
||||
//! \post The LHS file handle owns RHS' native file handle.
|
||||
//! \return A reference to the LHS file handle.
|
||||
//!
|
||||
file_handle& operator=(const file_handle& fh);
|
||||
|
||||
//!
|
||||
//! \brief Checks whether the file handle is valid or not.
|
||||
//!
|
||||
//! Returns a boolean indicating whether the file handle is valid or
|
||||
//! not. If the file handle is invalid, no other applications can be
|
||||
//! executed other than the destructor.
|
||||
//!
|
||||
//! \return True if the file handle is valid; false otherwise.
|
||||
//!
|
||||
bool is_valid(void) const;
|
||||
|
||||
//!
|
||||
//! \brief Closes the file handle.
|
||||
//!
|
||||
//! Explicitly closes the file handle, which must be valid. Upon
|
||||
//! exit, the handle is not valid any more.
|
||||
//!
|
||||
//! \pre The file handle is valid.
|
||||
//! \post The file handle is invalid.
|
||||
//! \post The native file handle is closed.
|
||||
//!
|
||||
void close(void);
|
||||
|
||||
//!
|
||||
//! \brief Reclaims ownership of the native file handle.
|
||||
//!
|
||||
//! Explicitly reclaims ownership of the native file handle contained
|
||||
//! in the \a file_handle object, returning the native file handle.
|
||||
//! The caller is responsible of closing it later on.
|
||||
//!
|
||||
//! \pre The file handle is valid.
|
||||
//! \post The file handle is invalid.
|
||||
//! \return The native file handle.
|
||||
//!
|
||||
handle_type disown(void);
|
||||
|
||||
//!
|
||||
//! \brief Gets the native file handle.
|
||||
//!
|
||||
//! Returns the native file handle for the \a file_handle object.
|
||||
//! The caller can issue any operation on it except closing it.
|
||||
//! If closing is required, disown() shall be used.
|
||||
//!
|
||||
//! \pre The file handle is valid.
|
||||
//! \return The native file handle.
|
||||
//!
|
||||
handle_type get(void) const;
|
||||
|
||||
//!
|
||||
//! \brief Changes the native file handle to the given one.
|
||||
//!
|
||||
//! Given a new native file handle \a h, this operation assigns this
|
||||
//! handle to the current object, closing its old native file handle.
|
||||
//! In other words, it first calls dup2() to remap the old handle to
|
||||
//! the new one and then closes the old handle.
|
||||
//!
|
||||
//! If \a h matches the current value of the handle, this is a no-op.
|
||||
//! This is done for simplicity, to avoid the caller having to check
|
||||
//! this condition on its own.
|
||||
//!
|
||||
//! If \a h is open, it is automatically closed by dup2().
|
||||
//!
|
||||
//! This operation is only available in POSIX systems.
|
||||
//!
|
||||
//! \pre The file handle is valid.
|
||||
//! \pre The native file handle \a h is valid; i.e., it must be
|
||||
//! closeable.
|
||||
//! \post The file handle's native file handle is \a h.
|
||||
//! \throw system_error If the internal remapping operation fails.
|
||||
//!
|
||||
void posix_remap(handle_type h);
|
||||
|
||||
private:
|
||||
//!
|
||||
//! \brief Internal handle value.
|
||||
//!
|
||||
//! This variable holds the native handle value for the file handle
|
||||
//! hold by this object. It is interesting to note that this needs
|
||||
//! to be mutable because the copy constructor and the assignment
|
||||
//! operator invalidate the source object.
|
||||
//!
|
||||
mutable handle_type m_handle;
|
||||
|
||||
//!
|
||||
//! \brief Constant function representing an invalid handle value.
|
||||
//!
|
||||
//! Returns the platform-specific handle value that represents an
|
||||
//! invalid handle. This is a constant function rather than a regular
|
||||
//! constant because, in the latter case, we cannot define it under
|
||||
//! Win32 due to the value being of a complex type.
|
||||
//!
|
||||
static handle_type invalid_value(void);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "systembuf" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief std::streambuf implementation for system file handles.
|
||||
//!
|
||||
//! systembuf provides a std::streambuf implementation for system file
|
||||
//! handles. Contrarywise to file_handle, this class does \b not take
|
||||
//! ownership of the native file handle; this should be taken care of
|
||||
//! somewhere else.
|
||||
//!
|
||||
//! This class follows the expected semantics of a std::streambuf object.
|
||||
//! However, it is not copyable to avoid introducing inconsistences with
|
||||
//! the on-disk file and the in-memory buffers.
|
||||
//!
|
||||
class systembuf : public std::streambuf
|
||||
{
|
||||
// Non-copyable.
|
||||
systembuf(const systembuf&);
|
||||
systembuf& operator=(const systembuf&);
|
||||
|
||||
public:
|
||||
typedef int handle_type;
|
||||
|
||||
//!
|
||||
//! \brief Constructs a new systembuf for the given file handle.
|
||||
//!
|
||||
//! This constructor creates a new systembuf object that reads or
|
||||
//! writes data from/to the \a h native file handle. This handle
|
||||
//! is \b not owned by the created systembuf object; the code
|
||||
//! should take care of it externally.
|
||||
//!
|
||||
//! This class buffers input and output; the buffer size may be
|
||||
//! tuned through the \a bufsize parameter, which defaults to 8192
|
||||
//! bytes.
|
||||
//!
|
||||
//! \see pistream.
|
||||
//!
|
||||
explicit systembuf(handle_type h, std::size_t bufsize = 8192);
|
||||
~systembuf(void);
|
||||
|
||||
private:
|
||||
//!
|
||||
//! \brief Native file handle used by the systembuf object.
|
||||
//!
|
||||
handle_type m_handle;
|
||||
|
||||
//!
|
||||
//! \brief Internal buffer size used during read and write operations.
|
||||
//!
|
||||
std::size_t m_bufsize;
|
||||
|
||||
//!
|
||||
//! \brief Internal buffer used during read operations.
|
||||
//!
|
||||
char* m_read_buf;
|
||||
|
||||
//!
|
||||
//! \brief Internal buffer used during write operations.
|
||||
//!
|
||||
char* m_write_buf;
|
||||
|
||||
protected:
|
||||
//!
|
||||
//! \brief Reads new data from the native file handle.
|
||||
//!
|
||||
//! This operation is called by input methods when there are no more
|
||||
//! data in the input buffer. The function fills the buffer with new
|
||||
//! data, if available.
|
||||
//!
|
||||
//! \pre All input positions are exhausted (gptr() >= egptr()).
|
||||
//! \post The input buffer has new data, if available.
|
||||
//! \returns traits_type::eof() if a read error occurrs or there are
|
||||
//! no more data to be read. Otherwise returns
|
||||
//! traits_type::to_int_type(*gptr()).
|
||||
//!
|
||||
virtual int_type underflow(void);
|
||||
|
||||
//!
|
||||
//! \brief Makes room in the write buffer for additional data.
|
||||
//!
|
||||
//! This operation is called by output methods when there is no more
|
||||
//! space in the output buffer to hold a new element. The function
|
||||
//! first flushes the buffer's contents to disk and then clears it to
|
||||
//! leave room for more characters. The given \a c character is
|
||||
//! stored at the beginning of the new space.
|
||||
//!
|
||||
//! \pre All output positions are exhausted (pptr() >= epptr()).
|
||||
//! \post The output buffer has more space if no errors occurred
|
||||
//! during the write to disk.
|
||||
//! \post *(pptr() - 1) is \a c.
|
||||
//! \returns traits_type::eof() if a write error occurrs. Otherwise
|
||||
//! returns traits_type::not_eof(c).
|
||||
//!
|
||||
virtual int_type overflow(int c);
|
||||
|
||||
//!
|
||||
//! \brief Flushes the output buffer to disk.
|
||||
//!
|
||||
//! Synchronizes the systembuf buffers with the contents of the file
|
||||
//! associated to this object through the native file handle. The
|
||||
//! output buffer is flushed to disk and cleared to leave new room
|
||||
//! for more data.
|
||||
//!
|
||||
//! \returns 0 on success, -1 if an error occurred.
|
||||
//!
|
||||
virtual int sync(void);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "pistream" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
//!
|
||||
//! \brief Child process' output stream.
|
||||
//!
|
||||
//! The pistream class represents an output communication channel with the
|
||||
//! child process. The child process writes data to this stream and the
|
||||
//! parent process can read it through the pistream object. In other
|
||||
//! words, from the child's point of view, the communication channel is an
|
||||
//! output one, but from the parent's point of view it is an input one;
|
||||
//! hence the confusing pistream name.
|
||||
//!
|
||||
//! pistream objects cannot be copied because they own the file handle
|
||||
//! they use to communicate with the child and because they buffer data
|
||||
//! that flows through the communication channel.
|
||||
//!
|
||||
//! A pistream object behaves as a std::istream stream in all senses.
|
||||
//! The class is only provided because it must provide a method to let
|
||||
//! the caller explicitly close the communication channel.
|
||||
//!
|
||||
//! \remark <b>Blocking remarks</b>: Functions that read data from this
|
||||
//! stream can block if the associated file handle blocks during the read.
|
||||
//! As this class is used to communicate with child processes through
|
||||
//! anonymous pipes, the most typical blocking condition happens when the
|
||||
//! child has no more data to send to the pipe's system buffer. When
|
||||
//! this happens, the buffer eventually empties and the system blocks
|
||||
//! until the writer generates some data.
|
||||
//!
|
||||
class pistream : public std::istream
|
||||
{
|
||||
// Non-copyable.
|
||||
pistream(const pistream&);
|
||||
pistream& operator=(const pistream&);
|
||||
|
||||
//!
|
||||
//! \brief The systembuf object used to manage this stream's data.
|
||||
//!
|
||||
systembuf m_systembuf;
|
||||
|
||||
public:
|
||||
//!
|
||||
//! \brief Creates a new process' output stream.
|
||||
//!
|
||||
//! Given a file handle, this constructor creates a new pistream
|
||||
//! object that owns the given file handle \a fh. Ownership of
|
||||
//! \a fh is transferred to the created pistream object.
|
||||
//!
|
||||
//! \pre \a fh is valid.
|
||||
//! \post \a fh is invalid.
|
||||
//! \post The new pistream object owns \a fh.
|
||||
//!
|
||||
explicit pistream(const int);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "muxer" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class muxer {
|
||||
// Non-copyable.
|
||||
muxer(const muxer&);
|
||||
muxer& operator=(const muxer&);
|
||||
|
||||
const int* m_fds;
|
||||
const size_t m_nfds;
|
||||
|
||||
const size_t m_bufsize;
|
||||
tools::auto_array< std::string > m_buffers;
|
||||
|
||||
protected:
|
||||
virtual void line_callback(const size_t, const std::string&) = 0;
|
||||
|
||||
size_t read_one(const size_t, const int, std::string&, const bool);
|
||||
|
||||
public:
|
||||
muxer(const int*, const size_t, const size_t bufsize = 1024);
|
||||
virtual ~muxer(void);
|
||||
|
||||
void mux(volatile const bool&);
|
||||
void flush(void);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_IO_HPP)
|
@ -1,471 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "io.hpp"
|
||||
#include "signals.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static
|
||||
void
|
||||
systembuf_check_data(std::istream& is, std::size_t length)
|
||||
{
|
||||
char ch = 'A', chr;
|
||||
std::size_t cnt = 0;
|
||||
while (is >> chr) {
|
||||
ATF_REQUIRE_EQ(ch, chr);
|
||||
if (ch == 'Z')
|
||||
ch = 'A';
|
||||
else
|
||||
ch++;
|
||||
cnt++;
|
||||
}
|
||||
ATF_REQUIRE_EQ(cnt, length);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
systembuf_write_data(std::ostream& os, std::size_t length)
|
||||
{
|
||||
char ch = 'A';
|
||||
for (std::size_t i = 0; i < length; i++) {
|
||||
os << ch;
|
||||
if (ch == 'Z')
|
||||
ch = 'A';
|
||||
else
|
||||
ch++;
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
systembuf_test_read(std::size_t length, std::size_t bufsize)
|
||||
{
|
||||
using tools::io::systembuf;
|
||||
|
||||
std::ofstream f("test_read.txt");
|
||||
systembuf_write_data(f, length);
|
||||
f.close();
|
||||
|
||||
int fd = ::open("test_read.txt", O_RDONLY);
|
||||
ATF_REQUIRE(fd != -1);
|
||||
systembuf sb(fd, bufsize);
|
||||
std::istream is(&sb);
|
||||
systembuf_check_data(is, length);
|
||||
::close(fd);
|
||||
::unlink("test_read.txt");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
systembuf_test_write(std::size_t length, std::size_t bufsize)
|
||||
{
|
||||
using tools::io::systembuf;
|
||||
|
||||
int fd = ::open("test_write.txt", O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
ATF_REQUIRE(fd != -1);
|
||||
systembuf sb(fd, bufsize);
|
||||
std::ostream os(&sb);
|
||||
systembuf_write_data(os, length);
|
||||
::close(fd);
|
||||
|
||||
std::ifstream is("test_write.txt");
|
||||
systembuf_check_data(is, length);
|
||||
is.close();
|
||||
::unlink("test_write.txt");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Test cases for the "file_handle" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(file_handle_ctor);
|
||||
ATF_TEST_CASE_HEAD(file_handle_ctor)
|
||||
{
|
||||
set_md_var("descr", "Tests file_handle's constructors");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(file_handle_ctor)
|
||||
{
|
||||
using tools::io::file_handle;
|
||||
|
||||
file_handle fh1;
|
||||
ATF_REQUIRE(!fh1.is_valid());
|
||||
|
||||
file_handle fh2(STDOUT_FILENO);
|
||||
ATF_REQUIRE(fh2.is_valid());
|
||||
fh2.disown();
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(file_handle_copy);
|
||||
ATF_TEST_CASE_HEAD(file_handle_copy)
|
||||
{
|
||||
set_md_var("descr", "Tests file_handle's copy constructor");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(file_handle_copy)
|
||||
{
|
||||
using tools::io::file_handle;
|
||||
|
||||
file_handle fh1;
|
||||
file_handle fh2(STDOUT_FILENO);
|
||||
|
||||
file_handle fh3(fh2);
|
||||
ATF_REQUIRE(!fh2.is_valid());
|
||||
ATF_REQUIRE(fh3.is_valid());
|
||||
|
||||
fh1 = fh3;
|
||||
ATF_REQUIRE(!fh3.is_valid());
|
||||
ATF_REQUIRE(fh1.is_valid());
|
||||
|
||||
fh1.disown();
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(file_handle_get);
|
||||
ATF_TEST_CASE_HEAD(file_handle_get)
|
||||
{
|
||||
set_md_var("descr", "Tests the file_handle::get method");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(file_handle_get)
|
||||
{
|
||||
using tools::io::file_handle;
|
||||
|
||||
file_handle fh1(STDOUT_FILENO);
|
||||
ATF_REQUIRE_EQ(fh1.get(), STDOUT_FILENO);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(file_handle_posix_remap);
|
||||
ATF_TEST_CASE_HEAD(file_handle_posix_remap)
|
||||
{
|
||||
set_md_var("descr", "Tests the file_handle::posix_remap method");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(file_handle_posix_remap)
|
||||
{
|
||||
using tools::io::file_handle;
|
||||
|
||||
int pfd[2];
|
||||
|
||||
ATF_REQUIRE(::pipe(pfd) != -1);
|
||||
file_handle rend(pfd[0]);
|
||||
file_handle wend(pfd[1]);
|
||||
|
||||
ATF_REQUIRE(rend.get() != 10);
|
||||
ATF_REQUIRE(wend.get() != 10);
|
||||
wend.posix_remap(10);
|
||||
ATF_REQUIRE_EQ(wend.get(), 10);
|
||||
ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
|
||||
{
|
||||
char buf[17];
|
||||
ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
|
||||
buf[16] = '\0';
|
||||
ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
|
||||
}
|
||||
|
||||
// Redo previous to ensure that remapping over the same descriptor
|
||||
// has no side-effects.
|
||||
ATF_REQUIRE_EQ(wend.get(), 10);
|
||||
wend.posix_remap(10);
|
||||
ATF_REQUIRE_EQ(wend.get(), 10);
|
||||
ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
|
||||
{
|
||||
char buf[17];
|
||||
ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
|
||||
buf[16] = '\0';
|
||||
ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Test cases for the "systembuf" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(systembuf_short_read);
|
||||
ATF_TEST_CASE_HEAD(systembuf_short_read)
|
||||
{
|
||||
set_md_var("descr", "Tests that a short read (one that fits in the "
|
||||
"internal buffer) works when using systembuf");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(systembuf_short_read)
|
||||
{
|
||||
systembuf_test_read(64, 1024);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(systembuf_long_read);
|
||||
ATF_TEST_CASE_HEAD(systembuf_long_read)
|
||||
{
|
||||
set_md_var("descr", "Tests that a long read (one that does not fit in "
|
||||
"the internal buffer) works when using systembuf");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(systembuf_long_read)
|
||||
{
|
||||
systembuf_test_read(64 * 1024, 1024);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(systembuf_short_write);
|
||||
ATF_TEST_CASE_HEAD(systembuf_short_write)
|
||||
{
|
||||
set_md_var("descr", "Tests that a short write (one that fits in the "
|
||||
"internal buffer) works when using systembuf");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(systembuf_short_write)
|
||||
{
|
||||
systembuf_test_write(64, 1024);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(systembuf_long_write);
|
||||
ATF_TEST_CASE_HEAD(systembuf_long_write)
|
||||
{
|
||||
set_md_var("descr", "Tests that a long write (one that does not fit "
|
||||
"in the internal buffer) works when using systembuf");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(systembuf_long_write)
|
||||
{
|
||||
systembuf_test_write(64 * 1024, 1024);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Test cases for the "pistream" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(pistream);
|
||||
ATF_TEST_CASE_HEAD(pistream)
|
||||
{
|
||||
set_md_var("descr", "Tests the pistream class");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(pistream)
|
||||
{
|
||||
using tools::io::file_handle;
|
||||
using tools::io::pistream;
|
||||
using tools::io::systembuf;
|
||||
|
||||
int fds[2];
|
||||
ATF_REQUIRE(::pipe(fds) != -1);
|
||||
|
||||
pistream rend(fds[0]);
|
||||
|
||||
systembuf wbuf(fds[1]);
|
||||
std::ostream wend(&wbuf);
|
||||
|
||||
// XXX This assumes that the pipe's buffer is big enough to accept
|
||||
// the data written without blocking!
|
||||
wend << "1Test 1message\n";
|
||||
wend.flush();
|
||||
std::string tmp;
|
||||
rend >> tmp;
|
||||
ATF_REQUIRE_EQ(tmp, "1Test");
|
||||
rend >> tmp;
|
||||
ATF_REQUIRE_EQ(tmp, "1message");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tests for the "muxer" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
static void
|
||||
check_stream(std::ostream& os)
|
||||
{
|
||||
// If we receive a signal while writing to the stream, the bad bit gets set.
|
||||
// Things seem to behave fine afterwards if we clear such error condition.
|
||||
// However, I'm not sure if it's safe to query errno at this point.
|
||||
ATF_REQUIRE(os.good() || (os.bad() && errno == EINTR));
|
||||
os.clear();
|
||||
}
|
||||
|
||||
class mock_muxer : public tools::io::muxer {
|
||||
void line_callback(const size_t index, const std::string& line)
|
||||
{
|
||||
// The following should be enabled but causes the output to be so big
|
||||
// that it is annoying. Reenable at some point if we make atf store
|
||||
// the output of the test cases in some other way (e.g. only if a test
|
||||
// failes), because this message is the only help in seeing how the
|
||||
// test fails.
|
||||
//std::cout << "line_callback(" << index << ", " << line << ")\n";
|
||||
check_stream(std::cout);
|
||||
switch (index) {
|
||||
case 0: lines0.push_back(line); break;
|
||||
case 1: lines1.push_back(line); break;
|
||||
default: ATF_REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
mock_muxer(const int* fds, const size_t nfds, const size_t bufsize) :
|
||||
muxer(fds, nfds, bufsize) {}
|
||||
|
||||
std::vector< std::string > lines0;
|
||||
std::vector< std::string > lines1;
|
||||
};
|
||||
|
||||
static bool child_finished = false;
|
||||
static void sigchld_handler(int signo)
|
||||
{
|
||||
assert(signo == SIGCHLD);
|
||||
child_finished = true;
|
||||
}
|
||||
|
||||
static void
|
||||
child_printer(const int pipeout[2], const int pipeerr[2],
|
||||
const size_t iterations)
|
||||
{
|
||||
::close(pipeout[0]);
|
||||
::close(pipeerr[0]);
|
||||
ATF_REQUIRE(::dup2(pipeout[1], STDOUT_FILENO) != -1);
|
||||
ATF_REQUIRE(::dup2(pipeerr[1], STDERR_FILENO) != -1);
|
||||
::close(pipeout[1]);
|
||||
::close(pipeerr[1]);
|
||||
|
||||
for (size_t i = 0; i < iterations; i++) {
|
||||
std::cout << "stdout " << i << "\n";
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
}
|
||||
|
||||
std::cout << "stdout eof\n";
|
||||
std::cerr << "stderr eof\n";
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
muxer_test(const size_t bufsize, const size_t iterations)
|
||||
{
|
||||
int pipeout[2], pipeerr[2];
|
||||
ATF_REQUIRE(pipe(pipeout) != -1);
|
||||
ATF_REQUIRE(pipe(pipeerr) != -1);
|
||||
|
||||
tools::signals::signal_programmer sigchld(SIGCHLD, sigchld_handler);
|
||||
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
|
||||
pid_t pid = ::fork();
|
||||
ATF_REQUIRE(pid != -1);
|
||||
if (pid == 0) {
|
||||
sigchld.unprogram();
|
||||
child_printer(pipeout, pipeerr, iterations);
|
||||
std::abort();
|
||||
}
|
||||
::close(pipeout[1]);
|
||||
::close(pipeerr[1]);
|
||||
|
||||
int fds[2] = {pipeout[0], pipeerr[0]};
|
||||
mock_muxer mux(fds, 2, bufsize);
|
||||
|
||||
mux.mux(child_finished);
|
||||
check_stream(std::cout);
|
||||
std::cout << "mux done\n";
|
||||
|
||||
mux.flush();
|
||||
std::cout << "flush done\n";
|
||||
check_stream(std::cout);
|
||||
|
||||
sigchld.unprogram();
|
||||
int status;
|
||||
ATF_REQUIRE(::waitpid(pid, &status, 0) != -1);
|
||||
ATF_REQUIRE(WIFEXITED(status));
|
||||
ATF_REQUIRE(WEXITSTATUS(status) == EXIT_SUCCESS);
|
||||
|
||||
ATF_REQUIRE(std::cout.good());
|
||||
ATF_REQUIRE(std::cerr.good());
|
||||
for (size_t i = 0; i < iterations; i++) {
|
||||
std::ostringstream exp0, exp1;
|
||||
exp0 << "stdout " << i;
|
||||
exp1 << "stderr " << i;
|
||||
|
||||
ATF_REQUIRE(mux.lines0.size() > i);
|
||||
ATF_REQUIRE_EQ(exp0.str(), mux.lines0[i]);
|
||||
ATF_REQUIRE(mux.lines1.size() > i);
|
||||
ATF_REQUIRE_EQ(exp1.str(), mux.lines1[i]);
|
||||
}
|
||||
ATF_REQUIRE_EQ("stdout eof", mux.lines0[iterations]);
|
||||
ATF_REQUIRE_EQ("stderr eof", mux.lines1[iterations]);
|
||||
std::cout << "all done\n";
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(muxer_small_buffer);
|
||||
ATF_TEST_CASE_BODY(muxer_small_buffer)
|
||||
{
|
||||
muxer_test(4, 20000);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(muxer_large_buffer);
|
||||
ATF_TEST_CASE_BODY(muxer_large_buffer)
|
||||
{
|
||||
muxer_test(1024, 50000);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Main.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
// Add the tests for the "file_handle" class.
|
||||
ATF_ADD_TEST_CASE(tcs, file_handle_ctor);
|
||||
ATF_ADD_TEST_CASE(tcs, file_handle_copy);
|
||||
ATF_ADD_TEST_CASE(tcs, file_handle_get);
|
||||
ATF_ADD_TEST_CASE(tcs, file_handle_posix_remap);
|
||||
|
||||
// Add the tests for the "systembuf" class.
|
||||
ATF_ADD_TEST_CASE(tcs, systembuf_short_read);
|
||||
ATF_ADD_TEST_CASE(tcs, systembuf_long_read);
|
||||
ATF_ADD_TEST_CASE(tcs, systembuf_short_write);
|
||||
ATF_ADD_TEST_CASE(tcs, systembuf_long_write);
|
||||
|
||||
// Add the tests for the "pistream" class.
|
||||
ATF_ADD_TEST_CASE(tcs, pistream);
|
||||
|
||||
// Add the tests for the "muxer" class.
|
||||
ATF_ADD_TEST_CASE(tcs, muxer_small_buffer);
|
||||
ATF_ADD_TEST_CASE(tcs, muxer_large_buffer);
|
||||
}
|
@ -1,448 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "env.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "process.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static
|
||||
void
|
||||
touch(const std::string& path)
|
||||
{
|
||||
std::ofstream os(path.c_str());
|
||||
if (!os)
|
||||
ATF_FAIL("Could not create file " + path);
|
||||
os.close();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Helper tests for "atf-run_test".
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(pass);
|
||||
ATF_TEST_CASE_HEAD(pass)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(pass)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(config);
|
||||
ATF_TEST_CASE_HEAD(config)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(config)
|
||||
{
|
||||
std::cout << "1st: " << get_config_var("1st") << "\n";
|
||||
std::cout << "2nd: " << get_config_var("2nd") << "\n";
|
||||
std::cout << "3rd: " << get_config_var("3rd") << "\n";
|
||||
std::cout << "4th: " << get_config_var("4th") << "\n";
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(fds);
|
||||
ATF_TEST_CASE_HEAD(fds)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(fds)
|
||||
{
|
||||
std::cout << "msg1 to stdout" << "\n";
|
||||
std::cout << "msg2 to stdout" << "\n";
|
||||
std::cerr << "msg1 to stderr" << "\n";
|
||||
std::cerr << "msg2 to stderr" << "\n";
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(mux_streams);
|
||||
ATF_TEST_CASE_BODY(mux_streams)
|
||||
{
|
||||
for (size_t i = 0; i < 10000; i++) {
|
||||
switch (i % 5) {
|
||||
case 0:
|
||||
std::cout << "stdout " << i << "\n";
|
||||
break;
|
||||
case 1:
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "stdout " << i << "\n";
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
break;
|
||||
case 3:
|
||||
std::cout << "stdout " << i << "\n";
|
||||
std::cout << "stdout " << i << "\n";
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
break;
|
||||
case 4:
|
||||
std::cout << "stdout " << i << "\n";
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
std::cerr << "stderr " << i << "\n";
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(testvar);
|
||||
ATF_TEST_CASE_HEAD(testvar)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(testvar)
|
||||
{
|
||||
if (!has_config_var("testvar"))
|
||||
fail("testvar variable not defined");
|
||||
std::cout << "testvar: " << get_config_var("testvar") << "\n";
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(env_list);
|
||||
ATF_TEST_CASE_HEAD(env_list)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(env_list)
|
||||
{
|
||||
const tools::process::status s =
|
||||
tools::process::exec(tools::fs::path("env"),
|
||||
tools::process::argv_array("env", NULL),
|
||||
tools::process::stream_inherit(),
|
||||
tools::process::stream_inherit());
|
||||
ATF_REQUIRE(s.exited());
|
||||
ATF_REQUIRE(s.exitstatus() == EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(env_home);
|
||||
ATF_TEST_CASE_HEAD(env_home)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(env_home)
|
||||
{
|
||||
ATF_REQUIRE(tools::env::has("HOME"));
|
||||
tools::fs::path p(tools::env::get("HOME"));
|
||||
tools::fs::file_info fi1(p);
|
||||
tools::fs::file_info fi2(tools::fs::path("."));
|
||||
ATF_REQUIRE_EQ(fi1.get_device(), fi2.get_device());
|
||||
ATF_REQUIRE_EQ(fi1.get_inode(), fi2.get_inode());
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(read_stdin);
|
||||
ATF_TEST_CASE_HEAD(read_stdin)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(read_stdin)
|
||||
{
|
||||
char buf[100];
|
||||
ssize_t len = ::read(STDIN_FILENO, buf, sizeof(buf) - 1);
|
||||
ATF_REQUIRE(len != -1);
|
||||
|
||||
buf[len + 1] = '\0';
|
||||
for (ssize_t i = 0; i < len; i++) {
|
||||
if (buf[i] != '\0') {
|
||||
fail("The stdin of the test case does not seem to be /dev/zero; "
|
||||
"got '" + std::string(buf) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(umask);
|
||||
ATF_TEST_CASE_HEAD(umask)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(umask)
|
||||
{
|
||||
mode_t m = ::umask(0);
|
||||
std::cout << "umask: " << std::setw(4) << std::setfill('0')
|
||||
<< std::oct << m << "\n";
|
||||
(void)::umask(m);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITH_CLEANUP(cleanup_states);
|
||||
ATF_TEST_CASE_HEAD(cleanup_states)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(cleanup_states)
|
||||
{
|
||||
touch(get_config_var("statedir") + "/to-delete");
|
||||
touch(get_config_var("statedir") + "/to-stay");
|
||||
|
||||
if (get_config_var("state") == "fail")
|
||||
ATF_FAIL("On purpose");
|
||||
else if (get_config_var("state") == "skip")
|
||||
ATF_SKIP("On purpose");
|
||||
}
|
||||
ATF_TEST_CASE_CLEANUP(cleanup_states)
|
||||
{
|
||||
tools::fs::remove(tools::fs::path(get_config_var("statedir") + "/to-delete"));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITH_CLEANUP(cleanup_curdir);
|
||||
ATF_TEST_CASE_HEAD(cleanup_curdir)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(cleanup_curdir)
|
||||
{
|
||||
std::ofstream os("oldvalue");
|
||||
if (!os)
|
||||
ATF_FAIL("Failed to create oldvalue file");
|
||||
os << 1234;
|
||||
os.close();
|
||||
}
|
||||
ATF_TEST_CASE_CLEANUP(cleanup_curdir)
|
||||
{
|
||||
std::ifstream is("oldvalue");
|
||||
if (is) {
|
||||
int i;
|
||||
is >> i;
|
||||
std::cout << "Old value: " << i << "\n";
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_arch);
|
||||
ATF_TEST_CASE_HEAD(require_arch)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.arch", get_config_var("arch", "not-set"));
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_arch)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_config);
|
||||
ATF_TEST_CASE_HEAD(require_config)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.config", "var1 var2");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_config)
|
||||
{
|
||||
std::cout << "var1: " << get_config_var("var1") << "\n";
|
||||
std::cout << "var2: " << get_config_var("var2") << "\n";
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_files);
|
||||
ATF_TEST_CASE_HEAD(require_files)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.files", get_config_var("files", "not-set"));
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_files)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_machine);
|
||||
ATF_TEST_CASE_HEAD(require_machine)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.machine", get_config_var("machine", "not-set"));
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_machine)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs);
|
||||
ATF_TEST_CASE_HEAD(require_progs)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.progs", get_config_var("progs", "not-set"));
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_progs)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_user);
|
||||
ATF_TEST_CASE_HEAD(require_user)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("require.user", get_config_var("user", "not-set"));
|
||||
}
|
||||
ATF_TEST_CASE_BODY(require_user)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(timeout);
|
||||
ATF_TEST_CASE_HEAD(timeout)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("timeout", "1");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(timeout)
|
||||
{
|
||||
sleep(10);
|
||||
touch(get_config_var("statedir") + "/finished");
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(timeout_forkexit);
|
||||
ATF_TEST_CASE_HEAD(timeout_forkexit)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(timeout_forkexit)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
ATF_REQUIRE(pid != -1);
|
||||
|
||||
if (pid == 0) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
|
||||
std::cout << "Waiting in subprocess\n";
|
||||
std::cout.flush();
|
||||
::sigsuspend(&mask);
|
||||
|
||||
touch(get_config_var("statedir") + "/child-finished");
|
||||
std::cout << "Subprocess exiting\n";
|
||||
std::cout.flush();
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
// Don't wait for the child process and let atf-run deal with it.
|
||||
touch(get_config_var("statedir") + "/parent-finished");
|
||||
std::cout << "Parent process exiting\n";
|
||||
ATF_PASS();
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(use_fs);
|
||||
ATF_TEST_CASE_HEAD(use_fs)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration test program");
|
||||
set_md_var("use.fs", "this-is-deprecated");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(use_fs)
|
||||
{
|
||||
touch("test-file");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Helper tests for "atf-report_test".
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(diff);
|
||||
ATF_TEST_CASE_HEAD(diff)
|
||||
{
|
||||
set_md_var("descr", "Helper test case for the t_integration program");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(diff)
|
||||
{
|
||||
std::cout << "--- a 2007-11-04 14:00:41.000000000 +0100\n";
|
||||
std::cout << "+++ b 2007-11-04 14:00:48.000000000 +0100\n";
|
||||
std::cout << "@@ -1,7 +1,7 @@\n";
|
||||
std::cout << " This test is meant to simulate a diff.\n";
|
||||
std::cout << " Blank space at beginning of context lines must be "
|
||||
"preserved.\n";
|
||||
std::cout << " \n";
|
||||
std::cout << "-First original line.\n";
|
||||
std::cout << "-Second original line.\n";
|
||||
std::cout << "+First modified line.\n";
|
||||
std::cout << "+Second modified line.\n";
|
||||
std::cout << " \n";
|
||||
std::cout << " EOF\n";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Main.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
std::string which = tools::env::get("TESTCASE");
|
||||
|
||||
// Add helper tests for atf-run_test.
|
||||
if (which == "pass")
|
||||
ATF_ADD_TEST_CASE(tcs, pass);
|
||||
if (which == "config")
|
||||
ATF_ADD_TEST_CASE(tcs, config);
|
||||
if (which == "fds")
|
||||
ATF_ADD_TEST_CASE(tcs, fds);
|
||||
if (which == "mux_streams")
|
||||
ATF_ADD_TEST_CASE(tcs, mux_streams);
|
||||
if (which == "testvar")
|
||||
ATF_ADD_TEST_CASE(tcs, testvar);
|
||||
if (which == "env_list")
|
||||
ATF_ADD_TEST_CASE(tcs, env_list);
|
||||
if (which == "env_home")
|
||||
ATF_ADD_TEST_CASE(tcs, env_home);
|
||||
if (which == "read_stdin")
|
||||
ATF_ADD_TEST_CASE(tcs, read_stdin);
|
||||
if (which == "umask")
|
||||
ATF_ADD_TEST_CASE(tcs, umask);
|
||||
if (which == "cleanup_states")
|
||||
ATF_ADD_TEST_CASE(tcs, cleanup_states);
|
||||
if (which == "cleanup_curdir")
|
||||
ATF_ADD_TEST_CASE(tcs, cleanup_curdir);
|
||||
if (which == "require_arch")
|
||||
ATF_ADD_TEST_CASE(tcs, require_arch);
|
||||
if (which == "require_config")
|
||||
ATF_ADD_TEST_CASE(tcs, require_config);
|
||||
if (which == "require_files")
|
||||
ATF_ADD_TEST_CASE(tcs, require_files);
|
||||
if (which == "require_machine")
|
||||
ATF_ADD_TEST_CASE(tcs, require_machine);
|
||||
if (which == "require_progs")
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs);
|
||||
if (which == "require_user")
|
||||
ATF_ADD_TEST_CASE(tcs, require_user);
|
||||
if (which == "timeout")
|
||||
ATF_ADD_TEST_CASE(tcs, timeout);
|
||||
if (which == "timeout_forkexit")
|
||||
ATF_ADD_TEST_CASE(tcs, timeout_forkexit);
|
||||
if (which == "use_fs")
|
||||
ATF_ADD_TEST_CASE(tcs, use_fs);
|
||||
|
||||
// Add helper tests for atf-report_test.
|
||||
if (which == "diff")
|
||||
ATF_ADD_TEST_CASE(tcs, diff);
|
||||
}
|
384
tools/parser.cpp
384
tools/parser.cpp
@ -1,384 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace impl = tools::parser;
|
||||
#define IMPL_NAME "tools::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 tools::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 = tools::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);
|
||||
assert(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++) {
|
||||
assert((*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)
|
||||
{
|
||||
assert(!hm.empty());
|
||||
headers_map::const_iterator ct = hm.find("Content-Type");
|
||||
assert(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 = tools::text::to_string(version);
|
||||
if (he.get_attr("version") != vstr)
|
||||
throw format_error("Mismatched version: expected `" +
|
||||
vstr + "' but got `" +
|
||||
he.get_attr("version") + "'");
|
||||
}
|
607
tools/parser.hpp
607
tools/parser.hpp
@ -1,607 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_PARSER_HPP)
|
||||
#define TOOLS_PARSER_HPP
|
||||
|
||||
#include <istream>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace tools {
|
||||
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.putback(ch);
|
||||
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.putback(ch);
|
||||
} else if (ch == '\n') {
|
||||
done = true;
|
||||
if (text.empty())
|
||||
t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
|
||||
else
|
||||
m_is.putback(ch);
|
||||
} 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 tools
|
||||
|
||||
#endif // !defined(TOOLS_PARSER_HPP)
|
File diff suppressed because it is too large
Load Diff
@ -1,44 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
ATF_TEST_CASE(main);
|
||||
ATF_TEST_CASE_HEAD(main)
|
||||
{
|
||||
set_md_var("descr", "Helper test case that always passes");
|
||||
}
|
||||
ATF_TEST_CASE_BODY(main)
|
||||
{
|
||||
}
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
ATF_ADD_TEST_CASE(tcs, main);
|
||||
}
|
@ -1,492 +0,0 @@
|
||||
//
|
||||
// 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 <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "defs.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "text.hpp"
|
||||
#include "process.hpp"
|
||||
|
||||
namespace detail = tools::process::detail;
|
||||
namespace impl = tools::process;
|
||||
#define IMPL_NAME "tools::process"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template< class C >
|
||||
tools::auto_array< const char* >
|
||||
collection_to_argv(const C& c)
|
||||
{
|
||||
tools::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++;
|
||||
}
|
||||
assert(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;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
safe_dup(const int oldfd, const int newfd)
|
||||
{
|
||||
if (oldfd != newfd) {
|
||||
if (dup2(oldfd, newfd) == -1) {
|
||||
throw tools::system_error(IMPL_NAME "::safe_dup",
|
||||
"Could not allocate file descriptor",
|
||||
errno);
|
||||
} else {
|
||||
::close(oldfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
const_execvp(const char *file, const char *const *argv)
|
||||
{
|
||||
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
|
||||
return ::execvp(file, (char* const*)(UNCONST(argv)));
|
||||
#undef UNCONST
|
||||
}
|
||||
|
||||
void
|
||||
detail::do_exec(void *v)
|
||||
{
|
||||
struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
|
||||
|
||||
if (ea->m_prehook != NULL)
|
||||
ea->m_prehook();
|
||||
|
||||
const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
|
||||
const int errnocopy = errno;
|
||||
assert(ret == -1);
|
||||
std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
|
||||
<< std::strerror(errnocopy) << "\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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::stream_capture::stream_capture(void)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
m_pipefds[i] = -1;
|
||||
}
|
||||
|
||||
impl::stream_capture::~stream_capture(void)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (m_pipefds[i] != -1)
|
||||
::close(m_pipefds[i]);
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_capture::prepare(void)
|
||||
{
|
||||
if (pipe(m_pipefds) == -1)
|
||||
throw system_error(IMPL_NAME "::stream_capture::prepare",
|
||||
"Failed to create pipe", errno);
|
||||
}
|
||||
|
||||
int
|
||||
impl::stream_capture::connect_parent(void)
|
||||
{
|
||||
::close(m_pipefds[1]); m_pipefds[1] = -1;
|
||||
const int fd = m_pipefds[0];
|
||||
m_pipefds[0] = -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_capture::connect_child(const int fd)
|
||||
{
|
||||
::close(m_pipefds[0]); m_pipefds[0] = -1;
|
||||
if (m_pipefds[1] != fd) {
|
||||
safe_dup(m_pipefds[1], fd);
|
||||
}
|
||||
m_pipefds[1] = -1;
|
||||
}
|
||||
|
||||
impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
|
||||
m_src_fd(src_fd), m_tgt_fd(tgt_fd)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_connect::prepare(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
impl::stream_connect::connect_parent(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_connect::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
safe_dup(m_tgt_fd, m_src_fd);
|
||||
}
|
||||
|
||||
impl::stream_inherit::stream_inherit(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_inherit::prepare(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
impl::stream_inherit::connect_parent(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_inherit::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
impl::stream_redirect_fd::stream_redirect_fd(const int fd) :
|
||||
m_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_redirect_fd::prepare(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
impl::stream_redirect_fd::connect_parent(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_redirect_fd::connect_child(const int fd)
|
||||
{
|
||||
safe_dup(m_fd, fd);
|
||||
}
|
||||
|
||||
impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
|
||||
m_path(p)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_redirect_path::prepare(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
impl::stream_redirect_path::connect_parent(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
impl::stream_redirect_path::connect_child(const int fd)
|
||||
{
|
||||
const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (aux == -1)
|
||||
throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
|
||||
"Could not create " + m_path.str(), errno);
|
||||
else
|
||||
safe_dup(aux, fd);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "status" type.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::status::status(int s) :
|
||||
m_status(s)
|
||||
{
|
||||
}
|
||||
|
||||
impl::status::~status(void)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
impl::status::exited(void)
|
||||
const
|
||||
{
|
||||
int mutable_status = m_status;
|
||||
return WIFEXITED(mutable_status);
|
||||
}
|
||||
|
||||
int
|
||||
impl::status::exitstatus(void)
|
||||
const
|
||||
{
|
||||
assert(exited());
|
||||
int mutable_status = m_status;
|
||||
return WEXITSTATUS(mutable_status);
|
||||
}
|
||||
|
||||
bool
|
||||
impl::status::signaled(void)
|
||||
const
|
||||
{
|
||||
int mutable_status = m_status;
|
||||
return WIFSIGNALED(mutable_status);
|
||||
}
|
||||
|
||||
int
|
||||
impl::status::termsig(void)
|
||||
const
|
||||
{
|
||||
assert(signaled());
|
||||
int mutable_status = m_status;
|
||||
return WTERMSIG(mutable_status);
|
||||
}
|
||||
|
||||
bool
|
||||
impl::status::coredump(void)
|
||||
const
|
||||
{
|
||||
assert(signaled());
|
||||
#if defined(WCOREDUMP)
|
||||
int mutable_status = m_status;
|
||||
return WCOREDUMP(mutable_status);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "child" type.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
|
||||
const int stderr_fd_arg) :
|
||||
m_pid(pid_arg),
|
||||
m_stdout(stdout_fd_arg),
|
||||
m_stderr(stderr_fd_arg),
|
||||
m_waited(false)
|
||||
{
|
||||
}
|
||||
|
||||
impl::child::~child(void)
|
||||
{
|
||||
if (!m_waited) {
|
||||
::kill(m_pid, SIGTERM);
|
||||
(void)wait();
|
||||
|
||||
if (m_stdout != -1)
|
||||
::close(m_stdout);
|
||||
if (m_stderr != -1)
|
||||
::close(m_stderr);
|
||||
}
|
||||
}
|
||||
|
||||
impl::status
|
||||
impl::child::wait(void)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (::waitpid(m_pid, &s, 0) == -1)
|
||||
throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
|
||||
"process " + text::to_string(m_pid), errno);
|
||||
|
||||
if (m_stdout != -1)
|
||||
::close(m_stdout); m_stdout = -1;
|
||||
if (m_stderr != -1)
|
||||
::close(m_stderr); m_stderr = -1;
|
||||
|
||||
m_waited = true;
|
||||
return status(s);
|
||||
}
|
||||
|
||||
pid_t
|
||||
impl::child::pid(void)
|
||||
const
|
||||
{
|
||||
return m_pid;
|
||||
}
|
||||
|
||||
int
|
||||
impl::child::stdout_fd(void)
|
||||
{
|
||||
return m_stdout;
|
||||
}
|
||||
|
||||
int
|
||||
impl::child::stderr_fd(void)
|
||||
{
|
||||
return m_stderr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// 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();
|
||||
}
|
@ -1,324 +0,0 @@
|
||||
//
|
||||
// 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(TOOLS_PROCESS_HPP)
|
||||
#define TOOLS_PROCESS_HPP
|
||||
|
||||
extern "C" {
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "auto_array.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "fs.hpp"
|
||||
|
||||
namespace tools {
|
||||
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.
|
||||
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 stream_capture {
|
||||
int m_pipefds[2];
|
||||
|
||||
// Allow access to the getters.
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
void prepare(void);
|
||||
int connect_parent(void);
|
||||
void connect_child(const int);
|
||||
|
||||
public:
|
||||
stream_capture(void);
|
||||
~stream_capture(void);
|
||||
};
|
||||
|
||||
class stream_connect {
|
||||
int m_src_fd;
|
||||
int m_tgt_fd;
|
||||
|
||||
// Allow access to the getters.
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
void prepare(void);
|
||||
int connect_parent(void);
|
||||
void connect_child(const int);
|
||||
|
||||
public:
|
||||
stream_connect(const int, const int);
|
||||
};
|
||||
|
||||
class stream_inherit {
|
||||
// Allow access to the getters.
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
void prepare(void);
|
||||
int connect_parent(void);
|
||||
void connect_child(const int);
|
||||
|
||||
public:
|
||||
stream_inherit(void);
|
||||
};
|
||||
|
||||
class stream_redirect_fd {
|
||||
int m_fd;
|
||||
|
||||
// Allow access to the getters.
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
void prepare(void);
|
||||
int connect_parent(void);
|
||||
void connect_child(const int);
|
||||
|
||||
public:
|
||||
stream_redirect_fd(const int);
|
||||
};
|
||||
|
||||
class stream_redirect_path {
|
||||
const tools::fs::path m_path;
|
||||
|
||||
// Allow access to the getters.
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
void prepare(void);
|
||||
int connect_parent(void);
|
||||
void connect_child(const int);
|
||||
|
||||
public:
|
||||
stream_redirect_path(const tools::fs::path&);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "status" type.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
class status {
|
||||
int m_status;
|
||||
|
||||
friend class child;
|
||||
template< class OutStream, class ErrStream > friend
|
||||
status exec(const tools::fs::path&, const argv_array&,
|
||||
const OutStream&, const ErrStream&, void (*)(void));
|
||||
|
||||
status(int);
|
||||
|
||||
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 {
|
||||
pid_t m_pid;
|
||||
|
||||
int m_stdout;
|
||||
int m_stderr;
|
||||
|
||||
bool m_waited;
|
||||
|
||||
template< class OutStream, class ErrStream > friend
|
||||
child fork(void (*)(void*), OutStream, ErrStream, void*);
|
||||
|
||||
child(const pid_t, const int, const int);
|
||||
|
||||
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);
|
||||
|
||||
struct exec_args {
|
||||
const tools::fs::path m_prog;
|
||||
const argv_array& m_argv;
|
||||
void (*m_prehook)(void);
|
||||
};
|
||||
|
||||
void do_exec(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*), OutStream outsb, ErrStream errsb, void* v)
|
||||
{
|
||||
detail::flush_streams();
|
||||
|
||||
outsb.prepare();
|
||||
errsb.prepare();
|
||||
|
||||
pid_t pid = ::fork();
|
||||
if (pid == -1) {
|
||||
throw system_error("tools::process::child::fork",
|
||||
"Failed to fork", errno);
|
||||
} else if (pid == 0) {
|
||||
try {
|
||||
outsb.connect_child(STDOUT_FILENO);
|
||||
errsb.connect_child(STDERR_FILENO);
|
||||
start(v);
|
||||
std::abort();
|
||||
} catch (...) {
|
||||
std::cerr << "Unhandled error while running subprocess\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
const int stdout_fd = outsb.connect_parent();
|
||||
const int stderr_fd = errsb.connect_parent();
|
||||
return child(pid, stdout_fd, stderr_fd);
|
||||
}
|
||||
}
|
||||
|
||||
template< class OutStream, class ErrStream >
|
||||
status
|
||||
exec(const tools::fs::path& prog, const argv_array& argv,
|
||||
const OutStream& outsb, const ErrStream& errsb,
|
||||
void (*prehook)(void))
|
||||
{
|
||||
struct detail::exec_args ea = { prog, argv, prehook };
|
||||
child c = fork(detail::do_exec, outsb, errsb, &ea);
|
||||
|
||||
again:
|
||||
try {
|
||||
return c.wait();
|
||||
} catch (const system_error& e) {
|
||||
if (e.code() == EINTR)
|
||||
goto again;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
template< class OutStream, class ErrStream >
|
||||
status
|
||||
exec(const tools::fs::path& prog, const argv_array& argv,
|
||||
const OutStream& outsb, const ErrStream& errsb)
|
||||
{
|
||||
return exec(prog, argv, outsb, errsb, NULL);
|
||||
}
|
||||
|
||||
} // namespace process
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_PROCESS_HPP)
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/types.h>
|
||||
|
||||
#include <assert.h> /* NO_CHECK_STYLE */
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static
|
||||
int
|
||||
h_echo(const char *msg)
|
||||
{
|
||||
printf("%s\n", msg);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
h_exit_failure(void)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
h_exit_signal(void)
|
||||
{
|
||||
kill(getpid(), SIGKILL);
|
||||
assert(0); /* NO_CHECK_STYLE */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
h_exit_success(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
h_stdout_stderr(const char *id)
|
||||
{
|
||||
fprintf(stdout, "Line 1 to stdout for %s\n", id);
|
||||
fprintf(stdout, "Line 2 to stdout for %s\n", id);
|
||||
fprintf(stderr, "Line 1 to stderr for %s\n", id);
|
||||
fprintf(stderr, "Line 2 to stderr for %s\n", id);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
check_args(const int argc, const char *const argv[], const int required)
|
||||
{
|
||||
if (argc < required) {
|
||||
fprintf(stderr, "Usage: %s helper-name [args]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char *const argv[])
|
||||
{
|
||||
int exitcode;
|
||||
|
||||
check_args(argc, argv, 2);
|
||||
|
||||
if (strcmp(argv[1], "echo") == 0) {
|
||||
check_args(argc, argv, 3);
|
||||
exitcode = h_echo(argv[2]);
|
||||
} else if (strcmp(argv[1], "exit-failure") == 0)
|
||||
exitcode = h_exit_failure();
|
||||
else if (strcmp(argv[1], "exit-signal") == 0)
|
||||
exitcode = h_exit_signal();
|
||||
else if (strcmp(argv[1], "exit-success") == 0)
|
||||
exitcode = h_exit_success();
|
||||
else if (strcmp(argv[1], "stdout-stderr") == 0) {
|
||||
check_args(argc, argv, 3);
|
||||
exitcode = h_stdout_stderr(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "%s: Unknown helper %s\n", argv[0], argv[1]);
|
||||
exitcode = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return exitcode;
|
||||
}
|
@ -1,360 +0,0 @@
|
||||
//
|
||||
// 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 <atf-c++.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
|
||||
tools::process::status
|
||||
exec_process_helpers(const atf::tests::tc& tc, const char* helper_name)
|
||||
{
|
||||
using tools::process::exec;
|
||||
|
||||
const tools::fs::path helpers = tools::fs::path(tc.get_config_var("srcdir")) /
|
||||
"process_helpers";
|
||||
|
||||
std::vector< std::string > argv;
|
||||
argv.push_back(helpers.leaf_name());
|
||||
argv.push_back(helper_name);
|
||||
|
||||
return exec(helpers,
|
||||
tools::process::argv_array(argv),
|
||||
tools::process::stream_inherit(),
|
||||
tools::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 };
|
||||
tools::process::argv_array argv(carray);
|
||||
|
||||
ATF_REQUIRE_EQ(argv.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
const char* const carray[] = { "arg0", NULL };
|
||||
tools::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 };
|
||||
tools::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;
|
||||
tools::process::argv_array argv(col);
|
||||
|
||||
ATF_REQUIRE_EQ(argv.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector< std::string > col;
|
||||
col.push_back("arg0");
|
||||
tools::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");
|
||||
tools::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)
|
||||
{
|
||||
tools::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)
|
||||
{
|
||||
{
|
||||
tools::process::argv_array argv("arg0", NULL);
|
||||
|
||||
ATF_REQUIRE_EQ(argv.size(), 1);
|
||||
ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
|
||||
}
|
||||
|
||||
{
|
||||
tools::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 tools::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 tools::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 tools::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 tools::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 tools::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 tools::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);
|
||||
}
|
440
tools/reader.cpp
440
tools/reader.cpp
@ -1,440 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/time.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "defs.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "reader.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace impl = tools::atf_report;
|
||||
#define IMPL_NAME "tools::atf_report"
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template< typename Type >
|
||||
Type
|
||||
string_to_int(const std::string& str)
|
||||
{
|
||||
std::istringstream ss(str);
|
||||
Type s;
|
||||
ss >> s;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_tps" auxiliary parser.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace atf_tps {
|
||||
|
||||
static const tools::parser::token_type eof_type = 0;
|
||||
static const tools::parser::token_type nl_type = 1;
|
||||
static const tools::parser::token_type text_type = 2;
|
||||
static const tools::parser::token_type colon_type = 3;
|
||||
static const tools::parser::token_type comma_type = 4;
|
||||
static const tools::parser::token_type tps_count_type = 5;
|
||||
static const tools::parser::token_type tp_start_type = 6;
|
||||
static const tools::parser::token_type tp_end_type = 7;
|
||||
static const tools::parser::token_type tc_start_type = 8;
|
||||
static const tools::parser::token_type tc_so_type = 9;
|
||||
static const tools::parser::token_type tc_se_type = 10;
|
||||
static const tools::parser::token_type tc_end_type = 11;
|
||||
static const tools::parser::token_type passed_type = 12;
|
||||
static const tools::parser::token_type failed_type = 13;
|
||||
static const tools::parser::token_type skipped_type = 14;
|
||||
static const tools::parser::token_type info_type = 16;
|
||||
static const tools::parser::token_type expected_death_type = 17;
|
||||
static const tools::parser::token_type expected_exit_type = 18;
|
||||
static const tools::parser::token_type expected_failure_type = 19;
|
||||
static const tools::parser::token_type expected_signal_type = 20;
|
||||
static const tools::parser::token_type expected_timeout_type = 21;
|
||||
|
||||
class tokenizer : public tools::parser::tokenizer< std::istream > {
|
||||
public:
|
||||
tokenizer(std::istream& is, size_t curline) :
|
||||
tools::parser::tokenizer< std::istream >
|
||||
(is, true, eof_type, nl_type, text_type, curline)
|
||||
{
|
||||
add_delim(':', colon_type);
|
||||
add_delim(',', comma_type);
|
||||
add_keyword("tps-count", tps_count_type);
|
||||
add_keyword("tp-start", tp_start_type);
|
||||
add_keyword("tp-end", tp_end_type);
|
||||
add_keyword("tc-start", tc_start_type);
|
||||
add_keyword("tc-so", tc_so_type);
|
||||
add_keyword("tc-se", tc_se_type);
|
||||
add_keyword("tc-end", tc_end_type);
|
||||
add_keyword("passed", passed_type);
|
||||
add_keyword("failed", failed_type);
|
||||
add_keyword("skipped", skipped_type);
|
||||
add_keyword("info", info_type);
|
||||
add_keyword("expected_death", expected_death_type);
|
||||
add_keyword("expected_exit", expected_exit_type);
|
||||
add_keyword("expected_failure", expected_failure_type);
|
||||
add_keyword("expected_signal", expected_signal_type);
|
||||
add_keyword("expected_timeout", expected_timeout_type);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace atf_tps
|
||||
|
||||
struct timeval
|
||||
read_timeval(tools::parser::parser< atf_tps::tokenizer >& parser)
|
||||
{
|
||||
using namespace atf_tps;
|
||||
|
||||
tools::parser::token t = parser.expect(text_type, "timestamp");
|
||||
const std::string::size_type divider = t.text().find('.');
|
||||
if (divider == std::string::npos || divider == 0 ||
|
||||
divider == t.text().length() - 1)
|
||||
throw tools::parser::parse_error(t.lineno(),
|
||||
"Malformed timestamp value " + t.text());
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = string_to_int< long >(t.text().substr(0, divider));
|
||||
tv.tv_usec = string_to_int< long >(t.text().substr(divider + 1));
|
||||
return tv;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// The "atf_tps_reader" class.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
impl::atf_tps_reader::atf_tps_reader(std::istream& is) :
|
||||
m_is(is)
|
||||
{
|
||||
}
|
||||
|
||||
impl::atf_tps_reader::~atf_tps_reader(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_info(
|
||||
const std::string& what ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& val ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_ntps(size_t ntps ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tp_start(
|
||||
const std::string& tp ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
size_t ntcs ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tp_end(
|
||||
struct timeval* tv ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& reason ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tc_start(
|
||||
const std::string& tcname ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tc_stdout_line(
|
||||
const std::string& line ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tc_stderr_line(
|
||||
const std::string& line ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_tc_end(
|
||||
const std::string& state ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
struct timeval* tv ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& reason ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::got_eof(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::read_info(void* pptr)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_tps;
|
||||
|
||||
tools::parser::parser< tokenizer >& p =
|
||||
*reinterpret_cast< tools::parser::parser< tokenizer >* >
|
||||
(pptr);
|
||||
|
||||
(void)p.expect(colon_type, "`:'");
|
||||
|
||||
tools::parser::token t = p.expect(text_type, "info property name");
|
||||
(void)p.expect(comma_type, "`,'");
|
||||
got_info(t.text(), tools::text::trim(p.rest_of_line()));
|
||||
|
||||
(void)p.expect(nl_type, "new line");
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::read_tp(void* pptr)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_tps;
|
||||
|
||||
tools::parser::parser< tokenizer >& p =
|
||||
*reinterpret_cast< tools::parser::parser< tokenizer >* >
|
||||
(pptr);
|
||||
|
||||
tools::parser::token t = p.expect(tp_start_type,
|
||||
"start of test program");
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
struct timeval s1 = read_timeval(p);
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(text_type, "test program name");
|
||||
std::string tpname = t.text();
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(text_type, "number of test programs");
|
||||
size_t ntcs = string_to_int< std::size_t >(t.text());
|
||||
|
||||
t = p.expect(nl_type, "new line");
|
||||
|
||||
ATF_PARSER_CALLBACK(p, got_tp_start(tpname, ntcs));
|
||||
|
||||
size_t i = 0;
|
||||
while (p.good() && i < ntcs) {
|
||||
try {
|
||||
read_tc(&p);
|
||||
i++;
|
||||
} catch (const parse_error& pe) {
|
||||
p.add_error(pe);
|
||||
p.reset(nl_type);
|
||||
}
|
||||
}
|
||||
t = p.expect(tp_end_type, "end of test program");
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
struct timeval s2 = read_timeval(p);
|
||||
|
||||
struct timeval s3;
|
||||
timersub(&s2, &s1, &s3);
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(text_type, "test program name");
|
||||
if (t.text() != tpname)
|
||||
throw parse_error(t.lineno(), "Test program name used in "
|
||||
"terminator does not match "
|
||||
"opening");
|
||||
|
||||
t = p.expect(nl_type, comma_type,
|
||||
"new line or comma_type");
|
||||
std::string reason;
|
||||
if (t.type() == comma_type) {
|
||||
reason = tools::text::trim(p.rest_of_line());
|
||||
if (reason.empty())
|
||||
throw parse_error(t.lineno(),
|
||||
"Empty reason for failed test program");
|
||||
t = p.next();
|
||||
}
|
||||
|
||||
ATF_PARSER_CALLBACK(p, got_tp_end(&s3, reason));
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::read_tc(void* pptr)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_tps;
|
||||
|
||||
tools::parser::parser< tokenizer >& p =
|
||||
*reinterpret_cast< tools::parser::parser< tokenizer >* >
|
||||
(pptr);
|
||||
|
||||
tools::parser::token t = p.expect(tc_start_type, "start of test case");
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
struct timeval s1 = read_timeval(p);
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(text_type, "test case name");
|
||||
std::string tcname = t.text();
|
||||
|
||||
ATF_PARSER_CALLBACK(p, got_tc_start(tcname));
|
||||
|
||||
t = p.expect(nl_type, "new line");
|
||||
|
||||
t = p.expect(tc_end_type, tc_so_type, tc_se_type,
|
||||
"end of test case or test case's stdout/stderr line");
|
||||
while (t.type() != tc_end_type &&
|
||||
(t.type() == tc_so_type || t.type() == tc_se_type)) {
|
||||
tools::parser::token t2 = t;
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
std::string line = p.rest_of_line();
|
||||
|
||||
if (t2.type() == tc_so_type) {
|
||||
ATF_PARSER_CALLBACK(p, got_tc_stdout_line(line));
|
||||
} else {
|
||||
assert(t2.type() == tc_se_type);
|
||||
ATF_PARSER_CALLBACK(p, got_tc_stderr_line(line));
|
||||
}
|
||||
|
||||
t = p.expect(nl_type, "new line");
|
||||
|
||||
t = p.expect(tc_end_type, tc_so_type, tc_se_type,
|
||||
"end of test case or test case's stdout/stderr line");
|
||||
}
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
struct timeval s2 = read_timeval(p);
|
||||
|
||||
struct timeval s3;
|
||||
timersub(&s2, &s1, &s3);
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(text_type, "test case name");
|
||||
if (t.text() != tcname)
|
||||
throw parse_error(t.lineno(),
|
||||
"Test case name used in terminator does not "
|
||||
"match opening");
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
|
||||
t = p.expect(expected_death_type, expected_exit_type, expected_failure_type,
|
||||
expected_signal_type, expected_timeout_type, passed_type, failed_type,
|
||||
skipped_type, "expected_{death,exit,failure,signal,timeout}, failed, "
|
||||
"passed or skipped");
|
||||
if (t.type() == passed_type) {
|
||||
ATF_PARSER_CALLBACK(p, got_tc_end("passed", &s3, ""));
|
||||
} else {
|
||||
std::string state;
|
||||
if (t.type() == expected_death_type) state = "expected_death";
|
||||
else if (t.type() == expected_exit_type) state = "expected_exit";
|
||||
else if (t.type() == expected_failure_type) state = "expected_failure";
|
||||
else if (t.type() == expected_signal_type) state = "expected_signal";
|
||||
else if (t.type() == expected_timeout_type) state = "expected_timeout";
|
||||
else if (t.type() == failed_type) state = "failed";
|
||||
else if (t.type() == skipped_type) state = "skipped";
|
||||
else std::abort();
|
||||
|
||||
t = p.expect(comma_type, "`,'");
|
||||
std::string reason = tools::text::trim(p.rest_of_line());
|
||||
if (reason.empty())
|
||||
throw parse_error(t.lineno(), "Empty reason for " + state +
|
||||
" test case result");
|
||||
ATF_PARSER_CALLBACK(p, got_tc_end(state, &s3, reason));
|
||||
}
|
||||
|
||||
t = p.expect(nl_type, "new line");
|
||||
}
|
||||
|
||||
void
|
||||
impl::atf_tps_reader::read(void)
|
||||
{
|
||||
using tools::parser::parse_error;
|
||||
using namespace atf_tps;
|
||||
|
||||
std::pair< size_t, tools::parser::headers_map > hml =
|
||||
tools::parser::read_headers(m_is, 1);
|
||||
tools::parser::validate_content_type(hml.second,
|
||||
"application/X-atf-tps", 3);
|
||||
|
||||
tokenizer tkz(m_is, hml.first);
|
||||
tools::parser::parser< tokenizer > p(tkz);
|
||||
|
||||
try {
|
||||
tools::parser::token t;
|
||||
|
||||
while ((t = p.expect(tps_count_type, info_type, "tps-count or info "
|
||||
"field")).type() == info_type)
|
||||
read_info(&p);
|
||||
|
||||
t = p.expect(colon_type, "`:'");
|
||||
|
||||
t = p.expect(text_type, "number of test programs");
|
||||
size_t ntps = string_to_int< std::size_t >(t.text());
|
||||
ATF_PARSER_CALLBACK(p, got_ntps(ntps));
|
||||
|
||||
t = p.expect(nl_type, "new line");
|
||||
|
||||
size_t i = 0;
|
||||
while (p.good() && i < ntps) {
|
||||
try {
|
||||
read_tp(&p);
|
||||
i++;
|
||||
} catch (const parse_error& pe) {
|
||||
p.add_error(pe);
|
||||
p.reset(nl_type);
|
||||
}
|
||||
}
|
||||
|
||||
while ((t = p.expect(eof_type, info_type, "end of stream or info "
|
||||
"field")).type() == info_type)
|
||||
read_info(&p);
|
||||
ATF_PARSER_CALLBACK(p, got_eof());
|
||||
} catch (const parse_error& pe) {
|
||||
p.add_error(pe);
|
||||
p.reset(nl_type);
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#if !defined(TOOLS_FORMATS_HPP)
|
||||
#define TOOLS_FORMATS_HPP
|
||||
|
||||
extern "C" {
|
||||
#include <sys/time.h>
|
||||
}
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
namespace atf_report {
|
||||
|
||||
struct test_case_result {
|
||||
enum state_enum {
|
||||
PASSED,
|
||||
FAILED,
|
||||
SKIPPED,
|
||||
};
|
||||
const state_enum state;
|
||||
const std::string& reason;
|
||||
|
||||
test_case_result(const state_enum p_state, const std::string& p_reason) :
|
||||
state(p_state),
|
||||
reason(p_reason)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class atf_tps_reader {
|
||||
std::istream& m_is;
|
||||
|
||||
void read_info(void*);
|
||||
void read_tp(void*);
|
||||
void read_tc(void*);
|
||||
|
||||
protected:
|
||||
virtual void got_info(const std::string&, const std::string&);
|
||||
virtual void got_ntps(size_t);
|
||||
virtual void got_tp_start(const std::string&, size_t);
|
||||
virtual void got_tp_end(struct timeval*, const std::string&);
|
||||
|
||||
virtual void got_tc_start(const std::string&);
|
||||
virtual void got_tc_stdout_line(const std::string&);
|
||||
virtual void got_tc_stderr_line(const std::string&);
|
||||
virtual void got_tc_end(const std::string&, struct timeval*,
|
||||
const std::string&);
|
||||
virtual void got_eof(void);
|
||||
|
||||
public:
|
||||
atf_tps_reader(std::istream&);
|
||||
virtual ~atf_tps_reader(void);
|
||||
|
||||
void read(void);
|
||||
};
|
||||
|
||||
} // namespace atf_report
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_FORMATS_HPP)
|
@ -1,987 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2010 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 <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <atf-c++.hpp>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "reader.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace impl = tools::atf_report;
|
||||
|
||||
class tps_reader : protected impl::atf_tps_reader {
|
||||
void
|
||||
got_info(const std::string& what, const std::string& val)
|
||||
{
|
||||
m_calls.push_back("got_info(" + what + ", " + val + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_ntps(size_t ntps)
|
||||
{
|
||||
m_calls.push_back("got_ntps(" + tools::text::to_string(ntps) + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tp_start(const std::string& tpname, size_t ntcs)
|
||||
{
|
||||
m_calls.push_back("got_tp_start(" + tpname + ", " +
|
||||
tools::text::to_string(ntcs) + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tp_end(struct timeval* tv ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& reason)
|
||||
{
|
||||
m_calls.push_back("got_tp_end(" + reason + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_start(const std::string& tcname)
|
||||
{
|
||||
m_calls.push_back("got_tc_start(" + tcname + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_end(const std::string& state,
|
||||
struct timeval* tv ATF_DEFS_ATTRIBUTE_UNUSED,
|
||||
const std::string& reason)
|
||||
{
|
||||
const std::string r = state + (reason.empty() ? "" : ", " + reason);
|
||||
m_calls.push_back("got_tc_end(" + r + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_stdout_line(const std::string& line)
|
||||
{
|
||||
m_calls.push_back("got_tc_stdout_line(" + line + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_tc_stderr_line(const std::string& line)
|
||||
{
|
||||
m_calls.push_back("got_tc_stderr_line(" + line + ")");
|
||||
}
|
||||
|
||||
void
|
||||
got_eof(void)
|
||||
{
|
||||
m_calls.push_back("got_eof()");
|
||||
}
|
||||
|
||||
public:
|
||||
tps_reader(std::istream& is) :
|
||||
impl::atf_tps_reader(is)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
read(void)
|
||||
{
|
||||
atf_tps_reader::read();
|
||||
}
|
||||
|
||||
std::vector< std::string > m_calls;
|
||||
};
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_1);
|
||||
ATF_TEST_CASE_BODY(tps_1)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 0\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(0)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_2);
|
||||
ATF_TEST_CASE_BODY(tps_2)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 2\n"
|
||||
"tp-start: 123.456, first-prog, 0\n"
|
||||
"tp-end: 123.567, first-prog\n"
|
||||
"tp-start: 123.678, second-prog, 0\n"
|
||||
"tp-end: 123.789, second-prog, This program failed\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(2)",
|
||||
"got_tp_start(first-prog, 0)",
|
||||
"got_tp_end()",
|
||||
"got_tp_start(second-prog, 0)",
|
||||
"got_tp_end(This program failed)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_3);
|
||||
ATF_TEST_CASE_BODY(tps_3)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 2\n"
|
||||
"tp-start: 123.123, first-prog, 3\n"
|
||||
"tc-start: 123.234, first-test\n"
|
||||
"tc-end: 123.345, first-test, passed\n"
|
||||
"tc-start: 123.456, second-test\n"
|
||||
"tc-end: 123.567, second-test, skipped, Testing skipped reason\n"
|
||||
"tc-start: 123.678, third.test\n"
|
||||
"tc-end: 123.789, third.test, failed, Testing failed reason\n"
|
||||
"tp-end: 123.890, first-prog\n"
|
||||
"tp-start: 124.901, second-prog, 3\n"
|
||||
"tc-start: 124.1012, first-test\n"
|
||||
"tc-so:first stdout line for 1st test\n"
|
||||
"tc-se:first stderr line for 1st test\n"
|
||||
"tc-so:second stdout line for 1st test\n"
|
||||
"tc-se:second stderr line for 1st test\n"
|
||||
"tc-end: 124.1123, first-test, passed\n"
|
||||
"tc-start: 124.1234, second-test\n"
|
||||
"tc-so:first stdout line for 2nd test\n"
|
||||
"tc-se:first stderr line for 2nd test\n"
|
||||
"tc-so:second stdout line for 2nd test\n"
|
||||
"tc-se:second stderr line for 2nd test\n"
|
||||
"tc-end: 124.1345, second-test, skipped, Testing skipped reason\n"
|
||||
"tc-start: 124.1456, third.test\n"
|
||||
"tc-so:first stdout line for 3rd test\n"
|
||||
"tc-se:first stderr line for 3rd test\n"
|
||||
"tc-so:second stdout line for 3rd test\n"
|
||||
"tc-se:second stderr line for 3rd test\n"
|
||||
"tc-end: 124.1567, third.test, failed, Testing failed reason\n"
|
||||
"tp-end: 124.1678, second-prog, This program failed\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(2)",
|
||||
"got_tp_start(first-prog, 3)",
|
||||
"got_tc_start(first-test)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tc_start(second-test)",
|
||||
"got_tc_end(skipped, Testing skipped reason)",
|
||||
"got_tc_start(third.test)",
|
||||
"got_tc_end(failed, Testing failed reason)",
|
||||
"got_tp_end()",
|
||||
"got_tp_start(second-prog, 3)",
|
||||
"got_tc_start(first-test)",
|
||||
"got_tc_stdout_line(first stdout line for 1st test)",
|
||||
"got_tc_stderr_line(first stderr line for 1st test)",
|
||||
"got_tc_stdout_line(second stdout line for 1st test)",
|
||||
"got_tc_stderr_line(second stderr line for 1st test)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tc_start(second-test)",
|
||||
"got_tc_stdout_line(first stdout line for 2nd test)",
|
||||
"got_tc_stderr_line(first stderr line for 2nd test)",
|
||||
"got_tc_stdout_line(second stdout line for 2nd test)",
|
||||
"got_tc_stderr_line(second stderr line for 2nd test)",
|
||||
"got_tc_end(skipped, Testing skipped reason)",
|
||||
"got_tc_start(third.test)",
|
||||
"got_tc_stdout_line(first stdout line for 3rd test)",
|
||||
"got_tc_stderr_line(first stderr line for 3rd test)",
|
||||
"got_tc_stdout_line(second stdout line for 3rd test)",
|
||||
"got_tc_stderr_line(second stderr line for 3rd test)",
|
||||
"got_tc_end(failed, Testing failed reason)",
|
||||
"got_tp_end(This program failed)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_4);
|
||||
ATF_TEST_CASE_BODY(tps_4)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a, foo\n"
|
||||
"info: b, bar\n"
|
||||
"info: c, baz\n"
|
||||
"tps-count: 2\n"
|
||||
"tp-start: 234.1, first-prog, 3\n"
|
||||
"tc-start: 234.12, first-test\n"
|
||||
"tc-end: 234.23, first-test, passed\n"
|
||||
"tc-start: 234.34, second-test\n"
|
||||
"tc-end: 234.45, second-test, skipped, Testing skipped reason\n"
|
||||
"tc-start: 234.56, third-test\n"
|
||||
"tc-end: 234.67, third-test, failed, Testing failed reason\n"
|
||||
"tp-end: 234.78, first-prog\n"
|
||||
"tp-start: 234.89, second-prog, 3\n"
|
||||
"tc-start: 234.90, first-test\n"
|
||||
"tc-so:first stdout line for 1st test\n"
|
||||
"tc-se:first stderr line for 1st test\n"
|
||||
"tc-so:second stdout line for 1st test\n"
|
||||
"tc-se:second stderr line for 1st test\n"
|
||||
"tc-end: 234.101, first-test, passed\n"
|
||||
"tc-start: 234.112, second-test\n"
|
||||
"tc-so:first stdout line for 2nd test\n"
|
||||
"tc-se:first stderr line for 2nd test\n"
|
||||
"tc-so:second stdout line for 2nd test\n"
|
||||
"tc-se:second stderr line for 2nd test\n"
|
||||
"tc-end: 234.123, second-test, skipped, Testing skipped reason\n"
|
||||
"tc-start: 234.134, third-test\n"
|
||||
"tc-so:first stdout line for 3rd test\n"
|
||||
"tc-se:first stderr line for 3rd test\n"
|
||||
"tc-so:second stdout line for 3rd test\n"
|
||||
"tc-se:second stderr line for 3rd test\n"
|
||||
"tc-end: 234.145, third-test, failed, Testing failed reason\n"
|
||||
"tp-end: 234.156, second-prog, This program failed\n"
|
||||
"info: d, foo\n"
|
||||
"info: e, bar\n"
|
||||
"info: f, baz\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, foo)",
|
||||
"got_info(b, bar)",
|
||||
"got_info(c, baz)",
|
||||
"got_ntps(2)",
|
||||
"got_tp_start(first-prog, 3)",
|
||||
"got_tc_start(first-test)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tc_start(second-test)",
|
||||
"got_tc_end(skipped, Testing skipped reason)",
|
||||
"got_tc_start(third-test)",
|
||||
"got_tc_end(failed, Testing failed reason)",
|
||||
"got_tp_end()",
|
||||
"got_tp_start(second-prog, 3)",
|
||||
"got_tc_start(first-test)",
|
||||
"got_tc_stdout_line(first stdout line for 1st test)",
|
||||
"got_tc_stderr_line(first stderr line for 1st test)",
|
||||
"got_tc_stdout_line(second stdout line for 1st test)",
|
||||
"got_tc_stderr_line(second stderr line for 1st test)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tc_start(second-test)",
|
||||
"got_tc_stdout_line(first stdout line for 2nd test)",
|
||||
"got_tc_stderr_line(first stderr line for 2nd test)",
|
||||
"got_tc_stdout_line(second stdout line for 2nd test)",
|
||||
"got_tc_stderr_line(second stderr line for 2nd test)",
|
||||
"got_tc_end(skipped, Testing skipped reason)",
|
||||
"got_tc_start(third-test)",
|
||||
"got_tc_stdout_line(first stdout line for 3rd test)",
|
||||
"got_tc_stderr_line(first stderr line for 3rd test)",
|
||||
"got_tc_stdout_line(second stdout line for 3rd test)",
|
||||
"got_tc_stderr_line(second stderr line for 3rd test)",
|
||||
"got_tc_end(failed, Testing failed reason)",
|
||||
"got_tp_end(This program failed)",
|
||||
"got_info(d, foo)",
|
||||
"got_info(e, bar)",
|
||||
"got_info(f, baz)",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_5);
|
||||
ATF_TEST_CASE_BODY(tps_5)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"tp-start: 345.123, the-prog, 1\n"
|
||||
"tc-start: 345.134, the-test\n"
|
||||
"tc-so:--- a 2007-11-04 14:00:41.000000000 +0100\n"
|
||||
"tc-so:+++ b 2007-11-04 14:00:48.000000000 +0100\n"
|
||||
"tc-so:@@ -1,7 +1,7 @@\n"
|
||||
"tc-so: This test is meant to simulate a diff.\n"
|
||||
"tc-so: Blank space at beginning of context lines must be preserved.\n"
|
||||
"tc-so: \n"
|
||||
"tc-so:-First original line.\n"
|
||||
"tc-so:-Second original line.\n"
|
||||
"tc-so:+First modified line.\n"
|
||||
"tc-so:+Second modified line.\n"
|
||||
"tc-so: \n"
|
||||
"tc-so: EOF\n"
|
||||
"tc-end: 345.145, the-test, passed\n"
|
||||
"tp-end: 345.156, the-prog\n"
|
||||
;
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
"got_tp_start(the-prog, 1)",
|
||||
"got_tc_start(the-test)",
|
||||
"got_tc_stdout_line(--- a 2007-11-04 14:00:41.000000000 +0100)",
|
||||
"got_tc_stdout_line(+++ b 2007-11-04 14:00:48.000000000 +0100)",
|
||||
"got_tc_stdout_line(@@ -1,7 +1,7 @@)",
|
||||
"got_tc_stdout_line( This test is meant to simulate a diff.)",
|
||||
"got_tc_stdout_line( Blank space at beginning of context lines must be preserved.)",
|
||||
"got_tc_stdout_line( )",
|
||||
"got_tc_stdout_line(-First original line.)",
|
||||
"got_tc_stdout_line(-Second original line.)",
|
||||
"got_tc_stdout_line(+First modified line.)",
|
||||
"got_tc_stdout_line(+Second modified line.)",
|
||||
"got_tc_stdout_line( )",
|
||||
"got_tc_stdout_line( EOF)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tp_end()",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_6);
|
||||
ATF_TEST_CASE_BODY(tps_6)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"tp-start: 321.1, the-prog, 8\n"
|
||||
"tc-start: 321.12, one\n"
|
||||
"tc-end: 321.23, one, expected_death, The reason\n"
|
||||
"tc-start: 321.34, two\n"
|
||||
"tc-end: 321.45, two, expected_exit, This would be an exit\n"
|
||||
"tc-start: 321.56, three\n"
|
||||
"tc-end: 321.67, three, expected_failure, And this a failure\n"
|
||||
"tc-start: 321.78, four\n"
|
||||
"tc-end: 321.89, four, expected_signal, And this a signal\n"
|
||||
"tc-start: 321.90, five\n"
|
||||
"tc-end: 321.101, five, failed, Another reason\n"
|
||||
"tc-start: 321.112, six\n"
|
||||
"tc-end: 321.123, six, passed\n"
|
||||
"tc-start: 321.134, seven\n"
|
||||
"tc-end: 321.145, seven, skipped, Skipping it\n"
|
||||
"tc-start: 321.156, eight\n"
|
||||
"tc-end: 321.167, eight, expected_timeout, Some hang reason\n"
|
||||
"tp-end: 321.178, the-prog\n"
|
||||
;
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
"got_tp_start(the-prog, 8)",
|
||||
"got_tc_start(one)",
|
||||
"got_tc_end(expected_death, The reason)",
|
||||
"got_tc_start(two)",
|
||||
"got_tc_end(expected_exit, This would be an exit)",
|
||||
"got_tc_start(three)",
|
||||
"got_tc_end(expected_failure, And this a failure)",
|
||||
"got_tc_start(four)",
|
||||
"got_tc_end(expected_signal, And this a signal)",
|
||||
"got_tc_start(five)",
|
||||
"got_tc_end(failed, Another reason)",
|
||||
"got_tc_start(six)",
|
||||
"got_tc_end(passed)",
|
||||
"got_tc_start(seven)",
|
||||
"got_tc_end(skipped, Skipping it)",
|
||||
"got_tc_start(eight)",
|
||||
"got_tc_end(expected_timeout, Some hang reason)",
|
||||
"got_tp_end()",
|
||||
"got_eof()",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
const char* exp_errors[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_50);
|
||||
ATF_TEST_CASE_BODY(tps_50)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `foo'; expected tps-count or info field",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_51);
|
||||
ATF_TEST_CASE_BODY(tps_51)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_52);
|
||||
ATF_TEST_CASE_BODY(tps_52)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count:\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected number of test programs",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_53);
|
||||
ATF_TEST_CASE_BODY(tps_53)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"4: Unexpected token `foo'; expected start of test program",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_54);
|
||||
ATF_TEST_CASE_BODY(tps_54)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"foo\n"
|
||||
"tp-start\n"
|
||||
"tp-start:\n"
|
||||
"tp-start: 123\n"
|
||||
"tp-start: 123.\n"
|
||||
"tp-start: 123.456\n"
|
||||
"tp-start: 123.456,\n"
|
||||
"tp-start: 123.456, foo\n"
|
||||
"tp-start: 123.456, foo,\n"
|
||||
"tp-start: 123.456, foo, 0\n"
|
||||
"bar\n"
|
||||
"tp-start: 456.789, foo, 0\n"
|
||||
"tp-end\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end:\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777.\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777.888\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777.888, \n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777.888, bar\n"
|
||||
"tp-start: 777.777, foo, 0\n"
|
||||
"tp-end: 777.888, foo,\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"4: Unexpected token `foo'; expected start of test program",
|
||||
"5: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"6: Unexpected token `<<NEWLINE>>'; expected timestamp",
|
||||
"7: Malformed timestamp value 123",
|
||||
"8: Malformed timestamp value 123.",
|
||||
"9: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"10: Unexpected token `<<NEWLINE>>'; expected test program name",
|
||||
"11: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"12: Unexpected token `<<NEWLINE>>'; expected number of test programs",
|
||||
"14: Unexpected token `bar'; expected end of test program",
|
||||
"16: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"18: Unexpected token `<<NEWLINE>>'; expected timestamp",
|
||||
"20: Malformed timestamp value 777",
|
||||
"22: Malformed timestamp value 777.",
|
||||
"24: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
|
||||
"26: Unexpected token `<<NEWLINE>>'; expected test program name",
|
||||
"28: Test program name used in terminator does not match opening",
|
||||
"30: Empty reason for failed test program",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_55);
|
||||
ATF_TEST_CASE_BODY(tps_55)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"tp-start: 100.200, foo, 1\n"
|
||||
"foo\n"
|
||||
"tc-start\n"
|
||||
"tc-start:\n"
|
||||
"tc-start: 111\n"
|
||||
"tc-start: 111.\n"
|
||||
"tc-start: 111.222\n"
|
||||
"tc-start: 111.222,\n"
|
||||
"tc-start: 111.222, foo\n"
|
||||
"bar\n"
|
||||
"tc-start: 111.333, foo\n"
|
||||
"tc-end\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end:\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.555\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.555, \n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.555, bar\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.555, foo\n"
|
||||
"tc-start: 111.444, foo\n"
|
||||
"tc-end: 111.555, foo,\n"
|
||||
"tp-end: 111.666, foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
"got_tp_start(foo, 1)",
|
||||
NULL
|
||||
};
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_errors[] = {
|
||||
"5: Unexpected token `foo'; expected start of test case",
|
||||
"6: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"7: Unexpected token `<<NEWLINE>>'; expected timestamp",
|
||||
"8: Malformed timestamp value 111",
|
||||
"9: Malformed timestamp value 111.",
|
||||
"10: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"11: Unexpected token `<<NEWLINE>>'; expected test case name",
|
||||
"13: Unexpected token `bar'; expected end of test case or test case's stdout/stderr line",
|
||||
"15: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
"17: Unexpected token `<<NEWLINE>>'; expected timestamp",
|
||||
"19: Malformed timestamp value 111",
|
||||
"21: Malformed timestamp value 111.",
|
||||
"23: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"25: Unexpected token `<<NEWLINE>>'; expected test case name",
|
||||
"27: Test case name used in terminator does not match opening",
|
||||
"29: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"31: Unexpected token `<<NEWLINE>>'; expected expected_{death,exit,failure,signal,timeout}, failed, passed or skipped",
|
||||
"32: Unexpected token `tp-end'; expected start of test case",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_56);
|
||||
ATF_TEST_CASE_BODY(tps_56)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"tp-start: 111.222, foo, 1\n"
|
||||
"tc-start: 111.333, foo\n"
|
||||
"tc-end: 111.444, foo, passe\n"
|
||||
"tc-start: 111.333, foo\n"
|
||||
"tc-end: 111.444, foo, passed,\n"
|
||||
"tc-start: 111.555, bar\n"
|
||||
"tc-end: 111.666, bar, failed\n"
|
||||
"tc-start: 111.555, bar\n"
|
||||
"tc-end: 111.666, bar, failed,\n"
|
||||
"tc-start: 111.555, baz\n"
|
||||
"tc-end: 111.666, baz, skipped\n"
|
||||
"tc-start: 111.555, baz\n"
|
||||
"tc-end: 111.666, baz, skipped,\n"
|
||||
"tp-end: 111.777, foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
"got_tp_start(foo, 1)",
|
||||
"got_tc_start(foo)",
|
||||
NULL
|
||||
};
|
||||
|
||||
// NO_CHECK_STYLE_BEGIN
|
||||
const char* exp_errors[] = {
|
||||
"6: Unexpected token `passe'; expected expected_{death,exit,failure,signal,timeout}, failed, passed or skipped",
|
||||
"8: Unexpected token `,'; expected new line",
|
||||
"10: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"12: Empty reason for failed test case result",
|
||||
"14: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
"16: Empty reason for skipped test case result",
|
||||
"17: Unexpected token `tp-end'; expected start of test case",
|
||||
NULL
|
||||
};
|
||||
// NO_CHECK_STYLE_END
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_57);
|
||||
ATF_TEST_CASE_BODY(tps_57)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 2\n"
|
||||
"tp-start: 111.222, foo, 0\n"
|
||||
"tp-end: 111.333, foo\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(2)",
|
||||
"got_tp_start(foo, 0)",
|
||||
"got_tp_end()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"6: Unexpected token `<<EOF>>'; expected start of test program",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_58);
|
||||
ATF_TEST_CASE_BODY(tps_58)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"tps-count: 1\n"
|
||||
"tp-start: 111.222, foo, 0\n"
|
||||
"tp-end: 111.333, foo\n"
|
||||
"tp-start: 111.444, bar, 0\n"
|
||||
"tp-end: 111.555, bar\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_ntps(1)",
|
||||
"got_tp_start(foo, 0)",
|
||||
"got_tp_end()",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"6: Unexpected token `tp-start'; expected end of stream or info field",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_59);
|
||||
ATF_TEST_CASE_BODY(tps_59)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_60);
|
||||
ATF_TEST_CASE_BODY(tps_60)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info:\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected info property name",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_61);
|
||||
ATF_TEST_CASE_BODY(tps_61)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"3: Unexpected token `<<NEWLINE>>'; expected `,'",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_62);
|
||||
ATF_TEST_CASE_BODY(tps_62)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a,\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, )",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"4: Unexpected token `<<EOF>>'; expected tps-count or info field",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_63);
|
||||
ATF_TEST_CASE_BODY(tps_63)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a, b\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, b)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"4: Unexpected token `<<EOF>>'; expected tps-count or info field",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_64);
|
||||
ATF_TEST_CASE_BODY(tps_64)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a, b\n"
|
||||
"info: a.b.c.def, g\n"
|
||||
"tps-count\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, b)",
|
||||
"got_info(a.b.c.def, g)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"5: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_65);
|
||||
ATF_TEST_CASE_BODY(tps_65)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a, b\n"
|
||||
"tps-count:\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, b)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"4: Unexpected token `<<NEWLINE>>'; expected number of test programs",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(tps_66);
|
||||
ATF_TEST_CASE_BODY(tps_66)
|
||||
{
|
||||
const char* input =
|
||||
"Content-Type: application/X-atf-tps; version=\"3\"\n"
|
||||
"\n"
|
||||
"info: a, b\n"
|
||||
"tps-count: 0\n"
|
||||
"info\n"
|
||||
;
|
||||
|
||||
const char* exp_calls[] = {
|
||||
"got_info(a, b)",
|
||||
"got_ntps(0)",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* exp_errors[] = {
|
||||
"5: Unexpected token `<<NEWLINE>>'; expected `:'",
|
||||
NULL
|
||||
};
|
||||
|
||||
do_parser_test< tps_reader >(input, exp_calls, exp_errors);
|
||||
}
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
ATF_ADD_TEST_CASE(tcs, tps_1);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_2);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_3);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_4);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_5);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_6);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_50);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_51);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_52);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_53);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_54);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_55);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_56);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_57);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_58);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_59);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_60);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_61);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_62);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_63);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_64);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_65);
|
||||
ATF_ADD_TEST_CASE(tcs, tps_66);
|
||||
}
|
||||
|
@ -1,325 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2007 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
|
||||
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "defs.hpp"
|
||||
#include "env.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "requirements.hpp"
|
||||
#include "text.hpp"
|
||||
#include "user.hpp"
|
||||
|
||||
namespace impl = tools;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
static
|
||||
bool
|
||||
has_program(const tools::fs::path& program)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (program.is_absolute()) {
|
||||
found = tools::fs::is_executable(program);
|
||||
} else {
|
||||
if (program.str().find('/') != std::string::npos)
|
||||
throw std::runtime_error("Relative paths are not allowed "
|
||||
"when searching for a program (" +
|
||||
program.str() + ")");
|
||||
|
||||
const std::vector< std::string > dirs = tools::text::split(
|
||||
tools::env::get("PATH"), ":");
|
||||
for (std::vector< std::string >::const_iterator iter = dirs.begin();
|
||||
!found && iter != dirs.end(); iter++) {
|
||||
const tools::fs::path& p = tools::fs::path(*iter) / program;
|
||||
if (tools::fs::is_executable(p))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_arch(const std::string& arches)
|
||||
{
|
||||
const std::vector< std::string > v = tools::text::split(arches, " ");
|
||||
|
||||
for (std::vector< std::string >::const_iterator iter = v.begin();
|
||||
iter != v.end(); iter++) {
|
||||
if ((*iter) == tools::config::get("atf_arch"))
|
||||
return "";
|
||||
}
|
||||
|
||||
if (v.size() == 1)
|
||||
return "Requires the '" + arches + "' architecture";
|
||||
else
|
||||
return "Requires one of the '" + arches + "' architectures";
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_config(const std::string& variables, const vars_map& config)
|
||||
{
|
||||
const std::vector< std::string > v = tools::text::split(variables, " ");
|
||||
for (std::vector< std::string >::const_iterator iter = v.begin();
|
||||
iter != v.end(); iter++) {
|
||||
if (config.find((*iter)) == config.end())
|
||||
return "Required configuration variable '" + (*iter) + "' not "
|
||||
"defined";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_files(const std::string& progs)
|
||||
{
|
||||
const std::vector< std::string > v = tools::text::split(progs, " ");
|
||||
for (std::vector< std::string >::const_iterator iter = v.begin();
|
||||
iter != v.end(); iter++) {
|
||||
const tools::fs::path file(*iter);
|
||||
if (!file.is_absolute())
|
||||
throw std::runtime_error("Relative paths are not allowed when "
|
||||
"checking for a required file (" + file.str() + ")");
|
||||
if (!tools::fs::exists(file))
|
||||
return "Required file '" + file.str() + "' not found";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_machine(const std::string& machines)
|
||||
{
|
||||
const std::vector< std::string > v = tools::text::split(machines, " ");
|
||||
|
||||
for (std::vector< std::string >::const_iterator iter = v.begin();
|
||||
iter != v.end(); iter++) {
|
||||
if ((*iter) == tools::config::get("atf_machine"))
|
||||
return "";
|
||||
}
|
||||
|
||||
if (v.size() == 1)
|
||||
return "Requires the '" + machines + "' machine type";
|
||||
else
|
||||
return "Requires one of the '" + machines + "' machine types";
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
static
|
||||
std::string
|
||||
check_memory_sysctl(const int64_t needed, const char* sysctl_variable)
|
||||
{
|
||||
int64_t available;
|
||||
std::size_t available_length = sizeof(available);
|
||||
if (::sysctlbyname(sysctl_variable, &available, &available_length,
|
||||
NULL, 0) == -1) {
|
||||
const char* e = std::strerror(errno);
|
||||
return "Failed to get sysctl(hw.usermem64) value: " + std::string(e);
|
||||
}
|
||||
|
||||
if (available < needed) {
|
||||
return "Not enough memory; needed " + tools::text::to_string(needed) +
|
||||
", available " + tools::text::to_string(available);
|
||||
} else
|
||||
return "";
|
||||
}
|
||||
# if defined(__APPLE__)
|
||||
static
|
||||
std::string
|
||||
check_memory_darwin(const int64_t needed)
|
||||
{
|
||||
return check_memory_sysctl(needed, "hw.usermem");
|
||||
}
|
||||
# elif defined(__FreeBSD__)
|
||||
static
|
||||
std::string
|
||||
check_memory_freebsd(const int64_t needed)
|
||||
{
|
||||
return check_memory_sysctl(needed, "hw.usermem");
|
||||
}
|
||||
# elif defined(__NetBSD__)
|
||||
static
|
||||
std::string
|
||||
check_memory_netbsd(const int64_t needed)
|
||||
{
|
||||
return check_memory_sysctl(needed, "hw.usermem64");
|
||||
}
|
||||
# else
|
||||
# error "Conditional error"
|
||||
# endif
|
||||
#else
|
||||
static
|
||||
std::string
|
||||
check_memory_unknown(const int64_t needed ATF_DEFS_ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
std::string
|
||||
check_memory(const std::string& raw_memory)
|
||||
{
|
||||
const int64_t needed = tools::text::to_bytes(raw_memory);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
return check_memory_darwin(needed);
|
||||
#elif defined(__FreeBSD__)
|
||||
return check_memory_freebsd(needed);
|
||||
#elif defined(__NetBSD__)
|
||||
return check_memory_netbsd(needed);
|
||||
#else
|
||||
return check_memory_unknown(needed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_progs(const std::string& progs)
|
||||
{
|
||||
const std::vector< std::string > v = tools::text::split(progs, " ");
|
||||
for (std::vector< std::string >::const_iterator iter = v.begin();
|
||||
iter != v.end(); iter++) {
|
||||
if (!has_program(tools::fs::path(*iter)))
|
||||
return "Required program '" + (*iter) + "' not found in the PATH";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
check_user(const std::string& user, const vars_map& config)
|
||||
{
|
||||
if (user == "root") {
|
||||
if (!tools::user::is_root())
|
||||
return "Requires root privileges";
|
||||
else
|
||||
return "";
|
||||
} else if (user == "unprivileged") {
|
||||
if (tools::user::is_root()) {
|
||||
const vars_map::const_iterator iter = config.find(
|
||||
"unprivileged-user");
|
||||
if (iter == config.end())
|
||||
return "Requires an unprivileged user and the "
|
||||
"'unprivileged-user' configuration variable is not set";
|
||||
else {
|
||||
const std::string& unprivileged_user = (*iter).second;
|
||||
try {
|
||||
(void)tools::user::get_user_ids(unprivileged_user);
|
||||
return "";
|
||||
} catch (const std::runtime_error& e) {
|
||||
return "Failed to get information for user " +
|
||||
unprivileged_user;
|
||||
}
|
||||
}
|
||||
} else
|
||||
return "";
|
||||
} else
|
||||
throw std::runtime_error("Invalid value '" + user + "' for property "
|
||||
"require.user");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::string
|
||||
impl::check_requirements(const vars_map& metadata,
|
||||
const vars_map& config)
|
||||
{
|
||||
std::string failure_reason = "";
|
||||
|
||||
for (vars_map::const_iterator iter = metadata.begin();
|
||||
failure_reason.empty() && iter != metadata.end(); iter++) {
|
||||
const std::string& name = (*iter).first;
|
||||
const std::string& value = (*iter).second;
|
||||
assert(!value.empty()); // Enforced by application/X-atf-tp parser.
|
||||
|
||||
if (name == "require.arch")
|
||||
failure_reason = check_arch(value);
|
||||
else if (name == "require.config")
|
||||
failure_reason = check_config(value, config);
|
||||
else if (name == "require.files")
|
||||
failure_reason = check_files(value);
|
||||
else if (name == "require.machine")
|
||||
failure_reason = check_machine(value);
|
||||
else if (name == "require.memory")
|
||||
failure_reason = check_memory(value);
|
||||
else if (name == "require.progs")
|
||||
failure_reason = check_progs(value);
|
||||
else if (name == "require.user")
|
||||
failure_reason = check_user(value, config);
|
||||
else {
|
||||
// Unknown require.* properties are forbidden by the
|
||||
// application/X-atf-tp parser.
|
||||
assert(failure_reason.find("require.") != 0);
|
||||
}
|
||||
}
|
||||
|
||||
return failure_reason;
|
||||
}
|
||||
|
||||
std::pair< int, int >
|
||||
impl::get_required_user(const vars_map& metadata,
|
||||
const vars_map& config)
|
||||
{
|
||||
const vars_map::const_iterator user = metadata.find(
|
||||
"require.user");
|
||||
if (user == metadata.end())
|
||||
return std::make_pair(-1, -1);
|
||||
|
||||
if ((*user).second == "unprivileged") {
|
||||
if (tools::user::is_root()) {
|
||||
const vars_map::const_iterator iter = config.find(
|
||||
"unprivileged-user");
|
||||
try {
|
||||
return tools::user::get_user_ids((*iter).second);
|
||||
} catch (const std::exception& e) {
|
||||
std::abort(); // This has been validated by check_user.
|
||||
}
|
||||
} else {
|
||||
return std::make_pair(-1, -1);
|
||||
}
|
||||
} else
|
||||
return std::make_pair(-1, -1);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2010 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(TOOLS_REQUIREMENTS_HPP)
|
||||
#define TOOLS_REQUIREMENTS_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace tools {
|
||||
|
||||
std::string check_requirements(const std::map< std::string, std::string >&,
|
||||
const std::map< std::string, std::string >&);
|
||||
std::pair< int, int > get_required_user(
|
||||
const std::map< std::string, std::string >&,
|
||||
const std::map< std::string, std::string >&);
|
||||
|
||||
} // namespace tools
|
||||
|
||||
#endif // !defined(TOOLS_REQUIREMENTS_HPP)
|
@ -1,400 +0,0 @@
|
||||
//
|
||||
// Automated Testing Framework (atf)
|
||||
//
|
||||
// Copyright (c) 2010 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++.hpp>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "requirements.hpp"
|
||||
#include "text.hpp"
|
||||
#include "user.hpp"
|
||||
|
||||
namespace impl = tools;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Auxiliary functions.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map< std::string, std::string > vars_map;
|
||||
|
||||
const vars_map no_config;
|
||||
|
||||
void
|
||||
do_check(const std::string& expected, const vars_map& metadata,
|
||||
const vars_map& config = no_config)
|
||||
{
|
||||
const std::string actual = impl::check_requirements(metadata, config);
|
||||
if (!tools::text::match(actual, expected))
|
||||
ATF_FAIL("Requirements failure reason \"" + actual + "\" does not "
|
||||
"match \"" + expected + "\"");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.arch metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(require_arch_one_ok);
|
||||
ATF_TEST_CASE_HEAD(require_arch_one_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_arch_one_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.arch"] = tools::config::get("atf_arch");
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_arch_one_fail);
|
||||
ATF_TEST_CASE_HEAD(require_arch_one_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_arch_one_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.arch"] = "__fake_arch__";
|
||||
do_check("Requires the '__fake_arch__' architecture", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_arch_many_ok);
|
||||
ATF_TEST_CASE_HEAD(require_arch_many_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_arch_many_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.arch"] = "__foo__ " + tools::config::get("atf_arch") +
|
||||
" __bar__";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_arch_many_fail);
|
||||
ATF_TEST_CASE_HEAD(require_arch_many_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_arch_many_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.arch"] = "__foo__ __bar__ __baz__";
|
||||
do_check("Requires one of the '__foo__ __bar__ __baz__' architectures",
|
||||
metadata);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.config metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(require_config_one_ok);
|
||||
ATF_TEST_CASE_HEAD(require_config_one_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_config_one_ok) {
|
||||
vars_map metadata, config;
|
||||
metadata["require.config"] = "var1";
|
||||
config["var1"] = "some-value";
|
||||
do_check("", metadata, config);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_config_one_fail);
|
||||
ATF_TEST_CASE_HEAD(require_config_one_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_config_one_fail) {
|
||||
vars_map metadata, config;
|
||||
metadata["require.config"] = "var1";
|
||||
do_check("Required configuration variable 'var1' not defined", metadata,
|
||||
config);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_config_many_ok);
|
||||
ATF_TEST_CASE_HEAD(require_config_many_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_config_many_ok) {
|
||||
vars_map metadata, config;
|
||||
metadata["require.config"] = "var1 var2 var3";
|
||||
config["var1"] = "first-value";
|
||||
config["var2"] = "second-value";
|
||||
config["var3"] = "third-value";
|
||||
do_check("", metadata, config);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_config_many_fail);
|
||||
ATF_TEST_CASE_HEAD(require_config_many_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_config_many_fail) {
|
||||
vars_map metadata, config;
|
||||
metadata["require.config"] = "var1 var2 var3";
|
||||
config["var1"] = "first-value";
|
||||
config["var3"] = "third-value";
|
||||
do_check("Required configuration variable 'var2' not defined", metadata,
|
||||
config);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.files metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_ok);
|
||||
ATF_TEST_CASE_BODY(require_files_one_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/bin/ls";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_missing);
|
||||
ATF_TEST_CASE_BODY(require_files_one_missing) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/non-existent/foo";
|
||||
do_check("Required file '/non-existent/foo' not found", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_one_fail);
|
||||
ATF_TEST_CASE_BODY(require_files_one_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/bin/cp this-is-relative";
|
||||
ATF_REQUIRE_THROW_RE(std::runtime_error, "Relative.*(this-is-relative)",
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_ok);
|
||||
ATF_TEST_CASE_BODY(require_files_many_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/bin/ls /bin/cp";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_missing);
|
||||
ATF_TEST_CASE_BODY(require_files_many_missing) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/bin/ls /non-existent/bar /bin/cp";
|
||||
do_check("Required file '/non-existent/bar' not found", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_files_many_fail);
|
||||
ATF_TEST_CASE_BODY(require_files_many_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.files"] = "/bin/cp also-relative";
|
||||
ATF_REQUIRE_THROW_RE(std::runtime_error, "Relative.*(also-relative)",
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.machine metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(require_machine_one_ok);
|
||||
ATF_TEST_CASE_HEAD(require_machine_one_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_machine_one_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.machine"] = tools::config::get("atf_machine");
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_machine_one_fail);
|
||||
ATF_TEST_CASE_HEAD(require_machine_one_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_machine_one_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.machine"] = "__fake_machine__";
|
||||
do_check("Requires the '__fake_machine__' machine type", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_machine_many_ok);
|
||||
ATF_TEST_CASE_HEAD(require_machine_many_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_machine_many_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.machine"] = "__foo__ " +
|
||||
tools::config::get("atf_machine") + " __bar__";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_machine_many_fail);
|
||||
ATF_TEST_CASE_HEAD(require_machine_many_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_machine_many_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.machine"] = "__foo__ __bar__ __baz__";
|
||||
do_check("Requires one of the '__foo__ __bar__ __baz__' machine types",
|
||||
metadata);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.memory metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_memory_ok);
|
||||
ATF_TEST_CASE_BODY(require_memory_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.memory"] = "1m";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_memory_not_enough);
|
||||
ATF_TEST_CASE_BODY(require_memory_not_enough) {
|
||||
vars_map metadata;
|
||||
metadata["require.memory"] = "128t";
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
do_check("Not enough memory; needed 140737488355328, available [0-9]*",
|
||||
metadata);
|
||||
#else
|
||||
skip("Don't know how to check for the amount of physical memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
ATF_TEST_CASE_WITHOUT_HEAD(require_memory_fail);
|
||||
ATF_TEST_CASE_BODY(require_memory_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.memory"] = "foo";
|
||||
ATF_REQUIRE_THROW(std::runtime_error,
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.progs metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(require_progs_one_ok);
|
||||
ATF_TEST_CASE_HEAD(require_progs_one_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_one_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "cp";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs_one_missing);
|
||||
ATF_TEST_CASE_HEAD(require_progs_one_missing) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_one_missing) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "cp __non-existent__";
|
||||
do_check("Required program '__non-existent__' not found in the PATH",
|
||||
metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs_one_fail);
|
||||
ATF_TEST_CASE_HEAD(require_progs_one_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_one_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "bin/cp";
|
||||
ATF_REQUIRE_THROW(std::runtime_error,
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs_many_ok);
|
||||
ATF_TEST_CASE_HEAD(require_progs_many_ok) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_many_ok) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "cp ls mv";
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs_many_missing);
|
||||
ATF_TEST_CASE_HEAD(require_progs_many_missing) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_many_missing) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "mv ls __foo__ cp";
|
||||
do_check("Required program '__foo__' not found in the PATH", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_progs_many_fail);
|
||||
ATF_TEST_CASE_HEAD(require_progs_many_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_progs_many_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.progs"] = "ls cp ../bin/cp";
|
||||
ATF_REQUIRE_THROW(std::runtime_error,
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Tests for the require.user metadata property.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_TEST_CASE(require_user_root);
|
||||
ATF_TEST_CASE_HEAD(require_user_root) {}
|
||||
ATF_TEST_CASE_BODY(require_user_root) {
|
||||
vars_map metadata;
|
||||
metadata["require.user"] = "root";
|
||||
if (tools::user::is_root())
|
||||
do_check("", metadata);
|
||||
else
|
||||
do_check("Requires root privileges", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_user_unprivileged);
|
||||
ATF_TEST_CASE_HEAD(require_user_unprivileged) {}
|
||||
ATF_TEST_CASE_BODY(require_user_unprivileged) {
|
||||
vars_map metadata;
|
||||
metadata["require.user"] = "unprivileged";
|
||||
if (tools::user::is_root())
|
||||
do_check("Requires an unprivileged user and the 'unprivileged-user' "
|
||||
"configuration variable is not set", metadata);
|
||||
else
|
||||
do_check("", metadata);
|
||||
}
|
||||
|
||||
ATF_TEST_CASE(require_user_fail);
|
||||
ATF_TEST_CASE_HEAD(require_user_fail) {}
|
||||
ATF_TEST_CASE_BODY(require_user_fail) {
|
||||
vars_map metadata;
|
||||
metadata["require.user"] = "nobody";
|
||||
ATF_REQUIRE_THROW(std::runtime_error,
|
||||
impl::check_requirements(metadata, no_config));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Main.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
ATF_INIT_TEST_CASES(tcs)
|
||||
{
|
||||
// Add test cases for require.arch.
|
||||
ATF_ADD_TEST_CASE(tcs, require_arch_one_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_arch_one_fail);
|
||||
ATF_ADD_TEST_CASE(tcs, require_arch_many_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_arch_many_fail);
|
||||
|
||||
// Add test cases for require.config.
|
||||
ATF_ADD_TEST_CASE(tcs, require_config_one_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_config_one_fail);
|
||||
ATF_ADD_TEST_CASE(tcs, require_config_many_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_config_many_fail);
|
||||
|
||||
// Add test cases for require.files.
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_one_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_one_missing);
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_one_fail);
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_many_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_many_missing);
|
||||
ATF_ADD_TEST_CASE(tcs, require_files_many_fail);
|
||||
|
||||
// Add test cases for require.machine.
|
||||
ATF_ADD_TEST_CASE(tcs, require_machine_one_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_machine_one_fail);
|
||||
ATF_ADD_TEST_CASE(tcs, require_machine_many_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_machine_many_fail);
|
||||
|
||||
// Add test cases for require.memory.
|
||||
ATF_ADD_TEST_CASE(tcs, require_memory_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_memory_not_enough);
|
||||
ATF_ADD_TEST_CASE(tcs, require_memory_fail);
|
||||
|
||||
// Add test cases for require.progs.
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_one_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_one_missing);
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_one_fail);
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_many_ok);
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_many_missing);
|
||||
ATF_ADD_TEST_CASE(tcs, require_progs_many_fail);
|
||||
|
||||
// Add test cases for require.user.
|
||||
ATF_ADD_TEST_CASE(tcs, require_user_root);
|
||||
ATF_ADD_TEST_CASE(tcs, require_user_unprivileged);
|
||||
ATF_ADD_TEST_CASE(tcs, require_user_fail);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#
|
||||
# Definition of custom hooks for atf-run.
|
||||
#
|
||||
# Uncomment any hooks that you want to override and add your own code
|
||||
# to them. Some sample calls are included in them. Be very careful
|
||||
# with what you print from here.
|
||||
#
|
||||
# See atf-run(1) for more details.
|
||||
#
|
||||
|
||||
#info_start_hook()
|
||||
#{
|
||||
# default_info_start_hook "${@}"
|
||||
#
|
||||
# atf_tps_writer_info "extra.info" "An example"
|
||||
#}
|
||||
|
||||
#info_end_hook()
|
||||
#{
|
||||
# default_info_end_hook "${@}"
|
||||
#
|
||||
# atf_tps_writer_info "extra.info" "An example"
|
||||
#}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user