Import ATF version 0,16

Discussed with: gibbs, gnn, keramida, mdf, mlaier,
Discussed with: Garrett Cooper
This commit is contained in:
Marcel Moolenaar 2012-09-04 23:07:32 +00:00
commit 679bf1899d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/atf/atf-0.16/; revision=240116; tag=vendor/atf/atf-0.16
302 changed files with 113515 additions and 0 deletions

30
AUTHORS Normal file
View File

@ -0,0 +1,30 @@
Authors and contributors Automated Testing Framework
===========================================================================
* Julio Merino <jmmv@NetBSD.org>
Main developer. He started the work on this project when he took part in
the Google Summer of Code 2007 program as a student.
* Martin Husemann <martin@NetBSD.org>
Mentored this project during its development as part of the Google Summer
of Code 2007 program.
* Lukasz Strzygowski <qx89l4@gmail.com>
Participant of the Google Summer of Code 2008 program. Mentored by The
NetBSD Foundation, he worked on the atfify NetBSD-SoC project and, as a
side-effect, he contributed to the ATF source code. He developed the
initial version of the atf-check utility and started the addition of the
ATF_REQUIRE family of macros in the C interface.
* Paul Goyette <pgoyette@NetBSD.org>
Implemented timestamping of test programs and test cases so that
atf-report can provide timings for their execution.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

12
Atffile Normal file
View File

@ -0,0 +1,12 @@
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: atf-config*
tp-glob: atf-report*
tp-glob: atf-run*

100
COPYING Normal file
View File

@ -0,0 +1,100 @@
Redistribution terms Automated Testing Framework
===========================================================================
License
*******
Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 The NetBSD Foundation, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright 2011, 2012 Google 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:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Google Inc. nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
Relicensed code
***************
The following code snippets have been taken from other projects. Even
though they were not originally licensed under the terms above, the
original authors have agreed to relicense their work so that this project
can be distributed under a single license. This section is put here just to
clarify this fact.
* configure.ac, Makefile.am: The original versions were derived from the
ones in the XML Catalog Manager project, version 2.2.
Author: Julio Merino <jmmv@users.sourceforge.net>
* atf-c/ui.c: The format_paragraph and format_text functions were
derived form the ones in the Monotone project, revision
3a0982da308228d796df35f98d787c5cff2bb5b6.
Author: Julio Merino <jmmv@NetBSD.org>
* atf-c++/detail/io.hpp, atf-c++/detail/io.cpp, atf-c++/detail/io_test.cpp:
These files were derived from the file_handle, systembuf, pipe and pistream
classes and tests found in the Boost.Process library.
Author: Julio Merino <jmmv84@gmail.com>
* admin/check-style.sh, admin/check-style-common.awk,
admin/check-style-cpp.awk, admin/check-style-shell.awk: These files,
except the first one, were first implemented in the Buildtool project.
They were later adapted to be part of Boost.Process and, during that
process, the shell script was created.
Author: Julio Merino <jmmv84@gmail.com>
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

232
INSTALL Normal file
View File

@ -0,0 +1,232 @@
Installation instructions Automated Testing Framework
===========================================================================
Introduction
************
ATF uses the GNU Automake, GNU Autoconf and GNU Libtool utilities as its
build system. These are used only when compiling the application from the
source code package. If you want to install ATF from a binary package, you
do not need to read this document.
For the impatient:
$ ./configure
$ make
Gain root privileges
# make install
Drop root privileges
$ make installcheck
Or alternatively, install as a regular user into your home directory:
$ ./configure --prefix ~/local
$ make
$ make install
$ make installcheck
Dependencies
************
To build and use ATF successfully you need:
* A standards-compliant C/C++ complier. For example, GNU GCC 2.95 will not
work.
* A POSIX shell interpreter.
* A make(1) utility.
If you are building ATF from the code on the repository, you will also need
the following tools. The versions listed here are the ones used to build
the files bundled in the last formal release, but these are not strictly
required. Newer ones will most likely work and, maybe, some slightly older
ones:
* GNU autoconf 2.68
* GNU automake 1.11.3
* GNU libtool 2.4.2
Regenerating the build system
*****************************
If you are building ATF from code extracted from the repository, you must
first regenerate the files used by the build system. You will also need to
do this if you modify configure.ac, Makefile.am or any of the other build
system files. To do this, simply run:
$ autoreconf -i -s
For formal releases, no extra steps are needed.
General build procedure
***********************
To build and install the source package, you must follow these steps:
1. Configure the sources to adapt to your operating system. This is done
using the 'configure' script located on the sources' top directory,
and it is usually invoked without arguments unless you want to change
the installation prefix. More details on this procedure are given on a
later section.
2. Build the sources to generate the binaries and scripts. Simply run
'make' on the sources' top directory after configuring them. No
problems should arise.
3. Install the program by running 'make install'. You may need to become
root to issue this step.
4. Issue any manual installation steps that may be required. These are
described later in their own section.
5. Check that the installed programs work by running 'make installcheck'.
You do not need to be root to do this, even though some checks will not
be run otherwise.
Configuration flags
*******************
The most common, standard flags given to 'configure' are:
* --prefix=directory
Possible values: Any path
Default: /usr/local
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.
The following environment variables are specific to ATF's 'configure'
script:
* ATF_BUILD_CC
Possible values: empty, a absolute or relative path to a C compiler.
Default: the value of CC as detected by the configure script.
Specifies the C compiler that ATF will use at run time whenever the
build-time-specific checks are used.
* ATF_BUILD_CFLAGS
Possible values: empty, a list of valid C compiler flags.
Default: the value of CFLAGS as detected by the configure script.
Specifies the C compiler flags that ATF will use at run time whenever the
build-time-specific checks are used.
* ATF_BUILD_CPP
Possible values: empty, a absolute or relative path to a C/C++
preprocessor.
Default: the value of CPP as detected by the configure script.
Specifies the C/C++ preprocessor that ATF will use at run time whenever
the build-time-specific checks are used.
* ATF_BUILD_CPPFLAGS
Possible values: empty, a list of valid C/C++ preprocessor flags.
Default: the value of CPPFLAGS as detected by the configure script.
Specifies the C/C++ preprocessor flags that ATF will use at run time
whenever the build-time-specific checks are used.
* ATF_BUILD_CXX
Possible values: empty, a absolute or relative path to a C++ compiler.
Default: the value of CXX as detected by the configure script.
Specifies the C++ compiler that ATF will use at run time whenever the
build-time-specific checks are used.
* ATF_BUILD_CXXFLAGS
Possible values: empty, a list of valid C++ compiler flags.
Default: the value of CXXFLAGS as detected by the configure 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.
Specifies the POSIX shell interpreter that ATF will use at run time to
execute its scripts and the test programs written using the atf-sh
library. If empty, the configure script will try to find a suitable
interpreter for you.
* ATF_WORKDIR
Possible values: empty, an absolute path.
Default: /tmp or /var/tmp, depending on availability.
Specifies the directory that ATF will use to place its temporary files
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
Possible values: yes, no
Default: 'yes' in Git HEAD builds; 'no' in formal releases.
Enables several features useful for development, such as the inclusion
of debugging symbols in all objects or the enforcement of compilation
warnings.
The compiler will be executed with an exhaustive collection of warning
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

18
Kyuafile Normal file
View File

@ -0,0 +1,18 @@
syntax("kyuafile", 1)
test_suite("atf")
include("atf-c/Kyuafile")
include("atf-c++/Kyuafile")
include("atf-sh/Kyuafile")
include("test-programs/Kyuafile")
if fs.exists("atf-config/Kyuafile") then
include("atf-config/Kyuafile")
end
if fs.exists("atf-report/Kyuafile") then
include("atf-report/Kyuafile")
end
if fs.exists("atf-run/Kyuafile") then
include("atf-run/Kyuafile")
end

151
Makefile.am Normal file
View File

@ -0,0 +1,151 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
atf_aclocal_DATA =
BUILT_SOURCES =
CLEANFILES =
EXTRA_DIST =
bin_PROGRAMS =
dist_man_MANS =
include_HEADERS =
lib_LTLIBRARIES =
libexec_PROGRAMS =
man_MANS =
noinst_DATA =
noinst_LTLIBRARIES =
INSTALLCHECK_TARGETS =
PHONY_TARGETS =
ACLOCAL_AMFLAGS = -I m4
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-tools
include admin/Makefile.am.inc
include atf-c/Makefile.am.inc
include atf-c++/Makefile.am.inc
include atf-sh/Makefile.am.inc
include bootstrap/Makefile.am.inc
include doc/Makefile.am.inc
include test-programs/Makefile.am.inc
if ENABLE_TOOLS
include atf-report/Makefile.am.inc
include atf-config/Makefile.am.inc
include atf-run/Makefile.am.inc
include atf-version/Makefile.am.inc
endif
#
# Top-level distfile documents.
#
doc_DATA = AUTHORS COPYING NEWS README
noinst_DATA += INSTALL README
EXTRA_DIST += $(doc_DATA) INSTALL README
#
# Supporting logic to run our custom testsuite.
#
TESTS_ENVIRONMENT = PATH=$(prefix)/bin:$${PATH} \
PKG_CONFIG_PATH=$(prefix)/lib/pkgconfig
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
installcheck-kyua:
cd $(pkgtestsdir) && $(TESTS_ENVIRONMENT) $(KYUA) test
endif
installcheck-targets: $(INSTALLCHECK_TARGETS)
pkgtests_DATA = Kyuafile
if ENABLE_TOOLS
pkgtests_DATA += Atffile
endif
EXTRA_DIST += $(pkgtests_DATA)
BUILD_SH_TP = \
echo "Creating $${dst}"; \
echo "\#! $(bindir)/atf-sh" >$${dst}; \
cat $${src} >>$${dst}; \
chmod +x $${dst}
#
# Custom targets.
#
dist-hook: 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
PHONY_TARGETS += release
release:
$(SH) $(srcdir)/admin/release.sh $(PACKAGE_VERSION) $(DIST_ARCHIVES)
PHONY_TARGETS += release-test
release-test:
$(SH) $(srcdir)/admin/release-test.sh $(DIST_ARCHIVES)
.PHONY: $(PHONY_TARGETS)
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8

5264
Makefile.in Normal file

File diff suppressed because it is too large Load Diff

570
NEWS Normal file
View File

@ -0,0 +1,570 @@
Major changes between releases Automated Testing Framework
===========================================================================
Changes in version 0.16
***********************
Experimental version released on July 10th, 2012.
* Added a --enable-tools flag to configure to request the build of the
deprecated ATF tools, whose build is now disabled by default. In order
to continue running tests, you should migrate to Kyua instead of enabling
the build of the deprecated tools. The kyua-atf-compat package provides
transitional compatibility versions of atf-run and atf-report built on
top of Kyua.
* Tweaked the ATF_TEST_CASE macro of atf-c++ so that the compiler can
detect defined but unused test cases.
* PR bin/45859: Fixed some XSLT bugs that resulted in the tc-time and
tp-time XML tags leaking into the generated HTML file. Also improved
the CSS file slightly to correct alignment and color issues with the
timestamps column.
* Optimized atf-c++/macros.hpp so that GNU G++ consumes less memory during
compilation with GNU G++.
* Flipped the default to building shared libraries for atf-c and atf-c++,
and started versioning them. As a side-effect, this removes the
--enable-unstable-shared flag from configure that appears to not work any
more (under NetBSD). Additionally, some distributions require the use of
shared libraries for proper dependency tracking (e.g. Fedora), so it is
better if we do the right versioning upstream.
* Project hosting moved from an adhoc solution (custom web site and
Monotone repository) to Google Code (standard wiki and Git). ATF now
lives in a subcomponent of the Kyua project.
Changes in version 0.15
***********************
Experimental version released on January 16th, 2012.
* Respect stdin in atf-check. The previous release silenced stdin for any
processes spawned by atf, not only test programs, which caused breakage
in tests that pipe data through atf-check.
* Performance improvements to atf-sh.
* Enabled detection of unused parameters and variables in the code and
fixed all warnings.
* Changed the behavior of "developer mode". Compiler warnings are now
enabled unconditionally regardless of whether we are in developer mode or
not; developer mode is now only used to perform strict warning checks and
to enable assertions. Additionally, developer mode is now only
automatically enabled when building from the repository, not for formal
releases.
* Added new Autoconf M4 macros (ATF_ARG_WITH, ATF_CHECK_C and
ATF_CHECK_CXX) to provide a consistent way of defining a --with-arg flag
in configure scripts and detecting the presence of any of the ATF
bindings. Note that ATF_CHECK_SH was already introduced in 0.14, but it
has now been modified to also honor --with-atf if instantiated.
* Added timing support to atf-run / atf-report.
* Added support for a 'require.memory' property, to specify the minimum
amount of physical memory needed by the test case to yield valid results.
* PR bin/45690: Force an ISO-8859-1 encoding in the XML files generated by
atf-report so that invalid data in the output of test cases does not
mangle our report.
Changes in version 0.14
***********************
Experimental version released on June 14th, 2011.
* Added a pkg-config file for atf-sh and an aclocal file to ease the
detection of atf-sh from autoconf scripts.
* Made the default test case body defined by atf_sh fail. This is to
ensure that test cases are properly defined in test programs and helps
in catching typos in the names of the body functions.
* PR bin/44882: Made atf-run connect the stdin of test cases to /dev/zero.
This provides more consistent results with "normal" execution (in
particular, when tests are executed detached from a terminal).
* Made atf-run hardcode TZ=UTC for test cases. It used to undefine TZ, but
that does not take into account that libc determines the current timezone
from a configuration file.
* All test programs will now print a warning when they are not run through
atf-run(1) stating that this is unsupported and may deliver incorrect
results.
* Added support for the 'require.files' test-case property. This allows
test cases to specify installed files that must be present for the test
case to run.
Changes in version 0.13
***********************
Experimental version released on March 31st, 2011.
This is the first release after the creation of the Kyua project, a more
modular and reliable replacement for ATF. From now on, ATF will change to
accomodate the transition to this new codebase, but ATF will still continue
to see development in the short/medium term. Check out the project page at
http://code.google.com/p/kyua/ for more details.
The changes in this release are:
* Added support to run the tests with the Kyua runtime engine (kyua-cli), a
new package that aims to replace atf-run and atf-report. The ATF tests
can be run with the new system by issuing a 'make installcheck-kyua' from
the top-level directory of the project (assuming the 'kyua' binary is
available during the configuration stage of ATF).
* atf-run and atf-report are now in maintenance mode (but *not* deprecated
yet!). Kyua already implements a new, much more reliable runtime engine
that provides similar features to these tools. That said, it is not
complete yet so all development efforts should go towards it.
* If GDB is installed, atf-run dumps the stack trace of crashing test
programs in an attempt to aid debugging. Contributed by Antti Kantee.
* Reverted default timeout change in previous release and reset its value
to 5 minutes. This was causing several issues, specially when running
the existing NetBSD test suite in qemu.
* Fixed the 'match' output checker in atf-check to properly validate the
last line of a file even if it does not have a newline.
* Added the ATF_REQUIRE_IN and ATF_REQUIRE_NOT_IN macros to atf-c++ to
check for the presence (or lack thereof) of an element in a collection.
* PR bin/44176: Fixed a race condition in atf-run that would crash atf-run
when the cleanup of a test case triggered asynchronous modifications to
its work directory (e.g. killing a daemon process that cleans up a pid
file in the work directory).
* PR bin/44301: Fixed the sample XSLT file to report bogus test programs
instead of just listing them as having 0 test cases.
Changes in version 0.12
***********************
Experimental version released on November 7th, 2010.
* Added the ATF_REQUIRE_THROW_RE to atf-c++, which is the same as
ATF_REQUIRE_THROW but allows checking for the validity of the exception's
error message by means of a regular expression.
* Added the ATF_REQUIRE_MATCH to atf-c++, which allows checking for a
regular expression match in a string.
* Changed the default timeout for test cases from 5 minutes to 30 seconds.
30 seconds is long enough for virtually all tests to complete, and 5
minutes is a way too long pause in a test suite where a single test case
stalls.
* Deprecated the use.fs property. While this seemed like a good idea in
the first place to impose more control on what test cases can do, it
turns out to be bad. First, use.fs=false prevents bogus test cases
from dumping core so after-the-fact debugging is harder. Second,
supporting use.fs adds a lot of unnecessary complexity. atf-run will
now ignore any value provided to use.fs and will allow test cases to
freely access the file system if they wish to.
* Added the atf_tc_get_config_var_as_{bool,long}{,_wd} functions to the atf-c
library. The 'text' module became private in 0.11 but was being used
externally to simplify the parsing of configuration variables.
* Made atf-run recognize the 'unprivileged-user' configuration variable
and automatically drop root privileges when a test case sets
require.user=unprivileged. Note that this is, by no means, done for
security purposes; this is just for user convenience; tests should, in
general, not be blindly run as root in the first place.
Changes in version 0.11
***********************
Experimental version released on October 20th, 2010.
* The ATF_CHECK* macros in atf-c++ were renamed to ATF_REQUIRE* to match
their counterparts in atf-c.
* Clearly separated the modules in atf-c that are supposed to be public
from those that are implementation details. The header files for the
internal modules are not installed any more.
* Made the atf-check tool private. It is only required by atf-sh and being
public has the danger of causing confusion. Also, making it private
simplifies the public API of atf.
* Changed atf-sh to enable per-command error checking (set -e) by default.
This catches many cases in which a test case is broken but it is not
reported as such because execution continues.
* Fixed the XSTL and CSS stylesheets to support expected failures.
Changes in version 0.10
***********************
Experimental version released on July 2nd, 2010.
Miscellaneous features
* Added expected failures support to test cases and atf-run. These
include, for example, expected clean exits, expected reception of fatal
signals, expected timeouts and expected errors in condition checks.
These statuses can be used to denote test cases that are known to fail
due to a bug in the code they are testing. atf-report reports these
tests separately but they do not count towards the failed test cases
amount.
* Added the ATF_CHECK_ERRNO and ATF_REQUIRE_ERRNO to the C library to
allow easy checking of call failures that update errno.
* Added the has.cleanup meta-data property to test caes that specifies
whether the test case has a cleanup routine or not; its value is
automatically set. This property is read by atf-run to know if it has to
run the cleanup routine; skipping this run for every test case
significantly speeds up the run time of test suites.
* Reversed the order of the ATF_CHECK_THROW macro in the C++ binding to
take the expected exception as the first argument and the statement to
execute as the second argument.
Changes in atf-check
* Changed atf-check to support negating the status and output checks by
prefixing them with not- and added support to specify multiple checkers
for stdout and stderr, not only one.
* Added the match output checker to atf-check to look for regular
expressions in the stdout and stderr of commands.
* Modified the exit checks in atf-check to support checking for the
reception of signals.
Code simplifications and cleanups
* Removed usage messages from test programs to simplify the
implementation of every binding by a significant amount. They just now
refer the user to the appropriate manual page and do not attempt to wrap
lines on terminal boundaries. Test programs are not supposed to be run
by users directly so this minor interface regression is not important.
* Removed the atf-format internal utility, which is unused after the
change documented above.
* Removed the atf-cleanup internal utility. It has been unused since the
test case isolation was moved to atf-run in 0.8
* Splitted the Makefile.am into smaller files for easier maintenance and
dropped the use of M4. Only affects users building from the repository
sources.
* Intermixed tests with the source files in the source tree to provide
them more visibility and easier access. The tests directory is gone from
the source tree and tests are now suffixed by _test, not prefixed by t_.
* Simplifications to the atf-c library: removed the io, tcr and ui
modules as they had become unnecessary after all simplifications
introduced since the 0.8 release.
* Removed the application/X-atf-tcr format introduced in 0.8 release.
Tests now print a much simplified format that is easy to parse and nicer
to read by end users. As a side effect, the default for test cases is
now to print their results to stdout unless otherwise stated by providing
the -r flag.
* Removed XML distribution documents and replaced them with plain-text
documents. They provided little value and introduced a lot of complexity
to the build system.
* Simplified the output of atf-version by not attempting to print a
revision number when building form a distfile. Makes the build system
easier to maintain.
Changes in version 0.9
**********************
Experimental version released on June 3rd, 2010.
* Added atf-sh, an interpreter to process test programs written using
the shell API. This is not really a shell interpreter by itself though:
it is just a wrapper around the system shell that eases the loading of
the necessary ATF libraries.
* Removed atf-compile in favour of atf-sh.
* Added the use.fs metadata property to test case, which is used to
specify which test cases require file system access. This is to
highlight dependencies on external resources more clearly and to speed up
the execution of test suites by skipping the creation of many unnecessary
work directories.
* Fixed test programs to get a sane default value for their source
directory. This means that it should not be necessary any more to pass
-s when running test programs that do not live in the current directory.
* Defining test case headers became optional. This is trivial to achieve
in shell-based tests but a bit ugly in C and C++. In C, use the new
ATF_TC_WITHOUT_HEAD macro to define the test case, and in C++ use
ATF_TEST_CASE_WITHOUT_HEAD.
Changes in version 0.8
**********************
Experimental version released on May 7th, 2010.
* Test programs no longer run several test cases in a row. The execution
of a test program now requires a test case name, and that single test
case is executed. To execute several test cases, use the atf-run utility
as usual.
* Test programs no longer fork a subprocess to isolate the execution of
test cases. They run the test case code in-process, and a crash of the
test case will result in a crash of the test program. This is to ease
debugging of faulty test cases.
* Test programs no longer isolate their test cases. This means that they
will not create temporary directories nor sanitize the environment any
more. Yes: running a test case that depends on system state by hand will
most likely yield different results depending on where (machine,
directory, user environment, etc.) it is run. Isolation has been moved
to atf-run.
* Test programs no longer print a cryptic format (application/X-atf-tcs)
on a special file channel. They can now print whatever they want on the
screen. Because test programs can now only run one test case every time,
providing controlled output is not necessary any more.
* Test programs no longer write their status into a special file
descriptor. Instead, they create a file with the results, which is later
parsed by atf-run. This changes the semantics of the -r flag.
* atf-run has been adjusted to perform the test case isolation. As a
result, there is now a single canonical place that implements the
isolation of test caes. In previous releases, the three language
bindings (C, C++ and shell) had to be kept in sync with each other (read:
not a nice thing to do at all). As a side effect of this change, writing
bindings for other languages will be much, much easier from now on.
* atf-run forks test programs on a test case basis, instead of on a test
program basis as it did before. This is to provide the test case
isolation that was before implemented by the test programs themselves.
* Removed the atf-exec tool. This was used to implement test case
isolation in atf-sh, but it is now unnecessary.
* It is now optional to define the descr meta-data property. It has been
proven to be mostly useless, because test cases often carry a descriptive
name of their own.
Changes in version 0.7
**********************
Experimental version released on December 22nd, 2009.
* Added build-time checks to atf-c and atf-c++. A binding for atf-sh
will come later.
* Migrated all build-time checks for header files to proper ATF tests.
This demonstrates the use of the new feature described above.
* Added an internal API for child process management.
* Converted all plain-text distribution documents to a Docbook canonical
version, and include pre-generated plain text and HTML copies in the
distribution file.
* Simplified the contents of the Makefile.am by regenerating it from a
canonical Makefile.am.m4 source. As a side-effect, some dependency
specifications were fixed.
* Migrated all checks from the check target to installcheck, as these
require ATF to be installed.
* Fixed sign comparison mismatches triggered by the now-enabled
-Wsign-compare.
* Fixed many memory and object leaks.
Changes in version 0.6
**********************
Experimental version released on January 18th, 2009.
* Make atf-exec be able to kill its child process after a certain period
of time; this is controlled through the new -t option.
* Change atf-sh to use atf-exec's -t option to control the test case's
timeouts, instead of doing it internally. Same behavior as before, but
noticeably faster.
* atf-exec's -g option and atf-killpg are gone due to the previous
change.
* Added the atf-check(1) tool, a program that executes a given command
and checks its exit code against a known value and allows the management
of stdout and stderr in multiple ways. This replaces the previous
atf_check function in the atf-sh library and exposes this functionality
to both atf-c and atf-c++.
* Added the ATF_REQUIRE family of macros to the C interface. These help
in checking for fatal test conditions. The old ATF_CHECK macros now
perform non-fatal checks only. I.e. by using ATF_CHECK, the test case
can now continue its execution and the failures will not be reported
until the end of the whole run.
* Extended the amount of ATF_CHECK_* C macros with new ones to provide
more features to the developer. These also have their corresponding
counterparts in the ATF_REQUIRE_* family. The new macros (listing the
suffixes only) are: _EQ (replaces _EQUAL), _EQ_MSG, _STREQ and
_STREQ_MSG.
Changes in version 0.5
**********************
Experimental version released on May 1st, 2008.
* Clauses 3 and 4 of the BSD license used by the project were dropped.
All the code is now under a 2-clause BSD license compatible with the GNU
General Public License (GPL).
* Added a C-only binding so that binary test programs do not need to be
tied to C++ at all. This binding is now known as the atf-c library.
* Renamed the C++ binding to atf-c++ for consistency with the new atf-c.
* Renamed the POSIX shell binding to atf-sh for consistency with the new
atf-c and atf-c++.
* Added a -w flag to test programs through which it is possible to
specify the work directory to be used. This was possible in prior
releases by defining the workdir configuration variable (-v workdir=...),
but was a conceptually incorrect mechanism.
* Test programs now preserve the execution order of test cases when they
are given in the command line. Even those mentioned more than once are
executed multiple times to comply with the user's requests.
Changes in version 0.4
**********************
Experimental version released on February 4th, 2008.
* Added two new manual pages, atf-c++-api and atf-sh-api, describing the
C++ and POSIX shell interfaces used to write test programs.
* Added a pkg-config file, useful to get the flags to build against the
C++ library or to easily detect the presence of ATF.
* Added a way for test cases to require a specific architecture and/or
machine type through the new 'require.arch' and 'require.machine'
meta-data properties, respectively.
* Added the 'timeout' property to test cases, useful to set an
upper-bound limit for the test's run time and thus prevent global test
program stalls due to the test case's misbehavior.
* Added the atf-exec(1) internal utility, used to execute a command
after changing the process group it belongs to.
* Added the atf-killpg(1) internal utility, used to kill process groups.
* Multiple portability fixes. Of special interest, full support for
SunOS (Solaris Express Developer Edition 2007/09) using the Sun Studio 12
C++ compiler.
* Fixed a serious bug that prevented atf-run(1) from working at all
under Fedora 8 x86_64. Due to the nature of the bug, other platforms
were likely affected too.
Changes in version 0.3
**********************
Experimental version released on November 11th, 2007.
* Added XML output support to atf-report. This is accompanied by a DTD
for the format's structure and sample XSLT/CSS files to post-process this
output and convert it to a plain HTML report.
* Changed atf-run to add system information to the report it generates.
This is currently used by atf-report's XML output only, and is later
printed in the HTML reports in a nice and useful summary table. The user
and system administrator are allowed to tune this feature by means of
hooks.
* Removed the test cases' 'isolated' property. This was intended to
avoid touching the file system at all when running the related test case,
but this has not been true for a long while: some control files are
unconditionally required for several purposes, and we cannot easily get
rid of them. This way we remove several critical and delicate pieces of
code.
* Improved atf-report's CSV output format to include information about
test programs too.
* Fixed the tests that used atf-compile to not require this tool as a
helper. Avoids systems without build-time utilities to skip many tests
that could otherwise be run. (E.g. NetBSD without the comp.tgz set
installed.)
* Many general cleanups: Fixed many pieces of code marked as ugly and/or
incomplete.
Changes in version 0.2
**********************
Experimental version released on September 20th, 2007.
* Test cases now get a known umask on entry.
* atf-run now detects many unexpected failures caused by test programs and
reports them as bogus tests. atf-report is able to handle these new
errors and nicely reports them to the user.
* All the data formats read and written by the tools have been
documented and cleaned up. These include those grammars that define how
the different components communicate with each other as well as the
format of files written by the developers and users: the Atffiles and the
configuration files.
* Added the atf-version tool, a utility that displays information about
the currently installed version of ATF.
* Test cases can now define an optional cleanup routine to undo their
actions regardless of their exit status.
* atf-report now summarizes the list of failed (bogus) test programs
when using the ticker output format.
* Test programs now capture some termination signals and clean up any
temporary files before exiting the program.
* Multiple bug fixes and improvements all around.
Changes in version 0.1
**********************
Experimental version released on August 20th, 2007.
* First public version. This was released coinciding with the end of the
Google Summer of Code 2007 program.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

40
README Normal file
View File

@ -0,0 +1,40 @@
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.
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.
Other documents
***************
* AUTHORS: List of authors and contributors for this project.
* COPYING: License information.
* INSTALL: Compilation and installation instructions. These is not the
standard document shipped with many packages, so be sure to read it for
things that are specific to ATF's build.
* NEWS: List of major changes between formal, published releases.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

184
TODO Normal file
View File

@ -0,0 +1,184 @@
Things to do Automated Testing Framework
===========================================================================
Last revised: November 30th, 2010
This document includes the list of things that need to be done in ATF that
are most requested by the users. This information used to be available in
an ad-hoc bug tracker but that proved to be a bad idea. I have collected
all worthy comments in here.
Please note that most work these days is going into Kyua (see
http://code.google.com/p/kyua/). The ideas listed here apply to the
components of ATF that have *not* been migrated to the new codebase yet.
For bug reports or ideas that apply to the components that already have
been migrated, please use the bug tracker in the URL above. Similarly,
whenever a component is migrated, the ideas in this file should be revised
and migrated to the new bug tracker where appropriate.
---------------------------------------------------------------------------
Add build-time checks to atf-sh
The 0.7 release introduced build-time tests to atf-c and atf-c++, but not
to atf-sh. Expose the functionality to the shell interface.
This will probably require writing an atf-build utility that exposes the C
code and can be called from the shell.
---------------------------------------------------------------------------
Revisit what to do when an Atffile lists a non-existent file
---------------------------------------------------------------------------
Add ATF_CHECK* versions to atf-c++ to support non-fatal tests
---------------------------------------------------------------------------
Implement race-condition tests
gcooper:
I would think that stress/negative tests would be of more value than race
condition tests (they're similar, but not exactly the same in my mind).
In particular,
1. Feed through as much data as possible to determine where reporting
breaks down.
2. Feed through data quickly and terminate ASAP. The data should be
captured. Terminate child applications with unexpected exit codes and
signals (in particular, SIGCHLD, SIGPIPE, exit codes that terminate,
etc).
3. Open up a file descriptor in the test application, don't close the file
descriptor.
4. fork(2) a process; don't wait(2) for the application to complete.
There are other scenarios that could be exercised, but these are the ones
I could think of off the topic of my head.
--
jmmv:
1. The thing is: how do you express any of this in a portable/abstract
interface? How do you express that a test case "receives data"? What
does that exactly mean? I don't think the framework should care about
this: each test should be free to decide where its data is and how to
deal with it.
2. Ditto.
3. Not sure I understand your request, but testing for "unexpected exit
codes" is already supported. See wiki:DesignXFail for the feature
design details.
4. What's the problem with this case? The test case exits right away after
terminating the execution of its body; any open file descriptors,
leaked memory, etc. die with it.
5. forking and not waiting for a subprocess was a problem already
addressed.
I kinda have an idea of what Antti means with "race condition tests", but
every time I have tried to describe my understanding of matters I seem to
be wrong. Would be nice to have a clear description of what this involves;
in particular, what are the expectations from the framework and how should
the feature be exposed.
As of now, what I understand by "race condition test" is: a test case that
exercises a race condition. The test case may finish without triggering
the race, in which case it just exists with a successful status.
Otherwise, if the race triggers, the test case gets stuck and times out.
The result should be reported as an "expected failure" different from
timeout.
--
pooka:
Yup. Plus some atf-wide mechanism for the operator to supply some kind of
guideline if the test should try to trigger the race for a second or for
an hour.
--
jmmv:
Alright. While mocking up some code for this, I think that your two
requests are complementary.
On the one hand, when you are talking about a "race condition" test you
really mean an "expected race condition" test. Correct? If so, we need to
extend the xfail mechanism to add one more case, which is to report any
failures as a race condition error and, if there is no failure, report the
test as successful.
On the other hand, the atf-wide mechanism to support how long the test
should run for can be thought as a "stress test" mechanism. I.e. run this
test for X time / iterations and report its results regularly without
involving xfail at all.
So, with this in mind:
* For a test that triggers an unfixed race condition, you set xfail to
race mode and define the test as a stress test. Any failures are
reported as expected failures.
* For a test that verifies a supposedly-fixed race condition, you do *not*
set xfail to race mode, and only set the test to stress test. Any
failures are reported as real failures.
These stress test cases implement a single iteration of the test and
atf-run is in charge of running the test several times, stopping on the
first failure.
Does that make sense?
---------------------------------------------------------------------------
Implement ATF_REQUIRE_ERRNO
pooka:
Most of the lines in tests against system functionality are:
if (syscall(args) == -1)
atf_tc_fail_errno("flop")
Some shorthand would be helpful, like ATF_REQUIRE_ERRNO(syscall(args))
Also, a variant which allows arbitrary return value checks (e.g. "!= 0" or
"< 124" or "!= size") would be nice.
--
gcooper:
There's a problem with this request; not all functions fail in the same
way ... in particular compare the pthread family of functions (which
return errno) vs many native syscalls. Furthermore, compare some
fcntl-like syscalls vs other syscalls. One size fits all solutions may not
be a wise idea in this case, so I think that the problem statement needs
to be better defined, because the above request is too loose.
FWIW, there's also a TEST macro in LTP, which tests for non-zero status,
and sets an appropriate set of global variables for errnos and return
codes, respectively. It was a good idea, but has been mostly abandoned
because it's too difficult to define a success and failure in a universal
manner, so I think that we need to be careful with what's implemented in
ATF to not repeat the mistakes that others have made.
--
jmmv:
I think you've got a good point.
This was mostly intended to simplify the handling of the stupid errno
global variable. I think this is valuable to have, but maybe the
macro/function name should be different because _ERRNO can be confusing.
Probably something like an ATF_CHECK_LIBC / ATF_CHECK_PTHREAD approach
would be more flexible and simple.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

1021
aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

48
admin/Makefile.am.inc Normal file
View File

@ -0,0 +1,48 @@
#
# 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.
#
dist-hook: check-install
PHONY_TARGETS += check-install
check-install: $(srcdir)/INSTALL
$(srcdir)/admin/check-install.sh $(srcdir)/INSTALL
dist-hook: check-style
PHONY_TARGETS += check-style
check-style:
$(srcdir)/admin/check-style.sh
EXTRA_DIST += admin/check-install.sh \
admin/check-style-common.awk \
admin/check-style-c.awk \
admin/check-style-cpp.awk \
admin/check-style-man.awk \
admin/check-style-shell.awk \
admin/check-style.sh
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8

92
admin/check-install.sh Executable file
View File

@ -0,0 +1,92 @@
#! /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.
#
#
# A utility to ensure that INSTALL lists the correct versions of the
# tools used to generate the distfile.
#
Prog_Name=${0##*/}
#
# err message
#
err() {
echo "${Prog_Name}: ${@}" 1>&2
exit 1
}
#
# warn message
#
warn() {
echo "${Prog_Name}: ${@}" 1>&2
}
#
# check_tool readme_file prog_name verbose_name
#
# Executes 'prog_name' to determine its version and checks if the
# given 'readme_file' contains 'verbose_name <version>' in it.
#
check_tool() {
readme=${1}
prog=${2}
name=${3}
ver=$(${prog} --version | head -n 1 | cut -d ' ' -f 4)
if grep "\\* ${name} ${ver}" ${readme} >/dev/null; then
true
else
warn "Incorrect version of ${name}"
false
fi
}
#
# main readme_file
#
# Entry point.
#
main() {
readme=${1}
ret=0
check_tool ${readme} autoconf "GNU autoconf" || ret=1
check_tool ${readme} automake "GNU automake" || ret=1
check_tool ${readme} libtool "GNU libtool" || ret=1
return ${ret}
}
main "${@}"
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4

94
admin/check-style-c.awk Normal file
View File

@ -0,0 +1,94 @@
#
# 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.
#
function warn(msg) {
print FILENAME "[" FNR "]: " msg > "/dev/stderr"
error = 1
}
BEGIN {
skip = 0
error = 0
}
/NO_CHECK_STYLE_BEGIN/ {
skip = 1
next
}
/NO_CHECK_STYLE_END/ {
skip = 0
next
}
/NO_CHECK_STYLE/ {
next
}
{
if (skip)
next
}
/#ifdef/ {
warn("Undesired usage of #ifdef; use #if defined()")
}
/#ifndef/ {
warn("Undesired usage of #ifndef; use #if !defined()")
}
/assert[ \t]*\(/ {
warn("Use the macros in sanity.h instead of assert");
}
/getprogname/ {
warn("getprogname(3) is not portable");
}
/include.*assert.h/ {
warn("Do not include assert.h");
}
/setprogname/ {
warn("setprogname(3) is not portable");
}
/\/\// {
warn("Do not use C99-style comments");
}
END {
if (skip)
warn("Missing NO_CHECK_STYLE_END");
if (error)
exit 1
}
# vim: syntax=awk:expandtab:shiftwidth=4:softtabstop=4

View File

@ -0,0 +1,82 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
function warn(msg) {
print FILENAME "[" FNR "]: " msg > "/dev/stderr"
error = 1
}
BEGIN {
skip = 0
error = 0
}
/NO_CHECK_STYLE_BEGIN/ {
skip = 1
next
}
/NO_CHECK_STYLE_END/ {
skip = 0
next
}
/NO_CHECK_STYLE/ {
next
}
{
if (skip)
next
if (length > 80)
warn("Line too long to fit on screen")
}
/^ *\t+/ {
if (! match(FILENAME, "Makefile"))
warn("Tab character used for indentation");
}
/[ \t]+$/ {
warn("Trailing spaces or tabs");
}
/#![^ ]/ { # NO_CHECK_STYLE
warn("Invalid shellbang: missing space after !");
}
END {
if (skip)
warn("Missing NO_CHECK_STYLE_END");
if (error)
exit 1
}
# vim: syntax=awk:expandtab:shiftwidth=4:softtabstop=4

90
admin/check-style-cpp.awk Normal file
View File

@ -0,0 +1,90 @@
#
# 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.
#
function warn(msg) {
print FILENAME "[" FNR "]: " msg > "/dev/stderr"
error = 1
}
BEGIN {
skip = 0
error = 0
}
/NO_CHECK_STYLE_BEGIN/ {
skip = 1
next
}
/NO_CHECK_STYLE_END/ {
skip = 0
next
}
/NO_CHECK_STYLE/ {
next
}
{
if (skip)
next
}
/#ifdef/ {
warn("Undesired usage of #ifdef; use #if defined()")
}
/#ifndef/ {
warn("Undesired usage of #ifndef; use #if !defined()")
}
/assert[ \t]*\(/ {
warn("Use the macros in sanity.hpp instead of assert");
}
/include.*assert/ {
warn("Do not include assert.h nor cassert");
}
/std::endl/ {
warn("Use \\n instead of std::endl");
}
/\/\*/ {
warn("Do not use C-style comments");
}
END {
if (skip)
warn("Missing NO_CHECK_STYLE_END");
if (error)
exit 1
}
# vim: syntax=awk:expandtab:shiftwidth=4:softtabstop=4

78
admin/check-style-man.awk Normal file
View File

@ -0,0 +1,78 @@
#
# 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.
#
function warn(msg) {
print FILENAME "[" FNR "]: " msg > "/dev/stderr"
error = 1
}
BEGIN {
skip = 0
error = 0
}
/NO_CHECK_STYLE_BEGIN|^\.Bd/ {
skip = 1
next
}
/NO_CHECK_STYLE_END|^\.Ed/ {
skip = 0
next
}
/NO_CHECK_STYLE/ {
next
}
/^\.\\"/ {
next
}
{
if (skip)
next
}
/\.\.|e\.g\.|i\.e\./ {
next
}
/\.[ ]+[a-zA-Z]+/ {
warn("Sentence does not start on new line")
}
END {
if (skip)
warn("Missing NO_CHECK_STYLE_END");
if (error)
exit 1
}
# vim: syntax=awk:expandtab:shiftwidth=4:softtabstop=4

106
admin/check-style-shell.awk Normal file
View File

@ -0,0 +1,106 @@
#
# 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.
#
function warn(msg) {
print FILENAME "[" FNR "]: " msg > "/dev/stderr"
error = 1
}
BEGIN {
skip = 0
error = 0
emacs_modeline = 0
vim_modeline = 0
}
/NO_CHECK_STYLE_BEGIN/ {
skip = 1
next
}
/NO_CHECK_STYLE_END/ {
skip = 0
next
}
/NO_CHECK_STYLE/ {
next
}
{
if (skip)
next
}
/vim: syntax=sh/ {
vim_modeline = 1
}
/^[ \t]*#/ {
next
}
/[$ \t]+_[a-zA-Z0-9]+=/ {
warn("Variable should not start with an underline")
}
/[^\\]\$[^0-9!'"$?@#*{}(|\/,]+/ {
warn("Missing braces around variable name")
}
/=(""|'')/ {
warn("Assignment to the empty string does not need quotes");
}
/basename[ \t]+/ {
warn("Use parameter expansion instead of basename");
}
/if[ \t]+(test|![ \t]+test)/ {
warn("Use [ instead of test");
}
/[ \t]+(test|\[).*==/ {
warn("test(1)'s == operator is not portable");
}
/if.*;[ \t]*fi$/ {
warn("Avoid using a single-line if conditional");
}
END {
if (skip)
warn("Missing NO_CHECK_STYLE_END");
if (! vim_modeline)
warn("Missing mode lines");
if (error)
exit 1
}
# vim: syntax=awk:expandtab:shiftwidth=4:softtabstop=4

189
admin/check-style.sh Executable file
View File

@ -0,0 +1,189 @@
#! /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.
#
#
# A utility to sanity check the coding style of all source files in the
# project tree.
#
Prog_Name=${0##*/}
#
# err message
#
err() {
echo "${Prog_Name}: ${@}" 1>&2
exit 1
}
#
# warn message
#
warn() {
echo "${Prog_Name}: ${@}" 1>&2
}
#
# guess_topdir
#
# Locates the project's top directory and prints its path. The caller
# must verify if the result is correct or not.
#
guess_topdir() {
olddir=$(pwd)
topdir=$(pwd)
while [ ${topdir} != / ]; do
if [ -f ./atf-c.h ]; then
break
else
cd ..
topdir=$(pwd)
fi
done
cd ${olddir}
echo ${topdir}
}
#
# find_sources
#
# Locates all source files within the project, relative to the current
# directory, and prints their paths.
#
find_sources() {
find . \( -name "AUTHORS" -o \
-name "COPYING" -o \
-name "ChangeLog" -o \
-name "NEWS" -o \
-name "README" -o \
-name "TODO" -o \
-name "*.[0-9]" -o \
-name "*.ac" -o \
-name "*.at" -o \
-name "*.awk" -o \
-name "*.c" -o \
-name "*.cpp" -o \
-name "*.h" -o \
-name "*.h.in" -o \
-name "*.hpp" -o \
-name "*.m4" -o \
-name "*.sh" \
\) -a \( \
\! -path "*/atf-[0-9]*" -a \
\! -path "*autom4te*" -a \
-type f -a \
\! -name "aclocal.m4" \
\! -name "bconfig.h" \
\! -name "defs.h" \
\! -name "libtool.m4" \
\! -name "ltoptions.m4" \
\! -name "ltsugar.m4" \
\! -name "lt~obsolete.m4" \
\! -name "*.so.*" \
\)
}
#
# guess_formats file
#
# Guesses the formats applicable to the given file and prints the resulting
# list.
#
guess_formats() {
case ${1} in
*/ltmain.sh)
;;
*.[0-9])
echo common man
;;
*.c|*.h)
echo common c
;;
*.cpp|*.hpp)
echo common cpp
;;
*.sh)
echo common shell
;;
*)
echo common
;;
esac
}
#
# check_file file
#
# Checks the validity of the given file.
#
check_file() {
err=0
for format in $(guess_formats ${1}); do
awk -f ${topdir}/admin/check-style-${format}.awk ${1} || err=1
done
return ${err}
}
#
# main [file list]
#
# Entry point.
#
main() {
topdir=$(guess_topdir)
if [ ! -f ${topdir}/atf-c.h ]; then
err "Could not locate the project's top directory"
fi
if [ ${#} -gt 0 ]; then
sources=${@}
else
cd ${topdir}
sources=$(find_sources)
fi
ok=0
for file in ${sources}; do
file=$(echo ${file} | sed -e "s,\\./,,")
if [ ! -f ${file} ]; then
err "Could not open ${file}"
else
check_file ${file} || ok=1
fi
done
return ${ok}
}
main "${@}"
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4

310
admin/compile Executable file
View File

@ -0,0 +1,310 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-01-04.17; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
# Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l*)
lib=${1#-l}
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
set x "$@" "$dir/$lib.dll.lib"
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
set x "$@" "$dir/$lib.lib"
break
fi
done
IFS=$save_IFS
test "$found" != yes && set x "$@" "$lib.lib"
shift
;;
-L*)
func_file_conv "${1#-L}"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

1522
admin/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1766
admin/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

688
admin/depcomp Executable file
View File

@ -0,0 +1,688 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2011-12-04.11; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# 2011 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add `dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# With Tru64 cc, shared objects can also be used to make a
# static library. This mechanism is used in libtool 1.4 series to
# handle both shared and static libraries in a single compilation.
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
#
# With libtool 1.5 this exception was removed, and libtool now
# generates 2 separate objects for the 2 libraries. These two
# compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
tmpdepfile2=$dir$base.o.d # libtool 1.5
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.o.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
tmpdepfile4=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test "$stat" = 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/ \1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/ /
G
p
}' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

527
admin/install-sh Executable file
View File

@ -0,0 +1,527 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for `test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

9655
admin/ltmain.sh Normal file

File diff suppressed because it is too large Load Diff

331
admin/missing Executable file
View File

@ -0,0 +1,331 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2012-01-06.13; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case $1 in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
autom4te touch the output file, or create a stub one
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
\`g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# normalize program name to check for.
program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program). This is about non-GNU programs, so use $1 not
# $program.
case $1 in
lex*|yacc*)
# Not GNU programs, they don't have --version.
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case $program in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case $f in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te*)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison*|yacc*)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if test ! -f y.tab.h; then
echo >y.tab.h
fi
if test ! -f y.tab.c; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex*|flex*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG=\${$#}
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if test ! -f lex.yy.c; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit $?
fi
;;
makeinfo*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '
/^@setfilename/{
s/.* \([^ ]*\) *$/\1/
p
q
}' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

35
atf-c++.hpp Normal file
View File

@ -0,0 +1,35 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_HPP_)
#define _ATF_CXX_HPP_
#include <atf-c++/macros.hpp>
#endif // !defined(_ATF_CXX_HPP_)

14
atf-c++/Atffile Normal file
View File

@ -0,0 +1,14 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = atf
tp: detail
tp: atf_c++_test
tp: build_test
tp: check_test
tp: config_test
tp: macros_test
tp: pkg_config_test
tp: tests_test
tp: utils_test

14
atf-c++/Kyuafile Normal file
View File

@ -0,0 +1,14 @@
syntax("kyuafile", 1)
test_suite("atf")
atf_test_program{name="atf_c++_test"}
atf_test_program{name="build_test"}
atf_test_program{name="check_test"}
atf_test_program{name="config_test"}
atf_test_program{name="macros_test"}
atf_test_program{name="pkg_config_test"}
atf_test_program{name="tests_test"}
atf_test_program{name="utils_test"}
include("detail/Kyuafile")

111
atf-c++/Makefile.am.inc Normal file
View File

@ -0,0 +1,111 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
ATF_CXX_LIBS = libatf-c++.la libatf-c.la
lib_LTLIBRARIES += libatf-c++.la
libatf_c___la_LIBADD = libatf-c.la
libatf_c___la_SOURCES = atf-c++/build.cpp \
atf-c++/build.hpp \
atf-c++/check.cpp \
atf-c++/check.hpp \
atf-c++/config.cpp \
atf-c++/config.hpp \
atf-c++/macros.hpp \
atf-c++/tests.cpp \
atf-c++/tests.hpp \
atf-c++/utils.hpp
libatf_c___la_LDFLAGS = -version-info 0:0:0
include_HEADERS += atf-c++.hpp
atf_c___HEADERS = atf-c++/build.hpp \
atf-c++/check.hpp \
atf-c++/config.hpp \
atf-c++/macros.hpp \
atf-c++/tests.hpp \
atf-c++/utils.hpp
atf_c__dir = $(includedir)/atf-c++
dist_man_MANS += atf-c++/atf-c++-api.3
atf_aclocal_DATA += atf-c++/atf-c++.m4
EXTRA_DIST += atf-c++/atf-c++.m4
atf_c__dirpkgconfigdir = $(atf_pkgconfigdir)
atf_c__dirpkgconfig_DATA = atf-c++/atf-c++.pc
CLEANFILES += atf-c++/atf-c++.pc
EXTRA_DIST += atf-c++/atf-c++.pc.in
atf-c++/atf-c++.pc: $(srcdir)/atf-c++/atf-c++.pc.in Makefile
test -d atf-c++ || mkdir -p atf-c++
sed -e 's#__ATF_VERSION__#$(PACKAGE_VERSION)#g' \
-e 's#__CXX__#$(CXX)#g' \
-e 's#__INCLUDEDIR__#$(includedir)#g' \
-e 's#__LIBDIR__#$(libdir)#g' \
<$(srcdir)/atf-c++/atf-c++.pc.in >atf-c++/atf-c++.pc.tmp
mv atf-c++/atf-c++.pc.tmp atf-c++/atf-c++.pc
tests_atf_c___DATA = atf-c++/Atffile \
atf-c++/Kyuafile \
atf-c++/macros_hpp_test.cpp \
atf-c++/unused_test.cpp
tests_atf_c__dir = $(pkgtestsdir)/atf-c++
EXTRA_DIST += $(tests_atf_c___DATA)
tests_atf_c___PROGRAMS = atf-c++/atf_c++_test
atf_c___atf_c___test_SOURCES = atf-c++/atf_c++_test.cpp
atf_c___atf_c___test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___PROGRAMS += atf-c++/build_test
atf_c___build_test_SOURCES = atf-c++/build_test.cpp atf-c/h_build.h
atf_c___build_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___PROGRAMS += atf-c++/check_test
atf_c___check_test_SOURCES = atf-c++/check_test.cpp
atf_c___check_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___PROGRAMS += atf-c++/config_test
atf_c___config_test_SOURCES = atf-c++/config_test.cpp
atf_c___config_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___PROGRAMS += atf-c++/macros_test
atf_c___macros_test_SOURCES = atf-c++/macros_test.cpp
atf_c___macros_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___SCRIPTS = atf-c++/pkg_config_test
CLEANFILES += atf-c++/pkg_config_test
EXTRA_DIST += atf-c++/pkg_config_test.sh
atf-c++/pkg_config_test: $(srcdir)/atf-c++/pkg_config_test.sh
test -d atf-c++ || mkdir -p atf-c++
@src="$(srcdir)/atf-c++/pkg_config_test.sh"; \
dst="atf-c++/pkg_config_test"; $(BUILD_SH_TP)
tests_atf_c___PROGRAMS += atf-c++/tests_test
atf_c___tests_test_SOURCES = atf-c++/tests_test.cpp
atf_c___tests_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___PROGRAMS += atf-c++/utils_test
atf_c___utils_test_SOURCES = atf-c++/utils_test.cpp
atf_c___utils_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
include atf-c++/detail/Makefile.am.inc
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8

420
atf-c++/atf-c++-api.3 Normal file
View File

@ -0,0 +1,420 @@
.\"
.\" Automated Testing Framework (atf)
.\"
.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd January 21, 2012
.Dt ATF-C++-API 3
.Os
.Sh NAME
.Nm ATF_ADD_TEST_CASE ,
.Nm ATF_CHECK_ERRNO ,
.Nm ATF_FAIL ,
.Nm ATF_INIT_TEST_CASES ,
.Nm ATF_PASS ,
.Nm ATF_REQUIRE ,
.Nm ATF_REQUIRE_EQ ,
.Nm ATF_REQUIRE_ERRNO ,
.Nm ATF_REQUIRE_IN ,
.Nm ATF_REQUIRE_MATCH ,
.Nm ATF_REQUIRE_NOT_IN ,
.Nm ATF_REQUIRE_THROW ,
.Nm ATF_REQUIRE_THROW_RE ,
.Nm ATF_SKIP ,
.Nm ATF_TEST_CASE ,
.Nm ATF_TEST_CASE_BODY ,
.Nm ATF_TEST_CASE_CLEANUP ,
.Nm ATF_TEST_CASE_HEAD ,
.Nm ATF_TEST_CASE_NAME ,
.Nm ATF_TEST_CASE_USE ,
.Nm ATF_TEST_CASE_WITH_CLEANUP ,
.Nm ATF_TEST_CASE_WITHOUT_HEAD ,
.Nd C++ API to write ATF-based test programs
.Sh SYNOPSIS
.In atf-c++.hpp
.Fn ATF_ADD_TEST_CASE "tcs" "name"
.Fn ATF_CHECK_ERRNO "exp_errno" "bool_expression"
.Fn ATF_FAIL "reason"
.Fn ATF_INIT_TEST_CASES "tcs"
.Fn ATF_PASS
.Fn ATF_REQUIRE "expression"
.Fn ATF_REQUIRE_EQ "expression_1" "expression_2"
.Fn ATF_REQUIRE_ERRNO "exp_errno" "bool_expression"
.Fn ATF_REQUIRE_IN "element" "collection"
.Fn ATF_REQUIRE_MATCH "regexp" "string_expression"
.Fn ATF_REQUIRE_NOT_IN "element" "collection"
.Fn ATF_REQUIRE_THROW "expected_exception" "statement"
.Fn ATF_REQUIRE_THROW_RE "expected_exception" "regexp" "statement"
.Fn ATF_SKIP "reason"
.Fn ATF_TEST_CASE "name"
.Fn ATF_TEST_CASE_BODY "name"
.Fn ATF_TEST_CASE_CLEANUP "name"
.Fn ATF_TEST_CASE_HEAD "name"
.Fn ATF_TEST_CASE_NAME "name"
.Fn ATF_TEST_CASE_USE "name"
.Fn ATF_TEST_CASE_WITH_CLEANUP "name"
.Fn ATF_TEST_CASE_WITHOUT_HEAD "name"
.Sh DESCRIPTION
ATF provides a mostly-macro-based programming interface to implement test
programs in C or C++.
This interface is backed by a C++ implementation, but this fact is
hidden from the developer as much as possible through the use of
macros to simplify programming.
However, the use of C++ is not hidden everywhere and while you can
implement test cases without knowing anything at all about the object model
underneath the provided calls, you might need some minimum notions of the
language in very specific circumstances.
.Pp
C++-based test programs always follow this template:
.Bd -literal -offset indent
extern "C" {
.Ns ... C-specific includes go here ...
}
.Ns ... C++-specific includes go here ...
#include <atf-c++.hpp>
ATF_TEST_CASE(tc1);
ATF_TEST_CASE_HEAD(tc1)
{
... first test case's header ...
}
ATF_TEST_CASE_BODY(tc1)
{
... first test case's body ...
}
ATF_TEST_CASE_WITH_CLEANUP(tc2);
ATF_TEST_CASE_HEAD(tc2)
{
... second test case's header ...
}
ATF_TEST_CASE_BODY(tc2)
{
... second test case's body ...
}
ATF_TEST_CASE_CLEANUP(tc2)
{
... second test case's cleanup ...
}
ATF_TEST_CASE(tc3);
ATF_TEST_CASE_BODY(tc3)
{
... third test case's body ...
}
.Ns ... additional test cases ...
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, tc1);
ATF_ADD_TEST_CASE(tcs, tc2);
ATF_ADD_TEST_CASE(tcs, tc3);
... add additional test cases ...
}
.Ed
.Ss Definition of test cases
Test cases have an identifier and are composed of three different parts:
the header, the body and an optional cleanup routine, all of which are
described in
.Xr atf-test-case 4 .
To define test cases, one can use the
.Fn ATF_TEST_CASE ,
.Fn ATF_TEST_CASE_WITH_CLEANUP
or the
.Fn ATF_TEST_CASE_WITHOUT_HEAD
macros, which take a single parameter specifiying the test case's
name.
.Fn ATF_TEST_CASE ,
requires to define a head and a body for the test case,
.Fn ATF_TEST_CASE_WITH_CLEANUP
requires to define a head, a body and a cleanup for the test case and
.Fn ATF_TEST_CASE_WITHOUT_HEAD
requires only a body for the test case.
It is important to note that these
.Em do not
set the test case up for execution when the program is run.
In order to do so, a later registration is needed through the
.Fn ATF_ADD_TEST_CASE
macro detailed in
.Sx Program initialization .
.Pp
Later on, one must define the three parts of the body by means of three
functions.
Their headers are given by the
.Fn ATF_TEST_CASE_HEAD ,
.Fn ATF_TEST_CASE_BODY
and
.Fn ATF_TEST_CASE_CLEANUP
macros, all of which take the test case's name.
Following each of these, a block of code is expected, surrounded by the
opening and closing brackets.
.Pp
Additionally, the
.Fn ATF_TEST_CASE_NAME
macro can be used to obtain the name of the class corresponding to a
particular test case, as the name is internally manged by the library to
prevent clashes with other user identifiers.
Similarly, the
.Fn ATF_TEST_CASE_USE
macro can be executed on a particular test case to mark it as "used" and
thus prevent compiler warnings regarding unused symbols.
Note that
.Em you should never have to use these macros during regular operation.
.Ss Program initialization
The library provides a way to easily define the test program's
.Fn main
function.
You should never define one on your own, but rely on the
library to do it for you.
This is done by using the
.Fn ATF_INIT_TEST_CASES
macro, which is passed the name of the list that will hold the test cases.
This name can be whatever you want as long as it is a valid variable value.
.Pp
After the macro, you are supposed to provide the body of a function, which
should only use the
.Fn ATF_ADD_TEST_CASE
macro to register the test cases the test program will execute.
The first parameter of this macro matches the name you provided in the
former call.
.Ss Header definitions
The test case's header can define the meta-data by using the
.Fn set
method, which takes two parameters: the first one specifies the
meta-data variable to be set and the second one specifies its value.
Both of them are strings.
.Ss Configuration variables
The test case has read-only access to the current configuration variables
by means of the
.Ft bool
.Fn has_config_var
and the
.Ft std::string
.Fn get_config_var
methods, which can be called in any of the three parts of a test case.
.Ss Access to the source directory
It is possible to get the path to the test case's source directory from any
of its three components by querying the
.Sq srcdir
configuration variable.
.Ss Requiring programs
Aside from the
.Va require.progs
meta-data variable available in the header only, one can also check for
additional programs in the test case's body by using the
.Fn require_prog
function, which takes the base name or full path of a single binary.
Relative paths are forbidden.
If it is not found, the test case will be automatically skipped.
.Ss Test case finalization
The test case finalizes either when the body reaches its end, at which
point the test is assumed to have
.Em passed ,
or at any explicit call to
.Fn ATF_PASS ,
.Fn ATF_FAIL
or
.Fn ATF_SKIP .
These three macros terminate the execution of the test case immediately.
The cleanup routine will be processed afterwards in a completely automated
way, regardless of the test case's termination reason.
.Pp
.Fn ATF_PASS
does not take any parameters.
.Fn ATF_FAIL
and
.Fn ATF_SKIP
take a single string that describes why the test case failed or
was skipped, respectively.
It is very important to provide a clear error message in both cases so that
the user can quickly know why the test did not pass.
.Ss Expectations
Everything explained in the previous section changes when the test case
expectations are redefined by the programmer.
.Pp
Each test case has an internal state called
.Sq expect
that describes what the test case expectations are at any point in time.
The value of this property can change during execution by any of:
.Bl -tag -width indent
.It Fn expect_death "reason"
Expects the test case to exit prematurely regardless of the nature of the
exit.
.It Fn expect_exit "exitcode" "reason"
Expects the test case to exit cleanly.
If
.Va exitcode
is not
.Sq -1 ,
.Xr atf-run 1
will validate that the exit code of the test case matches the one provided
in this call.
Otherwise, the exact value will be ignored.
.It Fn expect_fail "reason"
Any failure (be it fatal or non-fatal) raised in this mode is recorded.
However, such failures do not report the test case as failed; instead, the
test case finalizes cleanly and is reported as
.Sq expected failure ;
this report includes the provided
.Fa reason
as part of it.
If no error is raised while running in this mode, then the test case is
reported as
.Sq failed .
.Pp
This mode is useful to reproduce actual known bugs in tests.
Whenever the developer fixes the bug later on, the test case will start
reporting a failure, signaling the developer that the test case must be
adjusted to the new conditions.
In this situation, it is useful, for example, to set
.Fa reason
as the bug number for tracking purposes.
.It Fn expect_pass
This is the normal mode of execution.
In this mode, any failure is reported as such to the user and the test case
is marked as
.Sq failed .
.It Fn expect_race "reason"
Any failure or timeout during the execution of the test case will be
considered as if a race condition has been triggered and reported as such.
If no problems arise, the test will continue execution as usual.
.It Fn expect_signal "signo" "reason"
Expects the test case to terminate due to the reception of a signal.
If
.Va signo
is not
.Sq -1 ,
.Xr atf-run 1
will validate that the signal that terminated the test case matches the one
provided in this call.
Otherwise, the exact value will be ignored.
.It Fn expect_timeout "reason"
Expects the test case to execute for longer than its timeout.
.El
.Ss Helper macros for common checks
The library provides several macros that are very handy in multiple
situations.
These basically check some condition after executing a given statement or
processing a given expression and, if the condition is not met, they
automatically call
.Fn ATF_FAIL
with an appropriate error message.
.Pp
.Fn ATF_REQUIRE
takes an expression and raises a failure if it evaluates to false.
.Pp
.Fn ATF_REQUIRE_EQ
takes two expressions and raises a failure if the two do not evaluate to
the same exact value.
.Pp
.Fn ATF_REQUIRE_IN
takes an element and a collection and validates that the element is present in
the collection.
.Pp
.Fn ATF_REQUIRE_MATCH
takes a regular expression and a string and raises a failure if the regular
expression does not match the string.
.Pp
.Fn ATF_REQUIRE_NOT_IN
takes an element and a collection and validates that the element is not present
in the collection.
.Pp
.Fn ATF_REQUIRE_THROW
takes the name of an exception and a statement and raises a failure if
the statement does not throw the specified exception.
.Fn ATF_REQUIRE_THROW_EQ
takes the name of an exception, a regular expresion and a statement and raises a
failure if the statement does not throw the specified exception and if the
message of the exception does not match the regular expression.
.Pp
.Fn ATF_CHECK_ERRNO
and
.Fn ATF_REQUIRE_ERRNO
take, first, the error code that the check is expecting to find in the
.Va errno
variable and, second, a boolean expression that, if evaluates to true,
means that a call failed and
.Va errno
has to be checked against the first value.
.Sh EXAMPLES
The following shows a complete test program with a single test case that
validates the addition operator:
.Bd -literal -offset indent
#include <atf-c++.hpp>
ATF_TEST_CASE(addition);
ATF_TEST_CASE_HEAD(addition)
{
set("descr", "Sample tests for the addition operator");
}
ATF_TEST_CASE_BODY(addition)
{
ATF_REQUIRE_EQ(0 + 0, 0);
ATF_REQUIRE_EQ(0 + 1, 1);
ATF_REQUIRE_EQ(1 + 0, 1);
ATF_REQUIRE_EQ(1 + 1, 2);
ATF_REQUIRE_EQ(100 + 200, 300);
}
ATF_TEST_CASE(open_failure);
ATF_TEST_CASE_HEAD(open_failure)
{
set("descr", "Sample tests for the open function");
}
ATF_TEST_CASE_BODY(open_failure)
{
ATF_REQUIRE_ERRNO(ENOENT, open("non-existent", O_RDONLY) == -1);
}
ATF_TEST_CASE(known_bug);
ATF_TEST_CASE_HEAD(known_bug)
{
set("descr", "Reproduces a known bug");
}
ATF_TEST_CASE_BODY(known_bug)
{
expect_fail("See bug number foo/bar");
ATF_REQUIRE_EQ(3, 1 + 1);
expect_pass();
ATF_REQUIRE_EQ(3, 1 + 2);
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, addition);
ATF_ADD_TEST_CASE(tcs, open_failure);
ATF_ADD_TEST_CASE(tcs, known_bug);
}
.Ed
.Sh SEE ALSO
.Xr atf-test-program 1 ,
.Xr atf-test-case 4 ,
.Xr atf 7

48
atf-c++/atf-c++.m4 Normal file
View File

@ -0,0 +1,48 @@
dnl
dnl Automated Testing Framework (atf)
dnl
dnl Copyright 2011 Google Inc.
dnl All rights reserved.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions are
dnl met:
dnl
dnl * Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl * Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in the
dnl documentation and/or other materials provided with the distribution.
dnl * Neither the name of Google Inc. nor the names of its contributors
dnl may be used to endorse or promote products derived from this software
dnl without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl ATF_CHECK_CXX([version-spec])
dnl
dnl Checks if atf-c++ is present. If version-spec is provided, ensures that
dnl the installed version of atf-sh matches the required version. This
dnl argument must be something like '>= 0.14' and accepts any version
dnl specification supported by pkg-config.
dnl
dnl Defines and substitutes ATF_CXX_CFLAGS and ATF_CXX_LIBS with the compiler
dnl and linker flags need to build against atf-c++.
AC_DEFUN([ATF_CHECK_CXX], [
spec="atf-c++[]m4_default_nblank([ $1], [])"
_ATF_CHECK_ARG_WITH(
[PKG_CHECK_MODULES([ATF_CXX], [${spec}],
[found=yes found_atf_cxx=yes], [found=no])],
[required ${spec} not found])
])

11
atf-c++/atf-c++.pc.in Normal file
View File

@ -0,0 +1,11 @@
# ATF pkg-config file
cxx=__CXX__
includedir=__INCLUDEDIR__
libdir=__LIBDIR__
Name: atf-c++
Description: Automated Testing Framework (C++ binding)
Version: __ATF_VERSION__
Cflags: -I${includedir}
Libs: -L${libdir} -latf-c++ -latf-c

48
atf-c++/atf_c++_test.cpp Normal file
View File

@ -0,0 +1,48 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "macros.hpp"
#include "detail/test_helpers.hpp"
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

119
atf-c++/build.cpp Normal file
View File

@ -0,0 +1,119 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include "atf-c/build.h"
#include "atf-c/error.h"
#include "atf-c/utils.h"
}
#include "build.hpp"
#include "detail/exceptions.hpp"
#include "detail/process.hpp"
namespace impl = atf::build;
#define IMPL_NAME "atf::build"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
inline
atf::process::argv_array
cargv_to_argv(const atf_list_t* l)
{
std::vector< const char* > aux;
atf_list_citer_t iter;
atf_list_for_each_c(iter, l)
aux.push_back(static_cast< const char* >(atf_list_citer_data(iter)));
return atf::process::argv_array(aux);
}
inline
atf::process::argv_array
cargv_to_argv_and_free(char** l)
{
try {
atf::process::argv_array argv((const char* const*)l);
atf_utils_free_charpp(l);
return argv;
} catch (...) {
atf_utils_free_charpp(l);
throw;
}
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
atf::process::argv_array
impl::c_o(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
char** l;
atf_error_t err = atf_build_c_o(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &l);
if (atf_is_error(err))
throw_atf_error(err);
return cargv_to_argv_and_free(l);
}
atf::process::argv_array
impl::cpp(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
char** l;
atf_error_t err = atf_build_cpp(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &l);
if (atf_is_error(err))
throw_atf_error(err);
return cargv_to_argv_and_free(l);
}
atf::process::argv_array
impl::cxx_o(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
char** l;
atf_error_t err = atf_build_cxx_o(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &l);
if (atf_is_error(err))
throw_atf_error(err);
return cargv_to_argv_and_free(l);
}

57
atf-c++/build.hpp Normal file
View File

@ -0,0 +1,57 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_BUILD_HPP_)
#define _ATF_CXX_BUILD_HPP_
#include <string>
namespace atf {
namespace process {
class argv_array;
} // namespace process
namespace build {
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
process::argv_array c_o(const std::string&, const std::string&,
const process::argv_array&);
process::argv_array cpp(const std::string&, const std::string&,
const process::argv_array&);
process::argv_array cxx_o(const std::string&, const std::string&,
const process::argv_array&);
} // namespace build
} // namespace atf
#endif // !defined(_ATF_CXX_BUILD_HPP_)

247
atf-c++/build_test.cpp Normal file
View File

@ -0,0 +1,247 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
#include <iostream>
#include "../atf-c/h_build.h"
#include "build.hpp"
#include "config.hpp"
#include "macros.hpp"
#include "detail/env.hpp"
#include "detail/process.hpp"
#include "detail/test_helpers.hpp"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
namespace atf {
namespace config {
void __reinit(void);
}
}
template< class C >
void
print_col(const char* prefix, const C& c)
{
std::cout << prefix << ":";
for (typename C::const_iterator iter = c.begin(); iter != c.end();
iter++)
std::cout << " '" << *iter << "'";
std::cout << "\n";
}
static
void
print_array(const char* prefix, const char* const* a)
{
std::cout << prefix << ":";
for (; *a != NULL; a++)
std::cout << " '" << *a << "'";
std::cout << "\n";
}
static
void
verbose_set_env(const char *var, const char *val)
{
std::cout << "Setting " << var << " to '" << val << "'\n";
atf::env::set(var, val);
}
static
bool
equal_argvs(const atf::process::argv_array& aa, const char* const* array)
{
bool equal = true;
atf::process::argv_array::size_type i = 0;
while (equal && (i < aa.size() && array[i] != NULL)) {
if (std::strcmp(aa[i], array[i]) != 0)
equal = false;
else
i++;
}
if (equal && (i < aa.size() || array[i] != NULL))
equal = false;
return equal;
}
static
void
check_equal_argvs(const atf::process::argv_array& aa, const char* const* array)
{
print_array("Expected arguments", array);
print_col("Arguments returned", aa);
if (!equal_argvs(aa, array))
ATF_FAIL("The constructed argv differs from the expected values");
}
// ------------------------------------------------------------------------
// Internal test cases.
// ------------------------------------------------------------------------
ATF_TEST_CASE(equal_argvs);
ATF_TEST_CASE_HEAD(equal_argvs)
{
set_md_var("descr", "Tests the test case internal equal_argvs function");
}
ATF_TEST_CASE_BODY(equal_argvs)
{
{
const char* const array[] = { NULL };
const char* const argv[] = { NULL };
ATF_REQUIRE(equal_argvs(atf::process::argv_array(argv), array));
}
{
const char* const array[] = { NULL };
const char* const argv[] = { "foo", NULL };
ATF_REQUIRE(!equal_argvs(atf::process::argv_array(argv), array));
}
{
const char* const array[] = { "foo", NULL };
const char* const argv[] = { NULL };
ATF_REQUIRE(!equal_argvs(atf::process::argv_array(argv), array));
}
{
const char* const array[] = { "foo", NULL };
const char* const argv[] = { "foo", NULL };
ATF_REQUIRE(equal_argvs(atf::process::argv_array(argv), array));
}
}
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(c_o);
ATF_TEST_CASE_HEAD(c_o)
{
set_md_var("descr", "Tests the c_o function");
}
ATF_TEST_CASE_BODY(c_o)
{
for (struct c_o_test* test = c_o_tests; test->expargv[0] != NULL;
test++) {
std::cout << "> Test: " << test->msg << "\n";
verbose_set_env("ATF_BUILD_CC", test->cc);
verbose_set_env("ATF_BUILD_CFLAGS", test->cflags);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
atf::config::__reinit();
atf::process::argv_array argv =
atf::build::c_o(test->sfile, test->ofile,
atf::process::argv_array(test->optargs));
check_equal_argvs(argv, test->expargv);
}
}
ATF_TEST_CASE(cpp);
ATF_TEST_CASE_HEAD(cpp)
{
set_md_var("descr", "Tests the cpp function");
}
ATF_TEST_CASE_BODY(cpp)
{
for (struct cpp_test* test = cpp_tests; test->expargv[0] != NULL;
test++) {
std::cout << "> Test: " << test->msg << "\n";
verbose_set_env("ATF_BUILD_CPP", test->cpp);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
atf::config::__reinit();
atf::process::argv_array argv =
atf::build::cpp(test->sfile, test->ofile,
atf::process::argv_array(test->optargs));
check_equal_argvs(argv, test->expargv);
}
}
ATF_TEST_CASE(cxx_o);
ATF_TEST_CASE_HEAD(cxx_o)
{
set_md_var("descr", "Tests the cxx_o function");
}
ATF_TEST_CASE_BODY(cxx_o)
{
for (struct cxx_o_test* test = cxx_o_tests; test->expargv[0] != NULL;
test++) {
std::cout << "> Test: " << test->msg << "\n";
verbose_set_env("ATF_BUILD_CXX", test->cxx);
verbose_set_env("ATF_BUILD_CXXFLAGS", test->cxxflags);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
atf::config::__reinit();
atf::process::argv_array argv =
atf::build::cxx_o(test->sfile, test->ofile,
atf::process::argv_array(test->optargs));
check_equal_argvs(argv, test->expargv);
}
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/build.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the internal test cases.
ATF_ADD_TEST_CASE(tcs, equal_argvs);
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, c_o);
ATF_ADD_TEST_CASE(tcs, cpp);
ATF_ADD_TEST_CASE(tcs, cxx_o);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

158
atf-c++/check.cpp Normal file
View File

@ -0,0 +1,158 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
extern "C" {
#include "atf-c/build.h"
#include "atf-c/error.h"
}
#include "check.hpp"
#include "detail/exceptions.hpp"
#include "detail/process.hpp"
#include "detail/sanity.hpp"
namespace impl = atf::check;
#define IMPL_NAME "atf::check"
// ------------------------------------------------------------------------
// The "check_result" class.
// ------------------------------------------------------------------------
impl::check_result::check_result(const atf_check_result_t* result)
{
std::memcpy(&m_result, result, sizeof(m_result));
}
impl::check_result::~check_result(void)
{
atf_check_result_fini(&m_result);
}
bool
impl::check_result::exited(void)
const
{
return atf_check_result_exited(&m_result);
}
int
impl::check_result::exitcode(void)
const
{
PRE(exited());
return atf_check_result_exitcode(&m_result);
}
bool
impl::check_result::signaled(void)
const
{
return atf_check_result_signaled(&m_result);
}
int
impl::check_result::termsig(void)
const
{
PRE(signaled());
return atf_check_result_termsig(&m_result);
}
const std::string
impl::check_result::stdout_path(void) const
{
return atf_check_result_stdout(&m_result);
}
const std::string
impl::check_result::stderr_path(void) const
{
return atf_check_result_stderr(&m_result);
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
bool
impl::build_c_o(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
bool success;
atf_error_t err = atf_check_build_c_o(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &success);
if (atf_is_error(err))
throw_atf_error(err);
return success;
}
bool
impl::build_cpp(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
bool success;
atf_error_t err = atf_check_build_cpp(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &success);
if (atf_is_error(err))
throw_atf_error(err);
return success;
}
bool
impl::build_cxx_o(const std::string& sfile, const std::string& ofile,
const atf::process::argv_array& optargs)
{
bool success;
atf_error_t err = atf_check_build_cxx_o(sfile.c_str(), ofile.c_str(),
optargs.exec_argv(), &success);
if (atf_is_error(err))
throw_atf_error(err);
return success;
}
std::auto_ptr< impl::check_result >
impl::exec(const atf::process::argv_array& argva)
{
atf_check_result_t result;
atf_error_t err = atf_check_exec_array(argva.exec_argv(), &result);
if (atf_is_error(err))
throw_atf_error(err);
return std::auto_ptr< impl::check_result >(new impl::check_result(&result));
}

133
atf-c++/check.hpp Normal file
View File

@ -0,0 +1,133 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_CHECK_HPP_)
#define _ATF_CXX_CHECK_HPP_
extern "C" {
#include <atf-c/check.h>
}
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include <atf-c++/utils.hpp>
namespace atf {
namespace process {
class argv_array;
} // namespace process
namespace check {
// ------------------------------------------------------------------------
// The "check_result" class.
// ------------------------------------------------------------------------
//!
//! \brief A class that contains results of executed command.
//!
//! The check_result class holds information about results
//! of executing arbitrary command and manages files containing
//! its output.
//!
class check_result : utils::noncopyable {
//!
//! \brief Internal representation of a result.
//!
atf_check_result_t m_result;
//!
//! \brief Constructs a results object and grabs ownership of the
//! parameter passed in.
//!
check_result(const atf_check_result_t* result);
friend check_result test_constructor(const char* const*);
friend std::auto_ptr< check_result > exec(const atf::process::argv_array&);
public:
//!
//! \brief Destroys object and removes all managed files.
//!
~check_result(void);
//!
//! \brief Returns whether the command exited correctly or not.
//!
bool exited(void) const;
//!
//! \brief Returns command's exit status.
//!
int exitcode(void) const;
//!
//! \brief Returns whether the command received a signal or not.
//!
bool signaled(void) const;
//!
//! \brief Returns the signal that terminated the command.
//!
int termsig(void) const;
//!
//! \brief Returns the path to file contaning command's stdout.
//!
const std::string stdout_path(void) const;
//!
//! \brief Returns the path to file contaning command's stderr.
//!
const std::string stderr_path(void) const;
};
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
bool build_c_o(const std::string&, const std::string&,
const atf::process::argv_array&);
bool build_cpp(const std::string&, const std::string&,
const atf::process::argv_array&);
bool build_cxx_o(const std::string&, const std::string&,
const atf::process::argv_array&);
std::auto_ptr< check_result > exec(const atf::process::argv_array&);
// Useful for testing only.
check_result test_constructor(void);
} // namespace check
} // namespace atf
#endif // !defined(_ATF_CXX_CHECK_HPP_)

408
atf-c++/check_test.cpp Normal file
View File

@ -0,0 +1,408 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
}
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <list>
#include <memory>
#include <vector>
#include <atf-c++.hpp>
#include "check.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "detail/fs.hpp"
#include "detail/process.hpp"
#include "detail/test_helpers.hpp"
#include "detail/text.hpp"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
static
std::auto_ptr< atf::check::check_result >
do_exec(const atf::tests::tc* tc, const char* helper_name)
{
std::vector< std::string > argv;
argv.push_back(get_process_helpers_path(*tc).str());
argv.push_back(helper_name);
std::cout << "Executing " << argv[0] << " " << argv[1] << "\n";
atf::process::argv_array argva(argv);
return atf::check::exec(argva);
}
static
std::auto_ptr< atf::check::check_result >
do_exec(const atf::tests::tc* tc, const char* helper_name, const char *carg2)
{
std::vector< std::string > argv;
argv.push_back(get_process_helpers_path(*tc).str());
argv.push_back(helper_name);
argv.push_back(carg2);
std::cout << "Executing " << argv[0] << " " << argv[1] << " "
<< argv[2] << "\n";
atf::process::argv_array argva(argv);
return atf::check::exec(argva);
}
// ------------------------------------------------------------------------
// Helper test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(h_build_c_o_ok);
ATF_TEST_CASE_HEAD(h_build_c_o_ok)
{
set_md_var("descr", "Helper test case for build_c_o");
}
ATF_TEST_CASE_BODY(h_build_c_o_ok)
{
std::ofstream sfile("test.c");
sfile << "#include <stdio.h>\n";
sfile.close();
ATF_REQUIRE(atf::check::build_c_o("test.c", "test.o",
atf::process::argv_array()));
}
ATF_TEST_CASE(h_build_c_o_fail);
ATF_TEST_CASE_HEAD(h_build_c_o_fail)
{
set_md_var("descr", "Helper test case for build_c_o");
}
ATF_TEST_CASE_BODY(h_build_c_o_fail)
{
std::ofstream sfile("test.c");
sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
sfile.close();
ATF_REQUIRE(!atf::check::build_c_o("test.c", "test.o",
atf::process::argv_array()));
}
ATF_TEST_CASE(h_build_cpp_ok);
ATF_TEST_CASE_HEAD(h_build_cpp_ok)
{
set_md_var("descr", "Helper test case for build_cpp");
}
ATF_TEST_CASE_BODY(h_build_cpp_ok)
{
std::ofstream sfile("test.c");
sfile << "#define A foo\n";
sfile << "#define B bar\n";
sfile << "A B\n";
sfile.close();
ATF_REQUIRE(atf::check::build_cpp("test.c", "test.p",
atf::process::argv_array()));
}
ATF_TEST_CASE(h_build_cpp_fail);
ATF_TEST_CASE_HEAD(h_build_cpp_fail)
{
set_md_var("descr", "Helper test case for build_cpp");
}
ATF_TEST_CASE_BODY(h_build_cpp_fail)
{
std::ofstream sfile("test.c");
sfile << "#include \"./non-existent.h\"\n";
sfile.close();
ATF_REQUIRE(!atf::check::build_cpp("test.c", "test.p",
atf::process::argv_array()));
}
ATF_TEST_CASE(h_build_cxx_o_ok);
ATF_TEST_CASE_HEAD(h_build_cxx_o_ok)
{
set_md_var("descr", "Helper test case for build_cxx_o");
}
ATF_TEST_CASE_BODY(h_build_cxx_o_ok)
{
std::ofstream sfile("test.cpp");
sfile << "#include <iostream>\n";
sfile.close();
ATF_REQUIRE(atf::check::build_cxx_o("test.cpp", "test.o",
atf::process::argv_array()));
}
ATF_TEST_CASE(h_build_cxx_o_fail);
ATF_TEST_CASE_HEAD(h_build_cxx_o_fail)
{
set_md_var("descr", "Helper test case for build_cxx_o");
}
ATF_TEST_CASE_BODY(h_build_cxx_o_fail)
{
std::ofstream sfile("test.cpp");
sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
sfile.close();
ATF_REQUIRE(!atf::check::build_cxx_o("test.cpp", "test.o",
atf::process::argv_array()));
}
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(build_c_o);
ATF_TEST_CASE_HEAD(build_c_o)
{
set_md_var("descr", "Tests the build_c_o function");
}
ATF_TEST_CASE_BODY(build_c_o)
{
ATF_TEST_CASE_USE(h_build_c_o_ok);
run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_ok) >();
ATF_REQUIRE(grep_file("stdout", "-o test.o"));
ATF_REQUIRE(grep_file("stdout", "-c test.c"));
ATF_TEST_CASE_USE(h_build_c_o_fail);
run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_fail) >();
ATF_REQUIRE(grep_file("stdout", "-o test.o"));
ATF_REQUIRE(grep_file("stdout", "-c test.c"));
ATF_REQUIRE(grep_file("stderr", "test.c"));
ATF_REQUIRE(grep_file("stderr", "UNDEFINED_SYMBOL"));
}
ATF_TEST_CASE(build_cpp);
ATF_TEST_CASE_HEAD(build_cpp)
{
set_md_var("descr", "Tests the build_cpp function");
}
ATF_TEST_CASE_BODY(build_cpp)
{
ATF_TEST_CASE_USE(h_build_cpp_ok);
run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_ok) >();
ATF_REQUIRE(grep_file("stdout", "-o.*test.p"));
ATF_REQUIRE(grep_file("stdout", "test.c"));
ATF_REQUIRE(grep_file("test.p", "foo bar"));
ATF_TEST_CASE_USE(h_build_cpp_fail);
run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_fail) >();
ATF_REQUIRE(grep_file("stdout", "-o test.p"));
ATF_REQUIRE(grep_file("stdout", "test.c"));
ATF_REQUIRE(grep_file("stderr", "test.c"));
ATF_REQUIRE(grep_file("stderr", "non-existent.h"));
}
ATF_TEST_CASE(build_cxx_o);
ATF_TEST_CASE_HEAD(build_cxx_o)
{
set_md_var("descr", "Tests the build_cxx_o function");
}
ATF_TEST_CASE_BODY(build_cxx_o)
{
ATF_TEST_CASE_USE(h_build_cxx_o_ok);
run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_ok) >();
ATF_REQUIRE(grep_file("stdout", "-o test.o"));
ATF_REQUIRE(grep_file("stdout", "-c test.cpp"));
ATF_TEST_CASE_USE(h_build_cxx_o_fail);
run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_fail) >();
ATF_REQUIRE(grep_file("stdout", "-o test.o"));
ATF_REQUIRE(grep_file("stdout", "-c test.cpp"));
ATF_REQUIRE(grep_file("stderr", "test.cpp"));
ATF_REQUIRE(grep_file("stderr", "UNDEFINED_SYMBOL"));
}
ATF_TEST_CASE(exec_cleanup);
ATF_TEST_CASE_HEAD(exec_cleanup)
{
set_md_var("descr", "Tests that exec properly cleans up the temporary "
"files it creates");
}
ATF_TEST_CASE_BODY(exec_cleanup)
{
std::auto_ptr< atf::fs::path > out;
std::auto_ptr< atf::fs::path > err;
{
std::auto_ptr< atf::check::check_result > r =
do_exec(this, "exit-success");
out.reset(new atf::fs::path(r->stdout_path()));
err.reset(new atf::fs::path(r->stderr_path()));
ATF_REQUIRE(atf::fs::exists(*out.get()));
ATF_REQUIRE(atf::fs::exists(*err.get()));
}
ATF_REQUIRE(!atf::fs::exists(*out.get()));
ATF_REQUIRE(!atf::fs::exists(*err.get()));
}
ATF_TEST_CASE(exec_exitstatus);
ATF_TEST_CASE_HEAD(exec_exitstatus)
{
set_md_var("descr", "Tests that exec properly captures the exit "
"status of the executed command");
}
ATF_TEST_CASE_BODY(exec_exitstatus)
{
{
std::auto_ptr< atf::check::check_result > r =
do_exec(this, "exit-success");
ATF_REQUIRE(r->exited());
ATF_REQUIRE(!r->signaled());
ATF_REQUIRE_EQ(r->exitcode(), EXIT_SUCCESS);
}
{
std::auto_ptr< atf::check::check_result > r =
do_exec(this, "exit-failure");
ATF_REQUIRE(r->exited());
ATF_REQUIRE(!r->signaled());
ATF_REQUIRE_EQ(r->exitcode(), EXIT_FAILURE);
}
{
std::auto_ptr< atf::check::check_result > r =
do_exec(this, "exit-signal");
ATF_REQUIRE(!r->exited());
ATF_REQUIRE(r->signaled());
ATF_REQUIRE_EQ(r->termsig(), SIGKILL);
}
}
static
void
check_lines(const std::string& path, const char* outname,
const char* resname)
{
std::ifstream f(path.c_str());
ATF_REQUIRE(f);
std::string line;
std::getline(f, line);
ATF_REQUIRE_EQ(line, std::string("Line 1 to ") + outname + " for " +
resname);
std::getline(f, line);
ATF_REQUIRE_EQ(line, std::string("Line 2 to ") + outname + " for " +
resname);
}
ATF_TEST_CASE(exec_stdout_stderr);
ATF_TEST_CASE_HEAD(exec_stdout_stderr)
{
set_md_var("descr", "Tests that exec properly captures the stdout "
"and stderr streams of the child process");
}
ATF_TEST_CASE_BODY(exec_stdout_stderr)
{
std::auto_ptr< atf::check::check_result > r1 =
do_exec(this, "stdout-stderr", "result1");
ATF_REQUIRE(r1->exited());
ATF_REQUIRE_EQ(r1->exitcode(), EXIT_SUCCESS);
std::auto_ptr< atf::check::check_result > r2 =
do_exec(this, "stdout-stderr", "result2");
ATF_REQUIRE(r2->exited());
ATF_REQUIRE_EQ(r2->exitcode(), EXIT_SUCCESS);
const std::string out1 = r1->stdout_path();
const std::string out2 = r2->stdout_path();
const std::string err1 = r1->stderr_path();
const std::string err2 = r2->stderr_path();
ATF_REQUIRE(out1.find("check.XXXXXX") == std::string::npos);
ATF_REQUIRE(out2.find("check.XXXXXX") == std::string::npos);
ATF_REQUIRE(err1.find("check.XXXXXX") == std::string::npos);
ATF_REQUIRE(err2.find("check.XXXXXX") == std::string::npos);
ATF_REQUIRE(out1.find("/check") != std::string::npos);
ATF_REQUIRE(out2.find("/check") != std::string::npos);
ATF_REQUIRE(err1.find("/check") != std::string::npos);
ATF_REQUIRE(err2.find("/check") != std::string::npos);
ATF_REQUIRE(out1.find("/stdout") != std::string::npos);
ATF_REQUIRE(out2.find("/stdout") != std::string::npos);
ATF_REQUIRE(err1.find("/stderr") != std::string::npos);
ATF_REQUIRE(err2.find("/stderr") != std::string::npos);
ATF_REQUIRE(out1 != out2);
ATF_REQUIRE(err1 != err2);
check_lines(out1, "stdout", "result1");
check_lines(out2, "stdout", "result2");
check_lines(err1, "stderr", "result1");
check_lines(err2, "stderr", "result2");
}
ATF_TEST_CASE(exec_unknown);
ATF_TEST_CASE_HEAD(exec_unknown)
{
set_md_var("descr", "Tests that running a non-existing binary "
"is handled correctly");
}
ATF_TEST_CASE_BODY(exec_unknown)
{
std::vector< std::string > argv;
argv.push_back(atf::config::get("atf_workdir") + "/non-existent");
atf::process::argv_array argva(argv);
std::auto_ptr< atf::check::check_result > r = atf::check::exec(argva);
ATF_REQUIRE(r->exited());
ATF_REQUIRE_EQ(r->exitcode(), 127);
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/check.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, build_c_o);
ATF_ADD_TEST_CASE(tcs, build_cpp);
ATF_ADD_TEST_CASE(tcs, build_cxx_o);
ATF_ADD_TEST_CASE(tcs, exec_cleanup);
ATF_ADD_TEST_CASE(tcs, exec_exitstatus);
ATF_ADD_TEST_CASE(tcs, exec_stdout_stderr);
ATF_ADD_TEST_CASE(tcs, exec_unknown);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

123
atf-c++/config.cpp Normal file
View File

@ -0,0 +1,123 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <map>
extern "C" {
#include "atf-c/config.h"
}
#include "config.hpp"
#include "detail/env.hpp"
#include "detail/sanity.hpp"
static std::map< std::string, std::string > m_variables;
//
// Adds all predefined standard build-time variables to the m_variables
// map, considering the values a user may have provided in the environment.
//
// Can only be called once during the program's lifetime.
//
static
void
init_variables(void)
{
PRE(m_variables.empty());
m_variables["atf_arch"] = atf_config_get("atf_arch");
m_variables["atf_build_cc"] = atf_config_get("atf_build_cc");
m_variables["atf_build_cflags"] = atf_config_get("atf_build_cflags");
m_variables["atf_build_cpp"] = atf_config_get("atf_build_cpp");
m_variables["atf_build_cppflags"] = atf_config_get("atf_build_cppflags");
m_variables["atf_build_cxx"] = atf_config_get("atf_build_cxx");
m_variables["atf_build_cxxflags"] = atf_config_get("atf_build_cxxflags");
m_variables["atf_confdir"] = atf_config_get("atf_confdir");
m_variables["atf_includedir"] = atf_config_get("atf_includedir");
m_variables["atf_libdir"] = atf_config_get("atf_libdir");
m_variables["atf_libexecdir"] = atf_config_get("atf_libexecdir");
m_variables["atf_machine"] = atf_config_get("atf_machine");
m_variables["atf_pkgdatadir"] = atf_config_get("atf_pkgdatadir");
m_variables["atf_shell"] = atf_config_get("atf_shell");
m_variables["atf_workdir"] = atf_config_get("atf_workdir");
POST(!m_variables.empty());
}
const std::string&
atf::config::get(const std::string& varname)
{
if (m_variables.empty())
init_variables();
PRE(has(varname));
return m_variables[varname];
}
const std::map< std::string, std::string >&
atf::config::get_all(void)
{
if (m_variables.empty())
init_variables();
return m_variables;
}
bool
atf::config::has(const std::string& varname)
{
if (m_variables.empty())
init_variables();
return m_variables.find(varname) != m_variables.end();
}
extern "C" {
void __atf_config_reinit(void);
}
namespace atf {
namespace config {
//
// Auxiliary function for the t_config test program so that it can
// revert the configuration's global status to an empty state and
// do new tests from there on.
//
// Ideally this shouldn't be part of the production library... but
// this is so small that it does not matter.
//
void
__reinit(void)
{
__atf_config_reinit();
m_variables.clear();
}
} // namespace config
} // namespace atf

75
atf-c++/config.hpp Normal file
View File

@ -0,0 +1,75 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_CONFIG_HPP_)
#define _ATF_CXX_CONFIG_HPP_
#include <map>
#include <string>
namespace atf {
namespace config {
//!
//! \brief Gets a build-time configuration variable's value.
//!
//! Given the name of a build-time configuration variable, returns its
//! textual value. The user is free to override these by setting their
//! corresponding environment variables. Therefore always use this
//! interface to get the value of these variables.
//!
//! \pre The variable must exist.
//!
const std::string& get(const std::string&);
//!
//! \brief Returns all the build-time configuration variables.
//!
//! Returns a name to value map containing all build-time configuration
//! variables.
//!
const std::map< std::string, std::string >& get_all(void);
//!
//! \brief Checks whether a build-time configuration variable exists.
//!
//! Given the name of a build-time configuration variable, checks
//! whether it is defined and returns a boolean indicating this
//! condition. The program only has to use this function to sanity-check
//! a variable name provided by the user. Otherwise it can assume that
//! the variables are defined.
//!
bool has(const std::string&);
} // namespace config
} // namespace atf
#endif // !defined(_ATF_CXX_CONFIG_HPP_)

231
atf-c++/config_test.cpp Normal file
View File

@ -0,0 +1,231 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
#include <iostream>
#include "config.hpp"
#include "macros.hpp"
#include "detail/env.hpp"
#include "detail/exceptions.hpp"
#include "detail/test_helpers.hpp"
static const char *test_value = "env-value";
static struct varnames {
const char *lc;
const char *uc;
bool can_be_empty;
} all_vars[] = {
{ "atf_arch", "ATF_ARCH", false },
{ "atf_build_cc", "ATF_BUILD_CC", false },
{ "atf_build_cflags", "ATF_BUILD_CFLAGS", true },
{ "atf_build_cpp", "ATF_BUILD_CPP", false },
{ "atf_build_cppflags", "ATF_BUILD_CPPFLAGS", true },
{ "atf_build_cxx", "ATF_BUILD_CXX", false },
{ "atf_build_cxxflags", "ATF_BUILD_CXXFLAGS", true },
{ "atf_confdir", "ATF_CONFDIR", false },
{ "atf_includedir", "ATF_INCLUDEDIR", false },
{ "atf_libdir", "ATF_LIBDIR", false },
{ "atf_libexecdir", "ATF_LIBEXECDIR", false },
{ "atf_machine", "ATF_MACHINE", false },
{ "atf_pkgdatadir", "ATF_PKGDATADIR", false },
{ "atf_shell", "ATF_SHELL", false },
{ "atf_workdir", "ATF_WORKDIR", false },
{ NULL, NULL, false }
};
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
namespace atf {
namespace config {
void __reinit(void);
}
}
static
void
set_env_var(const char* name, const char* val)
{
try {
atf::env::set(name, val);
} catch (const atf::system_error&) {
ATF_FAIL(std::string("set_env_var(") + name + ", " + val +
") failed");
}
}
static
void
unset_env_var(const char* name)
{
try {
atf::env::unset(name);
} catch (const atf::system_error&) {
ATF_FAIL(std::string("unset_env_var(") + name + ") failed");
}
}
static
size_t
all_vars_count(void)
{
size_t count = 0;
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
count++;
return count;
}
static
void
unset_all(void)
{
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
unset_env_var(v->uc);
}
static
void
compare_one(const char* var, const char* expvalue)
{
std::cout << "Checking that " << var << " is set to " << expvalue << "\n";
for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
if (std::strcmp(v->lc, var) == 0)
ATF_REQUIRE_EQ(atf::config::get(v->lc), test_value);
else
ATF_REQUIRE(atf::config::get(v->lc) != test_value);
}
}
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(get);
ATF_TEST_CASE_HEAD(get)
{
set_md_var("descr", "Tests the config::get function");
}
ATF_TEST_CASE_BODY(get)
{
// Unset all known environment variables and make sure the built-in
// values do not match the bogus value we will use for testing.
unset_all();
atf::config::__reinit();
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
ATF_REQUIRE(atf::config::get(v->lc) != test_value);
// Test the behavior of empty values.
for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
unset_all();
if (!atf::config::get(v->lc).empty()) {
set_env_var(v->uc, "");
atf::config::__reinit();
if (v->can_be_empty)
ATF_REQUIRE(atf::config::get(v->lc).empty());
else
ATF_REQUIRE(!atf::config::get(v->lc).empty());
}
}
// Check if the ATF_ARCH variable is recognized.
for (const struct varnames* v = all_vars; v->lc != NULL; v++) {
unset_all();
set_env_var(v->uc, test_value);
atf::config::__reinit();
compare_one(v->lc, test_value);
}
}
ATF_TEST_CASE(get_all);
ATF_TEST_CASE_HEAD(get_all)
{
set_md_var("descr", "Tests the config::get_all function");
}
ATF_TEST_CASE_BODY(get_all)
{
atf::config::__reinit();
// Check that the valid variables, and only those, are returned.
std::map< std::string, std::string > vars = atf::config::get_all();
ATF_REQUIRE_EQ(vars.size(), all_vars_count());
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
ATF_REQUIRE(vars.find(v->lc) != vars.end());
}
ATF_TEST_CASE(has);
ATF_TEST_CASE_HEAD(has)
{
set_md_var("descr", "Tests the config::has function");
}
ATF_TEST_CASE_BODY(has)
{
atf::config::__reinit();
// Check for all the variables that must exist.
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
ATF_REQUIRE(atf::config::has(v->lc));
// Same as above, but using uppercase (which is incorrect).
for (const struct varnames* v = all_vars; v->lc != NULL; v++)
ATF_REQUIRE(!atf::config::has(v->uc));
// Check for some other variables that cannot exist.
ATF_REQUIRE(!atf::config::has("foo"));
ATF_REQUIRE(!atf::config::has("BAR"));
ATF_REQUIRE(!atf::config::has("atf_foo"));
ATF_REQUIRE(!atf::config::has("ATF_BAR"));
ATF_REQUIRE(!atf::config::has("atf_shel"));
ATF_REQUIRE(!atf::config::has("atf_shells"));
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/config.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, has);
ATF_ADD_TEST_CASE(tcs, get);
ATF_ADD_TEST_CASE(tcs, get_all);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

13
atf-c++/detail/Atffile Normal file
View File

@ -0,0 +1,13 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = atf
tp: application_test
tp: env_test
tp: exceptions_test
tp: expand_test
tp: fs_test
tp: parser_test
tp: sanity_test
tp: text_test
tp: ui_test

13
atf-c++/detail/Kyuafile Normal file
View File

@ -0,0 +1,13 @@
syntax("kyuafile", 1)
test_suite("atf")
atf_test_program{name="application_test"}
atf_test_program{name="env_test"}
atf_test_program{name="exceptions_test"}
atf_test_program{name="expand_test"}
atf_test_program{name="fs_test"}
atf_test_program{name="parser_test"}
atf_test_program{name="sanity_test"}
atf_test_program{name="text_test"}
atf_test_program{name="ui_test"}

View File

@ -0,0 +1,99 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
libatf_c___la_SOURCES += atf-c++/detail/application.cpp \
atf-c++/detail/application.hpp \
atf-c++/detail/env.cpp \
atf-c++/detail/env.hpp \
atf-c++/detail/exceptions.cpp \
atf-c++/detail/exceptions.hpp \
atf-c++/detail/expand.cpp \
atf-c++/detail/expand.hpp \
atf-c++/detail/fs.cpp \
atf-c++/detail/fs.hpp \
atf-c++/detail/parser.cpp \
atf-c++/detail/parser.hpp \
atf-c++/detail/process.cpp \
atf-c++/detail/process.hpp \
atf-c++/detail/sanity.hpp \
atf-c++/detail/text.cpp \
atf-c++/detail/text.hpp \
atf-c++/detail/ui.cpp \
atf-c++/detail/ui.hpp
tests_atf_c___detail_DATA = atf-c++/detail/Atffile \
atf-c++/detail/Kyuafile
tests_atf_c___detaildir = $(pkgtestsdir)/atf-c++/detail
EXTRA_DIST += $(tests_atf_c___detail_DATA)
noinst_LTLIBRARIES += atf-c++/detail/libtest_helpers.la
atf_c___detail_libtest_helpers_la_SOURCES = atf-c++/detail/test_helpers.cpp \
atf-c++/detail/test_helpers.hpp
tests_atf_c___detail_PROGRAMS = atf-c++/detail/application_test
atf_c___detail_application_test_SOURCES = atf-c++/detail/application_test.cpp
atf_c___detail_application_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/env_test
atf_c___detail_env_test_SOURCES = atf-c++/detail/env_test.cpp
atf_c___detail_env_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/exceptions_test
atf_c___detail_exceptions_test_SOURCES = atf-c++/detail/exceptions_test.cpp
atf_c___detail_exceptions_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/expand_test
atf_c___detail_expand_test_SOURCES = atf-c++/detail/expand_test.cpp
atf_c___detail_expand_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/fs_test
atf_c___detail_fs_test_SOURCES = atf-c++/detail/fs_test.cpp
atf_c___detail_fs_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/parser_test
atf_c___detail_parser_test_SOURCES = atf-c++/detail/parser_test.cpp
atf_c___detail_parser_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/process_test
atf_c___detail_process_test_SOURCES = atf-c++/detail/process_test.cpp
atf_c___detail_process_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/sanity_test
atf_c___detail_sanity_test_SOURCES = atf-c++/detail/sanity_test.cpp
atf_c___detail_sanity_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/text_test
atf_c___detail_text_test_SOURCES = atf-c++/detail/text_test.cpp
atf_c___detail_text_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
tests_atf_c___detail_PROGRAMS += atf-c++/detail/ui_test
atf_c___detail_ui_test_SOURCES = atf-c++/detail/ui_test.cpp
atf_c___detail_ui_test_LDADD = atf-c++/detail/libtest_helpers.la $(ATF_CXX_LIBS)
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8

View File

@ -0,0 +1,345 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if defined(HAVE_CONFIG_H)
#include "bconfig.h"
#endif
extern "C" {
#include <unistd.h>
}
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
extern "C" {
#include "atf-c/defs.h"
}
#include "application.hpp"
#include "sanity.hpp"
#include "ui.hpp"
#if !defined(HAVE_VSNPRINTF_IN_STD)
namespace std {
using ::vsnprintf;
}
#endif // !defined(HAVE_VSNPRINTF_IN_STD)
namespace impl = atf::application;
#define IMPL_NAME "atf::application"
// ------------------------------------------------------------------------
// The "usage_error" class.
// ------------------------------------------------------------------------
impl::usage_error::usage_error(const char *fmt, ...)
throw() :
std::runtime_error("usage_error; message unformatted")
{
va_list ap;
va_start(ap, fmt);
std::vsnprintf(m_text, sizeof(m_text), fmt, ap);
va_end(ap);
}
impl::usage_error::~usage_error(void)
throw()
{
}
const char*
impl::usage_error::what(void)
const throw()
{
return m_text;
}
// ------------------------------------------------------------------------
// The "application" class.
// ------------------------------------------------------------------------
impl::option::option(char ch,
const std::string& a,
const std::string& desc) :
m_character(ch),
m_argument(a),
m_description(desc)
{
}
bool
impl::option::operator<(const impl::option& o)
const
{
return m_character < o.m_character;
}
impl::app::app(const std::string& description,
const std::string& manpage,
const std::string& global_manpage,
const bool use_ui) :
m_hflag(false),
m_argc(-1),
m_argv(NULL),
m_prog_name(NULL),
m_description(description),
m_manpage(manpage),
m_global_manpage(global_manpage),
m_use_ui(use_ui)
{
}
impl::app::~app(void)
{
}
bool
impl::app::inited(void)
{
return m_argc != -1;
}
impl::app::options_set
impl::app::options(void)
{
options_set opts = specific_options();
if (m_use_ui) {
opts.insert(option('h', "", "Shows this help message"));
}
return opts;
}
std::string
impl::app::specific_args(void)
const
{
return "";
}
impl::app::options_set
impl::app::specific_options(void)
const
{
return options_set();
}
void
impl::app::process_option(int ch ATF_DEFS_ATTRIBUTE_UNUSED,
const char* arg ATF_DEFS_ATTRIBUTE_UNUSED)
{
}
void
impl::app::process_options(void)
{
PRE(inited());
std::string optstr;
#if defined(HAVE_GNU_GETOPT)
optstr += '+'; // Turn on POSIX behavior.
#endif
optstr += ':';
{
options_set opts = options();
for (options_set::const_iterator iter = opts.begin();
iter != opts.end(); iter++) {
const option& opt = (*iter);
optstr += opt.m_character;
if (!opt.m_argument.empty())
optstr += ':';
}
}
int ch;
const int old_opterr = ::opterr;
::opterr = 0;
while ((ch = ::getopt(m_argc, m_argv, optstr.c_str())) != -1) {
switch (ch) {
case 'h':
INV(m_use_ui);
m_hflag = true;
break;
case ':':
throw usage_error("Option -%c requires an argument.",
::optopt);
case '?':
throw usage_error("Unknown option -%c.", ::optopt);
default:
process_option(ch, ::optarg);
}
}
m_argc -= ::optind;
m_argv += ::optind;
// Clear getopt state just in case the test wants to use it.
opterr = old_opterr;
optind = 1;
#if defined(HAVE_OPTRESET)
optreset = 1;
#endif
}
void
impl::app::usage(std::ostream& os)
{
PRE(inited());
std::string args = specific_args();
if (!args.empty())
args = " " + args;
os << ui::format_text_with_tag(std::string(m_prog_name) + " [options]" +
args, "Usage: ", false) << "\n\n"
<< ui::format_text(m_description) << "\n\n";
options_set opts = options();
INV(!opts.empty());
os << "Available options:\n";
size_t coldesc = 0;
for (options_set::const_iterator iter = opts.begin();
iter != opts.end(); iter++) {
const option& opt = (*iter);
if (opt.m_argument.length() + 1 > coldesc)
coldesc = opt.m_argument.length() + 1;
}
for (options_set::const_iterator iter = opts.begin();
iter != opts.end(); iter++) {
const option& opt = (*iter);
std::string tag = std::string(" -") + opt.m_character;
if (opt.m_argument.empty())
tag += " ";
else
tag += " " + opt.m_argument + " ";
os << ui::format_text_with_tag(opt.m_description, tag, false,
coldesc + 10) << "\n";
}
os << "\n";
std::string gmp;
if (!m_global_manpage.empty())
gmp = " and " + m_global_manpage;
os << ui::format_text("For more details please see " + m_manpage +
gmp + ".")
<< "\n";
}
int
impl::app::run(int argc, char* const* argv)
{
PRE(argc > 0);
PRE(argv != NULL);
m_argc = argc;
m_argv = argv;
m_argv0 = m_argv[0];
m_prog_name = std::strrchr(m_argv[0], '/');
if (m_prog_name == NULL)
m_prog_name = m_argv[0];
else
m_prog_name++;
// Libtool workaround: if running from within the source tree (binaries
// that are not installed yet), skip the "lt-" prefix added to files in
// the ".libs" directory to show the real (not temporary) name.
if (std::strncmp(m_prog_name, "lt-", 3) == 0)
m_prog_name += 3;
const std::string bug =
std::string("This is probably a bug in ") + m_prog_name +
" or one of the libraries it uses. Please report this problem to "
PACKAGE_BUGREPORT " and provide as many details as possible "
"describing how you got to this condition.";
int errcode;
try {
int oldargc = m_argc;
process_options();
if (m_hflag) {
INV(m_use_ui);
if (oldargc != 2)
throw usage_error("-h must be given alone.");
usage(std::cout);
errcode = EXIT_SUCCESS;
} else
errcode = main();
} catch (const usage_error& e) {
if (m_use_ui) {
std::cerr << ui::format_error(m_prog_name, e.what()) << "\n"
<< ui::format_info(m_prog_name, std::string("Type `") +
m_prog_name + " -h' for more details.")
<< "\n";
} else {
std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
std::cerr << m_prog_name << ": See " << m_manpage << " for usage "
"details.\n";
}
errcode = EXIT_FAILURE;
} catch (const std::runtime_error& e) {
if (m_use_ui) {
std::cerr << ui::format_error(m_prog_name, std::string(e.what()))
<< "\n";
} else {
std::cerr << m_prog_name << ": ERROR: " << e.what() << "\n";
}
errcode = EXIT_FAILURE;
} catch (const std::exception& e) {
if (m_use_ui) {
std::cerr << ui::format_error(m_prog_name, std::string("Caught "
"unexpected error: ") + e.what() + "\n" + bug) << "\n";
} else {
std::cerr << m_prog_name << ": ERROR: Caught unexpected error: "
<< e.what() << "\n";
}
errcode = EXIT_FAILURE;
} catch (...) {
if (m_use_ui) {
std::cerr << ui::format_error(m_prog_name, std::string("Caught "
"unknown error\n") + bug) << "\n";
} else {
std::cerr << m_prog_name << ": ERROR: Caught unknown error\n";
}
errcode = EXIT_FAILURE;
}
return errcode;
}

View File

@ -0,0 +1,115 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_APPLICATION_HPP_)
#define _ATF_CXX_APPLICATION_HPP_
#include <ostream>
#include <set>
#include <stdexcept>
#include <string>
namespace atf {
namespace application {
// ------------------------------------------------------------------------
// The "usage_error" class.
// ------------------------------------------------------------------------
class usage_error : public std::runtime_error {
char m_text[4096];
public:
usage_error(const char*, ...) throw();
~usage_error(void) throw();
const char* what(void) const throw();
};
// ------------------------------------------------------------------------
// The "option" class.
// ------------------------------------------------------------------------
class option {
char m_character;
std::string m_argument;
std::string m_description;
friend class app;
public:
option(char, const std::string&, const std::string&);
bool operator<(const option&) const;
};
// ------------------------------------------------------------------------
// The "app" class.
// ------------------------------------------------------------------------
class app {
bool m_hflag;
void process_options(void);
void usage(std::ostream&);
bool inited(void);
protected:
typedef std::set< option > options_set;
int m_argc;
char* const* m_argv;
const char* m_argv0;
const char* m_prog_name;
std::string m_description;
std::string m_manpage, m_global_manpage;
const bool m_use_ui;
options_set options(void);
// To be redefined.
virtual std::string specific_args(void) const;
virtual options_set specific_options(void) const;
virtual void process_option(int, const char*);
virtual int main(void) = 0;
public:
app(const std::string&, const std::string&, const std::string&,
bool = true);
virtual ~app(void);
int run(int, char* const*);
};
} // namespace application
} // namespace atf
#endif // !defined(_ATF_CXX_APPLICATION_HPP_)

View File

@ -0,0 +1,94 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <unistd.h>
}
#include "application.hpp"
#include "../macros.hpp"
class getopt_app : public atf::application::app {
public:
getopt_app(void) : app("description", "manpage", "other") {}
int main(void)
{
// Provide an option that is unknown to the application driver and
// one that is, together with an argument that would be swallowed by
// the test program option if it were recognized.
int argc = 4;
char arg1[] = "progname";
char arg2[] = "-Z";
char arg3[] = "-s";
char arg4[] = "foo";
char *const argv[] = { arg1, arg2, arg3, arg4, NULL };
int ch;
bool zflag;
// Given that this obviously is an application, and that we used the
// same driver to start, we can test getopt(3) right here without doing
// any fancy stuff.
zflag = false;
while ((ch = ::getopt(argc, argv, ":Z")) != -1) {
switch (ch) {
case 'Z':
zflag = true;
break;
case '?':
default:
if (optopt != 's')
ATF_FAIL("Unexpected unknown option found");
}
}
ATF_REQUIRE(zflag);
ATF_REQUIRE_EQ(1, argc - optind);
ATF_REQUIRE_EQ(std::string("foo"), argv[optind]);
return 0;
}
};
ATF_TEST_CASE_WITHOUT_HEAD(getopt);
ATF_TEST_CASE_BODY(getopt)
{
int argc = 1;
char arg1[] = "progname";
char *const argv[] = { arg1, NULL };
ATF_REQUIRE_EQ(0, getopt_app().run(argc, argv));
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, getopt);
}

73
atf-c++/detail/env.cpp Normal file
View File

@ -0,0 +1,73 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include "../../atf-c/error.h"
#include "../../atf-c/detail/env.h"
}
#include "env.hpp"
#include "exceptions.hpp"
#include "sanity.hpp"
namespace impl = atf::env;
#define IMPL_NAME "atf::env"
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
std::string
impl::get(const std::string& name)
{
return atf_env_get(name.c_str());
}
bool
impl::has(const std::string& name)
{
return atf_env_has(name.c_str());
}
void
impl::set(const std::string& name, const std::string& val)
{
atf_error_t err = atf_env_set(name.c_str(), val.c_str());
if (atf_is_error(err))
throw_atf_error(err);
}
void
impl::unset(const std::string& name)
{
atf_error_t err = atf_env_unset(name.c_str());
if (atf_is_error(err))
throw_atf_error(err);
}

84
atf-c++/detail/env.hpp Normal file
View File

@ -0,0 +1,84 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_ENV_HPP_)
#define _ATF_CXX_ENV_HPP_
#include <string>
namespace atf {
namespace env {
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
//!
//! \brief Returns the value of an environment variable.
//!
//! Returns the value of the specified environment variable. The variable
//! must be defined.
//!
std::string get(const std::string&);
//!
//! \brief Checks if the environment has a variable.
//!
//! Checks if the environment has a given variable.
//!
bool has(const std::string&);
//!
//! \brief Sets an environment variable to a given value.
//!
//! Sets the specified environment variable to the given value. Note that
//! variables set to the empty string are different to undefined ones.
//!
//! Be aware that this alters the program's global status, which in general
//! is a bad thing to do due to the side-effects it may have. There are
//! some legitimate usages for this function, though.
//!
void set(const std::string&, const std::string&);
//!
//! \brief Unsets an environment variable.
//!
//! Unsets the specified environment variable Note that undefined
//! variables are different to those defined but set to an empty value.
//!
//! Be aware that this alters the program's global status, which in general
//! is a bad thing to do due to the side-effects it may have. There are
//! some legitimate usages for this function, though.
//!
void unset(const std::string&);
} // namespace env
} // namespace atf
#endif // !defined(_ATF_CXX_ENV_HPP_)

View File

@ -0,0 +1,91 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "../macros.hpp"
#include "env.hpp"
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(has_get);
ATF_TEST_CASE_HEAD(has_get)
{
set_md_var("descr", "Tests the has and get functions");
}
ATF_TEST_CASE_BODY(has_get)
{
ATF_REQUIRE(atf::env::has("PATH"));
ATF_REQUIRE(!atf::env::get("PATH").empty());
ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
}
ATF_TEST_CASE(set);
ATF_TEST_CASE_HEAD(set)
{
set_md_var("descr", "Tests the set function");
}
ATF_TEST_CASE_BODY(set)
{
ATF_REQUIRE(atf::env::has("PATH"));
const std::string& oldval = atf::env::get("PATH");
atf::env::set("PATH", "foo-bar");
ATF_REQUIRE(atf::env::get("PATH") != oldval);
ATF_REQUIRE_EQ(atf::env::get("PATH"), "foo-bar");
ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
atf::env::set("_UNDEFINED_VARIABLE_", "foo2-bar2");
ATF_REQUIRE_EQ(atf::env::get("_UNDEFINED_VARIABLE_"), "foo2-bar2");
}
ATF_TEST_CASE(unset);
ATF_TEST_CASE_HEAD(unset)
{
set_md_var("descr", "Tests the unset function");
}
ATF_TEST_CASE_BODY(unset)
{
ATF_REQUIRE(atf::env::has("PATH"));
atf::env::unset("PATH");
ATF_REQUIRE(!atf::env::has("PATH"));
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, has_get);
ATF_ADD_TEST_CASE(tcs, set);
ATF_ADD_TEST_CASE(tcs, unset);
}

View File

@ -0,0 +1,157 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if defined(HAVE_CONFIG_H)
#include "bconfig.h"
#endif
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <new>
extern "C" {
#include "../../atf-c/error.h"
};
#include "exceptions.hpp"
#include "sanity.hpp"
// ------------------------------------------------------------------------
// The "system_error" type.
// ------------------------------------------------------------------------
atf::system_error::system_error(const std::string& who,
const std::string& message,
int sys_err) :
std::runtime_error(who + ": " + message),
m_sys_err(sys_err)
{
}
atf::system_error::~system_error(void)
throw()
{
}
int
atf::system_error::code(void)
const
throw()
{
return m_sys_err;
}
const char*
atf::system_error::what(void)
const
throw()
{
try {
if (m_message.length() == 0) {
m_message = std::string(std::runtime_error::what()) + ": ";
m_message += ::strerror(m_sys_err);
}
return m_message.c_str();
} catch (...) {
return "Unable to format system_error message";
}
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
static
void
throw_libc_error(atf_error_t err)
{
PRE(atf_error_is(err, "libc"));
const int ecode = atf_libc_error_code(err);
const std::string msg = atf_libc_error_msg(err);
atf_error_free(err);
throw atf::system_error("XXX", msg, ecode);
}
static
void
throw_no_memory_error(atf_error_t err)
{
PRE(atf_error_is(err, "no_memory"));
atf_error_free(err);
throw std::bad_alloc();
}
static
void
throw_unknown_error(atf_error_t err)
{
PRE(atf_is_error(err));
static char buf[4096];
atf_error_format(err, buf, sizeof(buf));
atf_error_free(err);
throw std::runtime_error(buf);
}
void
atf::throw_atf_error(atf_error_t err)
{
static struct handler {
const char* m_name;
void (*m_func)(atf_error_t);
} handlers[] = {
{ "libc", throw_libc_error },
{ "no_memory", throw_no_memory_error },
{ NULL, throw_unknown_error },
};
PRE(atf_is_error(err));
handler* h = handlers;
while (h->m_name != NULL) {
if (atf_error_is(err, h->m_name)) {
h->m_func(err);
UNREACHABLE;
} else
h++;
}
// XXX: I'm not sure that raising an "unknown" error is a wise thing
// to do here. The C++ binding is supposed to have feature parity
// with the C one, so all possible errors raised by the C library
// should have their counterpart in the C++ library. Still, removing
// this will require some code auditing that I can't afford at the
// moment.
INV(h->m_name == NULL && h->m_func != NULL);
h->m_func(err);
UNREACHABLE;
}

View File

@ -0,0 +1,99 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_EXCEPTIONS_HPP_)
#define _ATF_CXX_EXCEPTIONS_HPP_
#include <stdexcept>
#include <string>
extern "C" {
struct atf_error;
}
namespace atf {
template< class T >
class not_found_error :
public std::runtime_error
{
T m_value;
public:
not_found_error(const std::string& message, const T& value) throw();
virtual ~not_found_error(void) throw();
const T& get_value(void) const throw();
};
template< class T >
inline
not_found_error< T >::not_found_error(const std::string& message,
const T& value)
throw() :
std::runtime_error(message),
m_value(value)
{
}
template< class T >
inline
not_found_error< T >::~not_found_error(void)
throw()
{
}
template< class T >
inline
const T&
not_found_error< T >::get_value(void)
const
throw()
{
return m_value;
}
class system_error : public std::runtime_error {
int m_sys_err;
mutable std::string m_message;
public:
system_error(const std::string&, const std::string&, int);
~system_error(void) throw();
int code(void) const throw();
const char* what(void) const throw();
};
void throw_atf_error(struct atf_error *);
} // namespace atf
#endif // !defined(_ATF_CXX_EXCEPTIONS_HPP_)

View File

@ -0,0 +1,148 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include "../../atf-c/error.h"
}
#include <cstdio>
#include <new>
#include "../macros.hpp"
#include "exceptions.hpp"
#include "sanity.hpp"
// ------------------------------------------------------------------------
// The "test" error.
// ------------------------------------------------------------------------
extern "C" {
struct test_error_data {
const char* m_msg;
};
typedef struct test_error_data test_error_data_t;
static
void
test_format(const atf_error_t err, char *buf, size_t buflen)
{
const test_error_data_t* data;
PRE(atf_error_is(err, "test"));
data = static_cast< const test_error_data_t * >(atf_error_data(err));
snprintf(buf, buflen, "Message: %s", data->m_msg);
}
static
atf_error_t
test_error(const char* msg)
{
atf_error_t err;
test_error_data_t data;
data.m_msg = msg;
err = atf_error_new("test", &data, sizeof(data), test_format);
return err;
}
} // extern
// ------------------------------------------------------------------------
// Tests cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(throw_atf_error_libc);
ATF_TEST_CASE_HEAD(throw_atf_error_libc)
{
set_md_var("descr", "Tests the throw_atf_error function when raising "
"a libc error");
}
ATF_TEST_CASE_BODY(throw_atf_error_libc)
{
try {
atf::throw_atf_error(atf_libc_error(1, "System error 1"));
} catch (const atf::system_error& e) {
ATF_REQUIRE(e.code() == 1);
ATF_REQUIRE(std::string(e.what()).find("System error 1") !=
std::string::npos);
} catch (const std::exception& e) {
ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
}
}
ATF_TEST_CASE(throw_atf_error_no_memory);
ATF_TEST_CASE_HEAD(throw_atf_error_no_memory)
{
set_md_var("descr", "Tests the throw_atf_error function when raising "
"a no_memory error");
}
ATF_TEST_CASE_BODY(throw_atf_error_no_memory)
{
try {
atf::throw_atf_error(atf_no_memory_error());
} catch (const std::bad_alloc&) {
} catch (const std::exception& e) {
ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
}
}
ATF_TEST_CASE(throw_atf_error_unknown);
ATF_TEST_CASE_HEAD(throw_atf_error_unknown)
{
set_md_var("descr", "Tests the throw_atf_error function when raising "
"an unknown error");
}
ATF_TEST_CASE_BODY(throw_atf_error_unknown)
{
try {
atf::throw_atf_error(test_error("The message"));
} catch (const std::runtime_error& e) {
const std::string msg = e.what();
ATF_REQUIRE(msg.find("The message") != std::string::npos);
} catch (const std::exception& e) {
ATF_FAIL(std::string("Got unexpected exception: ") + e.what());
}
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, throw_atf_error_libc);
ATF_ADD_TEST_CASE(tcs, throw_atf_error_no_memory);
ATF_ADD_TEST_CASE(tcs, throw_atf_error_unknown);
}

81
atf-c++/detail/expand.cpp Normal file
View File

@ -0,0 +1,81 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <stdexcept>
#include "expand.hpp"
#include "text.hpp"
namespace impl = atf::expand;
#define IMPL_NAME "atf::expand"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
namespace {
std::string
glob_to_regex(const std::string& glob)
{
std::string regex;
regex.reserve(glob.length() * 2);
regex += '^';
for (std::string::const_iterator iter = glob.begin(); iter != glob.end();
iter++) {
switch (*iter) {
case '*': regex += ".*"; break;
case '?': regex += "."; break;
default: regex += *iter;
}
}
regex += '$';
return regex;
}
} // anonymous namespace
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
bool
impl::is_glob(const std::string& glob)
{
// NOTE: Keep this in sync with glob_to_regex!
return glob.find_first_of("*?") != std::string::npos;
}
bool
impl::matches_glob(const std::string& glob, const std::string& candidate)
{
return atf::text::match(candidate, glob_to_regex(glob));
}

82
atf-c++/detail/expand.hpp Normal file
View File

@ -0,0 +1,82 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_EXPAND_HPP_)
#define _ATF_CXX_EXPAND_HPP_
#include <string>
#include <vector>
namespace atf {
namespace expand {
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
//!
//! \brief Checks if the given string is a glob pattern.
//!
//! Returns true if the given string is a glob pattern; i.e. if it contains
//! any character that will be expanded by expand_glob.
//!
bool is_glob(const std::string&);
//!
//! \brief Checks if a given string matches a glob pattern.
//!
//! Given a glob pattern and a string, checks whether the former matches
//! the latter. Returns a boolean indicating this condition.
//!
bool matches_glob(const std::string&, const std::string&);
//!
//! \brief Expands a glob pattern among multiple candidates.
//!
//! Given a glob pattern and a set of candidate strings, checks which of
//! those strings match the glob pattern and returns them.
//!
template< class T >
std::vector< std::string > expand_glob(const std::string& glob,
const T& candidates)
{
std::vector< std::string > exps;
for (typename T::const_iterator iter = candidates.begin();
iter != candidates.end(); iter++)
if (matches_glob(glob, *iter))
exps.push_back(*iter);
return exps;
}
} // namespace expand
} // namespace atf
#endif // !defined(_ATF_CXX_EXPAND_HPP_)

View File

@ -0,0 +1,272 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
#include "../macros.hpp"
#include "expand.hpp"
// XXX Many of the tests here are duplicated in atf-c/t_expand. Should
// find a way to easily share them, or maybe remove the ones here.
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(is_glob);
ATF_TEST_CASE_HEAD(is_glob)
{
set_md_var("descr", "Tests the is_glob function.");
}
ATF_TEST_CASE_BODY(is_glob)
{
using atf::expand::is_glob;
ATF_REQUIRE(!is_glob(""));
ATF_REQUIRE(!is_glob("a"));
ATF_REQUIRE(!is_glob("foo"));
ATF_REQUIRE( is_glob("*"));
ATF_REQUIRE( is_glob("a*"));
ATF_REQUIRE( is_glob("*a"));
ATF_REQUIRE( is_glob("a*b"));
ATF_REQUIRE( is_glob("?"));
ATF_REQUIRE( is_glob("a?"));
ATF_REQUIRE( is_glob("?a"));
ATF_REQUIRE( is_glob("a?b"));
}
ATF_TEST_CASE(matches_glob_plain);
ATF_TEST_CASE_HEAD(matches_glob_plain)
{
set_md_var("descr", "Tests the matches_glob function by using plain "
"text strings as patterns only.");
}
ATF_TEST_CASE_BODY(matches_glob_plain)
{
using atf::expand::matches_glob;
ATF_REQUIRE( matches_glob("", ""));
ATF_REQUIRE(!matches_glob("a", ""));
ATF_REQUIRE(!matches_glob("", "a"));
ATF_REQUIRE( matches_glob("ab", "ab"));
ATF_REQUIRE(!matches_glob("abc", "ab"));
ATF_REQUIRE(!matches_glob("ab", "abc"));
}
ATF_TEST_CASE(matches_glob_star);
ATF_TEST_CASE_HEAD(matches_glob_star)
{
set_md_var("descr", "Tests the matches_glob function by using the '*' "
"meta-character as part of the pattern.");
}
ATF_TEST_CASE_BODY(matches_glob_star)
{
using atf::expand::matches_glob;
ATF_REQUIRE( matches_glob("*", ""));
ATF_REQUIRE( matches_glob("*", "a"));
ATF_REQUIRE( matches_glob("*", "ab"));
ATF_REQUIRE(!matches_glob("a*", ""));
ATF_REQUIRE( matches_glob("a*", "a"));
ATF_REQUIRE( matches_glob("a*", "aa"));
ATF_REQUIRE( matches_glob("a*", "ab"));
ATF_REQUIRE( matches_glob("a*", "abc"));
ATF_REQUIRE(!matches_glob("a*", "ba"));
ATF_REQUIRE( matches_glob("*a", "a"));
ATF_REQUIRE( matches_glob("*a", "ba"));
ATF_REQUIRE(!matches_glob("*a", "bc"));
ATF_REQUIRE(!matches_glob("*a", "bac"));
ATF_REQUIRE( matches_glob("*ab", "ab"));
ATF_REQUIRE( matches_glob("*ab", "aab"));
ATF_REQUIRE( matches_glob("*ab", "aaab"));
ATF_REQUIRE( matches_glob("*ab", "bab"));
ATF_REQUIRE(!matches_glob("*ab", "bcb"));
ATF_REQUIRE(!matches_glob("*ab", "bacb"));
ATF_REQUIRE( matches_glob("a*b", "ab"));
ATF_REQUIRE( matches_glob("a*b", "acb"));
ATF_REQUIRE( matches_glob("a*b", "acdeb"));
ATF_REQUIRE(!matches_glob("a*b", "acdebz"));
ATF_REQUIRE(!matches_glob("a*b", "zacdeb"));
}
ATF_TEST_CASE(matches_glob_question);
ATF_TEST_CASE_HEAD(matches_glob_question)
{
set_md_var("descr", "Tests the matches_glob function by using the '?' "
"meta-character as part of the pattern.");
}
ATF_TEST_CASE_BODY(matches_glob_question)
{
using atf::expand::matches_glob;
ATF_REQUIRE(!matches_glob("?", ""));
ATF_REQUIRE( matches_glob("?", "a"));
ATF_REQUIRE(!matches_glob("?", "ab"));
ATF_REQUIRE( matches_glob("?", "b"));
ATF_REQUIRE( matches_glob("?", "c"));
ATF_REQUIRE( matches_glob("a?", "ab"));
ATF_REQUIRE( matches_glob("a?", "ac"));
ATF_REQUIRE(!matches_glob("a?", "ca"));
ATF_REQUIRE( matches_glob("???", "abc"));
ATF_REQUIRE( matches_glob("???", "def"));
ATF_REQUIRE(!matches_glob("???", "a"));
ATF_REQUIRE(!matches_glob("???", "ab"));
ATF_REQUIRE(!matches_glob("???", "abcd"));
}
ATF_TEST_CASE(expand_glob_base);
ATF_TEST_CASE_HEAD(expand_glob_base)
{
set_md_var("descr", "Tests the expand_glob function with random "
"patterns.");
}
ATF_TEST_CASE_BODY(expand_glob_base)
{
using atf::expand::expand_glob;
std::vector< std::string > candidates;
candidates.push_back("foo");
candidates.push_back("bar");
candidates.push_back("baz");
candidates.push_back("foobar");
candidates.push_back("foobarbaz");
candidates.push_back("foobarbazfoo");
std::vector< std::string > exps;
exps = expand_glob("foo", candidates);
ATF_REQUIRE_EQ(exps.size(), 1);
ATF_REQUIRE(exps[0] == "foo");
exps = expand_glob("bar", candidates);
ATF_REQUIRE_EQ(exps.size(), 1);
ATF_REQUIRE(exps[0] == "bar");
exps = expand_glob("foo*", candidates);
ATF_REQUIRE_EQ(exps.size(), 4);
ATF_REQUIRE(exps[0] == "foo");
ATF_REQUIRE(exps[1] == "foobar");
ATF_REQUIRE(exps[2] == "foobarbaz");
ATF_REQUIRE(exps[3] == "foobarbazfoo");
exps = expand_glob("*foo", candidates);
ATF_REQUIRE_EQ(exps.size(), 2);
ATF_REQUIRE(exps[0] == "foo");
ATF_REQUIRE(exps[1] == "foobarbazfoo");
exps = expand_glob("*foo*", candidates);
ATF_REQUIRE_EQ(exps.size(), 4);
ATF_REQUIRE(exps[0] == "foo");
ATF_REQUIRE(exps[1] == "foobar");
ATF_REQUIRE(exps[2] == "foobarbaz");
ATF_REQUIRE(exps[3] == "foobarbazfoo");
exps = expand_glob("ba", candidates);
ATF_REQUIRE_EQ(exps.size(), 0);
exps = expand_glob("ba*", candidates);
ATF_REQUIRE_EQ(exps.size(), 2);
ATF_REQUIRE(exps[0] == "bar");
ATF_REQUIRE(exps[1] == "baz");
exps = expand_glob("*ba", candidates);
ATF_REQUIRE_EQ(exps.size(), 0);
exps = expand_glob("*ba*", candidates);
ATF_REQUIRE_EQ(exps.size(), 5);
ATF_REQUIRE(exps[0] == "bar");
ATF_REQUIRE(exps[1] == "baz");
ATF_REQUIRE(exps[2] == "foobar");
ATF_REQUIRE(exps[3] == "foobarbaz");
ATF_REQUIRE(exps[4] == "foobarbazfoo");
}
ATF_TEST_CASE(expand_glob_tps);
ATF_TEST_CASE_HEAD(expand_glob_tps)
{
set_md_var("descr", "Tests the expand_glob function with patterns that "
"match typical test program names. This is just a subcase "
"of expand_base, but it is nice to make sure that it really "
"works.");
}
ATF_TEST_CASE_BODY(expand_glob_tps)
{
using atf::expand::expand_glob;
std::vector< std::string > candidates;
candidates.push_back("Atffile");
candidates.push_back("h_foo");
candidates.push_back("t_foo");
candidates.push_back("t_bar");
candidates.push_back("t_baz");
candidates.push_back("foo_helper");
candidates.push_back("foo_test");
candidates.push_back("bar_test");
candidates.push_back("baz_test");
std::vector< std::string > exps;
exps = expand_glob("t_*", candidates);
ATF_REQUIRE_EQ(exps.size(), 3);
ATF_REQUIRE(exps[0] == "t_foo");
ATF_REQUIRE(exps[1] == "t_bar");
ATF_REQUIRE(exps[2] == "t_baz");
exps = expand_glob("*_test", candidates);
ATF_REQUIRE_EQ(exps.size(), 3);
ATF_REQUIRE(exps[0] == "foo_test");
ATF_REQUIRE(exps[1] == "bar_test");
ATF_REQUIRE(exps[2] == "baz_test");
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the tests for the free functions.
ATF_ADD_TEST_CASE(tcs, is_glob);
ATF_ADD_TEST_CASE(tcs, matches_glob_plain);
ATF_ADD_TEST_CASE(tcs, matches_glob_star);
ATF_ADD_TEST_CASE(tcs, matches_glob_question);
ATF_ADD_TEST_CASE(tcs, expand_glob_base);
ATF_ADD_TEST_CASE(tcs, expand_glob_tps);
}

517
atf-c++/detail/fs.cpp Normal file
View File

@ -0,0 +1,517 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if defined(HAVE_CONFIG_H)
#include "bconfig.h"
#endif
extern "C" {
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
#include <libgen.h>
#include <unistd.h>
}
#include <cerrno>
#include <cstdlib>
#include <cstring>
extern "C" {
#include "../../atf-c/error.h"
}
#include "../utils.hpp"
#include "exceptions.hpp"
#include "env.hpp"
#include "fs.hpp"
#include "process.hpp"
#include "sanity.hpp"
#include "text.hpp"
namespace impl = atf::fs;
#define IMPL_NAME "atf::fs"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
static bool safe_access(const impl::path&, int, int);
//!
//! \brief A controlled version of access(2).
//!
//! This function reimplements the standard access(2) system call to
//! safely control its exit status and raise an exception in case of
//! failure.
//!
static
bool
safe_access(const impl::path& p, int mode, int experr)
{
bool ok;
atf_error_t err = atf_fs_eaccess(p.c_path(), mode);
if (atf_is_error(err)) {
if (atf_error_is(err, "libc")) {
if (atf_libc_error_code(err) == experr) {
atf_error_free(err);
ok = false;
} else {
atf::throw_atf_error(err);
// XXX Silence warning; maybe throw_atf_error should be
// an exception and not a function.
ok = false;
}
} else {
atf::throw_atf_error(err);
// XXX Silence warning; maybe throw_atf_error should be
// an exception and not a function.
ok = false;
}
} else
ok = true;
return ok;
}
// ------------------------------------------------------------------------
// The "path" class.
// ------------------------------------------------------------------------
impl::path::path(const std::string& s)
{
atf_error_t err = atf_fs_path_init_fmt(&m_path, "%s", s.c_str());
if (atf_is_error(err))
throw_atf_error(err);
}
impl::path::path(const path& p)
{
atf_error_t err = atf_fs_path_copy(&m_path, &p.m_path);
if (atf_is_error(err))
throw_atf_error(err);
}
impl::path::path(const atf_fs_path_t *p)
{
atf_error_t err = atf_fs_path_copy(&m_path, p);
if (atf_is_error(err))
throw_atf_error(err);
}
impl::path::~path(void)
{
atf_fs_path_fini(&m_path);
}
const char*
impl::path::c_str(void)
const
{
return atf_fs_path_cstring(&m_path);
}
const atf_fs_path_t*
impl::path::c_path(void)
const
{
return &m_path;
}
std::string
impl::path::str(void)
const
{
return c_str();
}
bool
impl::path::is_absolute(void)
const
{
return atf_fs_path_is_absolute(&m_path);
}
bool
impl::path::is_root(void)
const
{
return atf_fs_path_is_root(&m_path);
}
impl::path
impl::path::branch_path(void)
const
{
atf_fs_path_t bp;
atf_error_t err;
err = atf_fs_path_branch_path(&m_path, &bp);
if (atf_is_error(err))
throw_atf_error(err);
path p(atf_fs_path_cstring(&bp));
atf_fs_path_fini(&bp);
return p;
}
std::string
impl::path::leaf_name(void)
const
{
atf_dynstr_t ln;
atf_error_t err;
err = atf_fs_path_leaf_name(&m_path, &ln);
if (atf_is_error(err))
throw_atf_error(err);
std::string s(atf_dynstr_cstring(&ln));
atf_dynstr_fini(&ln);
return s;
}
impl::path
impl::path::to_absolute(void)
const
{
atf_fs_path_t pa;
atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa);
if (atf_is_error(err))
throw_atf_error(err);
path p(atf_fs_path_cstring(&pa));
atf_fs_path_fini(&pa);
return p;
}
impl::path&
impl::path::operator=(const path& p)
{
atf_fs_path_t tmp;
atf_error_t err = atf_fs_path_init_fmt(&tmp, "%s", p.c_str());
if (atf_is_error(err))
throw_atf_error(err);
else {
atf_fs_path_fini(&m_path);
m_path = tmp;
}
return *this;
}
bool
impl::path::operator==(const path& p)
const
{
return atf_equal_fs_path_fs_path(&m_path, &p.m_path);
}
bool
impl::path::operator!=(const path& p)
const
{
return !atf_equal_fs_path_fs_path(&m_path, &p.m_path);
}
impl::path
impl::path::operator/(const std::string& p)
const
{
path p2 = *this;
atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", p.c_str());
if (atf_is_error(err))
throw_atf_error(err);
return p2;
}
impl::path
impl::path::operator/(const path& p)
const
{
path p2 = *this;
atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s",
atf_fs_path_cstring(&p.m_path));
if (atf_is_error(err))
throw_atf_error(err);
return p2;
}
bool
impl::path::operator<(const path& p)
const
{
const char *s1 = atf_fs_path_cstring(&m_path);
const char *s2 = atf_fs_path_cstring(&p.m_path);
return std::strcmp(s1, s2) < 0;
}
// ------------------------------------------------------------------------
// The "file_info" class.
// ------------------------------------------------------------------------
const int impl::file_info::blk_type = atf_fs_stat_blk_type;
const int impl::file_info::chr_type = atf_fs_stat_chr_type;
const int impl::file_info::dir_type = atf_fs_stat_dir_type;
const int impl::file_info::fifo_type = atf_fs_stat_fifo_type;
const int impl::file_info::lnk_type = atf_fs_stat_lnk_type;
const int impl::file_info::reg_type = atf_fs_stat_reg_type;
const int impl::file_info::sock_type = atf_fs_stat_sock_type;
const int impl::file_info::wht_type = atf_fs_stat_wht_type;
impl::file_info::file_info(const path& p)
{
atf_error_t err;
err = atf_fs_stat_init(&m_stat, p.c_path());
if (atf_is_error(err))
throw_atf_error(err);
}
impl::file_info::file_info(const file_info& fi)
{
atf_fs_stat_copy(&m_stat, &fi.m_stat);
}
impl::file_info::~file_info(void)
{
atf_fs_stat_fini(&m_stat);
}
dev_t
impl::file_info::get_device(void)
const
{
return atf_fs_stat_get_device(&m_stat);
}
ino_t
impl::file_info::get_inode(void)
const
{
return atf_fs_stat_get_inode(&m_stat);
}
mode_t
impl::file_info::get_mode(void)
const
{
return atf_fs_stat_get_mode(&m_stat);
}
off_t
impl::file_info::get_size(void)
const
{
return atf_fs_stat_get_size(&m_stat);
}
int
impl::file_info::get_type(void)
const
{
return atf_fs_stat_get_type(&m_stat);
}
bool
impl::file_info::is_owner_readable(void)
const
{
return atf_fs_stat_is_owner_readable(&m_stat);
}
bool
impl::file_info::is_owner_writable(void)
const
{
return atf_fs_stat_is_owner_writable(&m_stat);
}
bool
impl::file_info::is_owner_executable(void)
const
{
return atf_fs_stat_is_owner_executable(&m_stat);
}
bool
impl::file_info::is_group_readable(void)
const
{
return atf_fs_stat_is_group_readable(&m_stat);
}
bool
impl::file_info::is_group_writable(void)
const
{
return atf_fs_stat_is_group_writable(&m_stat);
}
bool
impl::file_info::is_group_executable(void)
const
{
return atf_fs_stat_is_group_executable(&m_stat);
}
bool
impl::file_info::is_other_readable(void)
const
{
return atf_fs_stat_is_other_readable(&m_stat);
}
bool
impl::file_info::is_other_writable(void)
const
{
return atf_fs_stat_is_other_writable(&m_stat);
}
bool
impl::file_info::is_other_executable(void)
const
{
return atf_fs_stat_is_other_executable(&m_stat);
}
// ------------------------------------------------------------------------
// The "directory" class.
// ------------------------------------------------------------------------
impl::directory::directory(const path& p)
{
DIR* dp = ::opendir(p.c_str());
if (dp == NULL)
throw system_error(IMPL_NAME "::directory::directory(" +
p.str() + ")", "opendir(3) failed", errno);
struct dirent* dep;
while ((dep = ::readdir(dp)) != NULL) {
path entryp = p / dep->d_name;
insert(value_type(dep->d_name, file_info(entryp)));
}
if (::closedir(dp) == -1)
throw system_error(IMPL_NAME "::directory::directory(" +
p.str() + ")", "closedir(3) failed", errno);
}
std::set< std::string >
impl::directory::names(void)
const
{
std::set< std::string > ns;
for (const_iterator iter = begin(); iter != end(); iter++)
ns.insert((*iter).first);
return ns;
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
bool
impl::exists(const path& p)
{
atf_error_t err;
bool b;
err = atf_fs_exists(p.c_path(), &b);
if (atf_is_error(err))
throw_atf_error(err);
return b;
}
bool
impl::have_prog_in_path(const std::string& prog)
{
PRE(prog.find('/') == std::string::npos);
// Do not bother to provide a default value for PATH. If it is not
// there something is broken in the user's environment.
if (!atf::env::has("PATH"))
throw std::runtime_error("PATH not defined in the environment");
std::vector< std::string > dirs =
atf::text::split(atf::env::get("PATH"), ":");
bool found = false;
for (std::vector< std::string >::const_iterator iter = dirs.begin();
!found && iter != dirs.end(); iter++) {
const path& dir = path(*iter);
if (is_executable(dir / prog))
found = true;
}
return found;
}
bool
impl::is_executable(const path& p)
{
if (!exists(p))
return false;
return safe_access(p, atf_fs_access_x, EACCES);
}
void
impl::remove(const path& p)
{
if (file_info(p).get_type() == file_info::dir_type)
throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
"Is a directory",
EPERM);
if (::unlink(p.c_str()) == -1)
throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
"unlink(" + p.str() + ") failed",
errno);
}
void
impl::rmdir(const path& p)
{
atf_error_t err = atf_fs_rmdir(p.c_path());
if (atf_is_error(err))
throw_atf_error(err);
}

391
atf-c++/detail/fs.hpp Normal file
View File

@ -0,0 +1,391 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_FS_HPP_)
#define _ATF_CXX_FS_HPP_
extern "C" {
#include <sys/types.h>
}
#include <map>
#include <memory>
#include <ostream>
#include <set>
#include <stdexcept>
#include <string>
extern "C" {
#include "../../atf-c/detail/fs.h"
}
namespace atf {
namespace io {
class systembuf;
} // namespace io
namespace fs {
// ------------------------------------------------------------------------
// The "path" class.
// ------------------------------------------------------------------------
//!
//! \brief A class to represent a path to a file.
//!
//! The path class represents the route to a file or directory in the
//! file system. All file manipulation operations use this class to
//! represent their arguments as it takes care of normalizing user-provided
//! strings and ensures they are valid.
//!
//! It is important to note that the file pointed to by a path need not
//! exist.
//!
class path {
//!
//! \brief Internal representation of a path.
//!
atf_fs_path_t m_path;
public:
//! \brief Constructs a new path from a user-provided string.
//!
//! This constructor takes a string, either provided by the program's
//! code or by the user and constructs a new path object. The string
//! is normalized to not contain multiple delimiters together and to
//! remove any trailing one.
//!
//! The input string cannot be empty.
//!
explicit path(const std::string&);
//!
//! \brief Copy constructor.
//!
path(const path&);
//!
//! \brief Copy constructor.
//!
path(const atf_fs_path_t *);
//!
//! \brief Destructor for the path class.
//!
~path(void);
//!
//! \brief Returns a pointer to a C-style string representing this path.
//!
const char* c_str(void) const;
//!
//! \brief Returns a pointer to the implementation data.
//!
const atf_fs_path_t* c_path(void) const;
//!
//! \brief Returns a string representing this path.
//! XXX Really needed?
//!
std::string str(void) const;
//!
//! \brief Returns the branch path of this path.
//!
//! Calculates and returns the branch path of this path. In other
//! words, it returns what the standard ::dirname function would return.
//!
path branch_path(void) const;
//!
//! \brief Returns the leaf name of this path.
//!
//! Calculates and returns the leaf name of this path. In other words,
//! it returns what the standard ::basename function would return.
//!
std::string leaf_name(void) const;
//!
//! \brief Checks whether this path is absolute or not.
//!
//! Returns a boolean indicating if this is an absolute path or not;
//! i.e. if it starts with a slash.
//!
bool is_absolute(void) const;
//!
//! \brief Checks whether this path points to the root directory or not.
//!
//! Returns a boolean indicating if this is path points to the root
//! directory or not. The checks made by this are extremely simple (so
//! the results cannot always be trusted) but they are enough for our
//! modest sanity-checking needs. I.e. "/../" could return false.
//!
bool is_root(void) const;
//!
//! \brief Converts the path to be absolute.
//!
//! \pre The path was not absolute.
//!
path to_absolute(void) const;
//!
//! \brief Assignment operator.
//!
path& operator=(const path&);
//!
//! \brief Checks if two paths are equal.
//!
bool operator==(const path&) const;
//!
//! \brief Checks if two paths are different.
//!
bool operator!=(const path&) const;
//!
//! \brief Concatenates a path with a string.
//!
//! Constructs a new path object that is the concatenation of the
//! left-hand path with the right-hand string. The string is normalized
//! before the concatenation, and a path delimiter is introduced between
//! the two components if needed.
//!
path operator/(const std::string&) const;
//!
//! \brief Concatenates a path with another path.
//!
//! Constructs a new path object that is the concatenation of the
//! left-hand path with the right-hand one. A path delimiter is
//! introduced between the two components if needed.
//!
path operator/(const path&) const;
//!
//! \brief Checks if a path has to be sorted before another one
//! lexicographically.
//!
bool operator<(const path&) const;
};
// ------------------------------------------------------------------------
// The "file_info" class.
// ------------------------------------------------------------------------
class directory;
//!
//! \brief A class that contains information about a file.
//!
//! The file_info class holds information about an specific file that
//! exists in the file system.
//!
class file_info {
atf_fs_stat_t m_stat;
public:
//!
//! \brief The file's type.
//!
static const int blk_type;
static const int chr_type;
static const int dir_type;
static const int fifo_type;
static const int lnk_type;
static const int reg_type;
static const int sock_type;
static const int wht_type;
//!
//! \brief Constructs a new file_info based on a given file.
//!
//! This constructor creates a new file_info object and fills it with
//! the data returned by ::stat when run on the given file, which must
//! exist.
//!
explicit file_info(const path&);
//!
//! \brief The copy constructor.
//!
file_info(const file_info&);
//!
//! \brief The destructor.
//!
~file_info(void);
//!
//! \brief Returns the device containing the file.
//!
dev_t get_device(void) const;
//!
//! \brief Returns the file's inode.
//!
ino_t get_inode(void) const;
//!
//! \brief Returns the file's permissions.
//!
mode_t get_mode(void) const;
//!
//! \brief Returns the file's size.
//!
off_t get_size(void) const;
//!
//! \brief Returns the file's type.
//!
int get_type(void) const;
//!
//! \brief Returns whether the file is readable by its owner or not.
//!
bool is_owner_readable(void) const;
//!
//! \brief Returns whether the file is writable by its owner or not.
//!
bool is_owner_writable(void) const;
//!
//! \brief Returns whether the file is executable by its owner or not.
//!
bool is_owner_executable(void) const;
//!
//! \brief Returns whether the file is readable by the users belonging
//! to its group or not.
//!
bool is_group_readable(void) const;
//!
//! \brief Returns whether the file is writable the users belonging to
//! its group or not.
//!
bool is_group_writable(void) const;
//!
//! \brief Returns whether the file is executable by the users
//! belonging to its group or not.
//!
bool is_group_executable(void) const;
//!
//! \brief Returns whether the file is readable by people different
//! than the owner and those belonging to the group or not.
//!
bool is_other_readable(void) const;
//!
//! \brief Returns whether the file is write by people different
//! than the owner and those belonging to the group or not.
//!
bool is_other_writable(void) const;
//!
//! \brief Returns whether the file is executable by people different
//! than the owner and those belonging to the group or not.
//!
bool is_other_executable(void) const;
};
// ------------------------------------------------------------------------
// The "directory" class.
// ------------------------------------------------------------------------
//!
//! \brief A class representing a file system directory.
//!
//! The directory class represents a group of files in the file system and
//! corresponds to exactly one directory.
//!
class directory : public std::map< std::string, file_info > {
public:
//!
//! \brief Constructs a new directory.
//!
//! Constructs a new directory object representing the given path.
//! The directory must exist at creation time as the contents of the
//! class are gathered from it.
//!
directory(const path&);
//!
//! \brief Returns the file names of the files in the directory.
//!
//! Returns the leaf names of all files contained in the directory.
//! I.e. the keys of the directory map.
//!
std::set< std::string > names(void) const;
};
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
//!
//! \brief Checks if the given path exists.
//!
bool exists(const path&);
//!
//! \brief Looks for the given program in the PATH.
//!
//! Given a program name (without slashes) looks for it in the path and
//! returns its full path name if found, otherwise an empty path.
//!
bool have_prog_in_path(const std::string&);
//!
//! \brief Checks if the given path exists, is accessible and is executable.
//!
bool is_executable(const path&);
//!
//! \brief Removes a given file.
//!
void remove(const path&);
//!
//! \brief Removes an empty directory.
//!
void rmdir(const path&);
} // namespace fs
} // namespace atf
#endif // !defined(_ATF_CXX_FS_HPP_)

545
atf-c++/detail/fs_test.cpp Normal file
View File

@ -0,0 +1,545 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
}
#include <fstream>
#include <cerrno>
#include <cstdio>
#include "../macros.hpp"
#include "exceptions.hpp"
#include "fs.hpp"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
static
void
create_files(void)
{
::mkdir("files", 0755);
::mkdir("files/dir", 0755);
std::ofstream os("files/reg");
os.close();
// TODO: Should create all other file types (blk, chr, fifo, lnk, sock)
// and test for them... but the underlying file system may not support
// most of these. Specially as we are working on /tmp, which can be
// mounted with flags such as "nodev". See how to deal with this
// situation.
}
// ------------------------------------------------------------------------
// Test cases for the "path" class.
// ------------------------------------------------------------------------
ATF_TEST_CASE(path_normalize);
ATF_TEST_CASE_HEAD(path_normalize)
{
set_md_var("descr", "Tests the path's normalization");
}
ATF_TEST_CASE_BODY(path_normalize)
{
using atf::fs::path;
ATF_REQUIRE_EQ(path(".").str(), ".");
ATF_REQUIRE_EQ(path("..").str(), "..");
ATF_REQUIRE_EQ(path("foo").str(), "foo");
ATF_REQUIRE_EQ(path("foo/bar").str(), "foo/bar");
ATF_REQUIRE_EQ(path("foo/bar/").str(), "foo/bar");
ATF_REQUIRE_EQ(path("/foo").str(), "/foo");
ATF_REQUIRE_EQ(path("/foo/bar").str(), "/foo/bar");
ATF_REQUIRE_EQ(path("/foo/bar/").str(), "/foo/bar");
ATF_REQUIRE_EQ(path("///foo").str(), "/foo");
ATF_REQUIRE_EQ(path("///foo///bar").str(), "/foo/bar");
ATF_REQUIRE_EQ(path("///foo///bar///").str(), "/foo/bar");
}
ATF_TEST_CASE(path_is_absolute);
ATF_TEST_CASE_HEAD(path_is_absolute)
{
set_md_var("descr", "Tests the path::is_absolute function");
}
ATF_TEST_CASE_BODY(path_is_absolute)
{
using atf::fs::path;
ATF_REQUIRE( path("/").is_absolute());
ATF_REQUIRE( path("////").is_absolute());
ATF_REQUIRE( path("////a").is_absolute());
ATF_REQUIRE( path("//a//").is_absolute());
ATF_REQUIRE(!path("a////").is_absolute());
ATF_REQUIRE(!path("../foo").is_absolute());
}
ATF_TEST_CASE(path_is_root);
ATF_TEST_CASE_HEAD(path_is_root)
{
set_md_var("descr", "Tests the path::is_root function");
}
ATF_TEST_CASE_BODY(path_is_root)
{
using atf::fs::path;
ATF_REQUIRE( path("/").is_root());
ATF_REQUIRE( path("////").is_root());
ATF_REQUIRE(!path("////a").is_root());
ATF_REQUIRE(!path("//a//").is_root());
ATF_REQUIRE(!path("a////").is_root());
ATF_REQUIRE(!path("../foo").is_root());
}
ATF_TEST_CASE(path_branch_path);
ATF_TEST_CASE_HEAD(path_branch_path)
{
set_md_var("descr", "Tests the path::branch_path function");
}
ATF_TEST_CASE_BODY(path_branch_path)
{
using atf::fs::path;
ATF_REQUIRE_EQ(path(".").branch_path().str(), ".");
ATF_REQUIRE_EQ(path("foo").branch_path().str(), ".");
ATF_REQUIRE_EQ(path("foo/bar").branch_path().str(), "foo");
ATF_REQUIRE_EQ(path("/foo").branch_path().str(), "/");
ATF_REQUIRE_EQ(path("/foo/bar").branch_path().str(), "/foo");
}
ATF_TEST_CASE(path_leaf_name);
ATF_TEST_CASE_HEAD(path_leaf_name)
{
set_md_var("descr", "Tests the path::leaf_name function");
}
ATF_TEST_CASE_BODY(path_leaf_name)
{
using atf::fs::path;
ATF_REQUIRE_EQ(path(".").leaf_name(), ".");
ATF_REQUIRE_EQ(path("foo").leaf_name(), "foo");
ATF_REQUIRE_EQ(path("foo/bar").leaf_name(), "bar");
ATF_REQUIRE_EQ(path("/foo").leaf_name(), "foo");
ATF_REQUIRE_EQ(path("/foo/bar").leaf_name(), "bar");
}
ATF_TEST_CASE(path_compare_equal);
ATF_TEST_CASE_HEAD(path_compare_equal)
{
set_md_var("descr", "Tests the comparison for equality between paths");
}
ATF_TEST_CASE_BODY(path_compare_equal)
{
using atf::fs::path;
ATF_REQUIRE(path("/") == path("///"));
ATF_REQUIRE(path("/a") == path("///a"));
ATF_REQUIRE(path("/a") == path("///a///"));
ATF_REQUIRE(path("a/b/c") == path("a//b//c"));
ATF_REQUIRE(path("a/b/c") == path("a//b//c///"));
}
ATF_TEST_CASE(path_compare_different);
ATF_TEST_CASE_HEAD(path_compare_different)
{
set_md_var("descr", "Tests the comparison for difference between paths");
}
ATF_TEST_CASE_BODY(path_compare_different)
{
using atf::fs::path;
ATF_REQUIRE(path("/") != path("//a/"));
ATF_REQUIRE(path("/a") != path("a///"));
ATF_REQUIRE(path("a/b/c") != path("a/b"));
ATF_REQUIRE(path("a/b/c") != path("a//b"));
ATF_REQUIRE(path("a/b/c") != path("/a/b/c"));
ATF_REQUIRE(path("a/b/c") != path("/a//b//c"));
}
ATF_TEST_CASE(path_concat);
ATF_TEST_CASE_HEAD(path_concat)
{
set_md_var("descr", "Tests the concatenation of multiple paths");
}
ATF_TEST_CASE_BODY(path_concat)
{
using atf::fs::path;
ATF_REQUIRE_EQ((path("foo") / "bar").str(), "foo/bar");
ATF_REQUIRE_EQ((path("foo/") / "/bar").str(), "foo/bar");
ATF_REQUIRE_EQ((path("foo/") / "/bar/baz").str(), "foo/bar/baz");
ATF_REQUIRE_EQ((path("foo/") / "///bar///baz").str(), "foo/bar/baz");
}
ATF_TEST_CASE(path_to_absolute);
ATF_TEST_CASE_HEAD(path_to_absolute)
{
set_md_var("descr", "Tests the conversion of a relative path to an "
"absolute one");
}
ATF_TEST_CASE_BODY(path_to_absolute)
{
using atf::fs::file_info;
using atf::fs::path;
create_files();
{
const path p(".");
path pa = p.to_absolute();
ATF_REQUIRE(pa.is_absolute());
file_info fi(p);
file_info fia(pa);
ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
}
{
const path p("files/reg");
path pa = p.to_absolute();
ATF_REQUIRE(pa.is_absolute());
file_info fi(p);
file_info fia(pa);
ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
}
}
ATF_TEST_CASE(path_op_less);
ATF_TEST_CASE_HEAD(path_op_less)
{
set_md_var("descr", "Tests that the path's less-than operator works");
}
ATF_TEST_CASE_BODY(path_op_less)
{
using atf::fs::path;
create_files();
ATF_REQUIRE(!(path("aaa") < path("aaa")));
ATF_REQUIRE( path("aab") < path("abc"));
ATF_REQUIRE(!(path("abc") < path("aab")));
}
// ------------------------------------------------------------------------
// Test cases for the "directory" class.
// ------------------------------------------------------------------------
ATF_TEST_CASE(directory_read);
ATF_TEST_CASE_HEAD(directory_read)
{
set_md_var("descr", "Tests the directory class creation, which reads "
"the contents of a directory");
}
ATF_TEST_CASE_BODY(directory_read)
{
using atf::fs::directory;
using atf::fs::path;
create_files();
directory d(path("files"));
ATF_REQUIRE_EQ(d.size(), 4);
ATF_REQUIRE(d.find(".") != d.end());
ATF_REQUIRE(d.find("..") != d.end());
ATF_REQUIRE(d.find("dir") != d.end());
ATF_REQUIRE(d.find("reg") != d.end());
}
ATF_TEST_CASE(directory_file_info);
ATF_TEST_CASE_HEAD(directory_file_info)
{
set_md_var("descr", "Tests that the file_info objects attached to the "
"directory are valid");
}
ATF_TEST_CASE_BODY(directory_file_info)
{
using atf::fs::directory;
using atf::fs::file_info;
using atf::fs::path;
create_files();
directory d(path("files"));
{
directory::const_iterator iter = d.find("dir");
ATF_REQUIRE(iter != d.end());
const file_info& fi = (*iter).second;
ATF_REQUIRE(fi.get_type() == file_info::dir_type);
}
{
directory::const_iterator iter = d.find("reg");
ATF_REQUIRE(iter != d.end());
const file_info& fi = (*iter).second;
ATF_REQUIRE(fi.get_type() == file_info::reg_type);
}
}
ATF_TEST_CASE(directory_names);
ATF_TEST_CASE_HEAD(directory_names)
{
set_md_var("descr", "Tests the directory's names method");
}
ATF_TEST_CASE_BODY(directory_names)
{
using atf::fs::directory;
using atf::fs::path;
create_files();
directory d(path("files"));
std::set< std::string > ns = d.names();
ATF_REQUIRE_EQ(ns.size(), 4);
ATF_REQUIRE(ns.find(".") != ns.end());
ATF_REQUIRE(ns.find("..") != ns.end());
ATF_REQUIRE(ns.find("dir") != ns.end());
ATF_REQUIRE(ns.find("reg") != ns.end());
}
// ------------------------------------------------------------------------
// Test cases for the "file_info" class.
// ------------------------------------------------------------------------
ATF_TEST_CASE(file_info_stat);
ATF_TEST_CASE_HEAD(file_info_stat)
{
set_md_var("descr", "Tests the file_info creation and its basic contents");
}
ATF_TEST_CASE_BODY(file_info_stat)
{
using atf::fs::file_info;
using atf::fs::path;
create_files();
{
path p("files/dir");
file_info fi(p);
ATF_REQUIRE(fi.get_type() == file_info::dir_type);
}
{
path p("files/reg");
file_info fi(p);
ATF_REQUIRE(fi.get_type() == file_info::reg_type);
}
}
ATF_TEST_CASE(file_info_perms);
ATF_TEST_CASE_HEAD(file_info_perms)
{
set_md_var("descr", "Tests the file_info methods to get the file's "
"permissions");
}
ATF_TEST_CASE_BODY(file_info_perms)
{
using atf::fs::file_info;
using atf::fs::path;
path p("file");
std::ofstream os(p.c_str());
os.close();
#define perms(ur, uw, ux, gr, gw, gx, othr, othw, othx) \
{ \
file_info fi(p); \
ATF_REQUIRE(fi.is_owner_readable() == ur); \
ATF_REQUIRE(fi.is_owner_writable() == uw); \
ATF_REQUIRE(fi.is_owner_executable() == ux); \
ATF_REQUIRE(fi.is_group_readable() == gr); \
ATF_REQUIRE(fi.is_group_writable() == gw); \
ATF_REQUIRE(fi.is_group_executable() == gx); \
ATF_REQUIRE(fi.is_other_readable() == othr); \
ATF_REQUIRE(fi.is_other_writable() == othw); \
ATF_REQUIRE(fi.is_other_executable() == othx); \
}
::chmod(p.c_str(), 0000);
perms(false, false, false, false, false, false, false, false, false);
::chmod(p.c_str(), 0001);
perms(false, false, false, false, false, false, false, false, true);
::chmod(p.c_str(), 0010);
perms(false, false, false, false, false, true, false, false, false);
::chmod(p.c_str(), 0100);
perms(false, false, true, false, false, false, false, false, false);
::chmod(p.c_str(), 0002);
perms(false, false, false, false, false, false, false, true, false);
::chmod(p.c_str(), 0020);
perms(false, false, false, false, true, false, false, false, false);
::chmod(p.c_str(), 0200);
perms(false, true, false, false, false, false, false, false, false);
::chmod(p.c_str(), 0004);
perms(false, false, false, false, false, false, true, false, false);
::chmod(p.c_str(), 0040);
perms(false, false, false, true, false, false, false, false, false);
::chmod(p.c_str(), 0400);
perms(true, false, false, false, false, false, false, false, false);
::chmod(p.c_str(), 0644);
perms(true, true, false, true, false, false, true, false, false);
::chmod(p.c_str(), 0755);
perms(true, true, true, true, false, true, true, false, true);
::chmod(p.c_str(), 0777);
perms(true, true, true, true, true, true, true, true, true);
#undef perms
}
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(exists);
ATF_TEST_CASE_HEAD(exists)
{
set_md_var("descr", "Tests the exists function");
}
ATF_TEST_CASE_BODY(exists)
{
using atf::fs::exists;
using atf::fs::path;
create_files();
ATF_REQUIRE( exists(path("files")));
ATF_REQUIRE(!exists(path("file")));
ATF_REQUIRE(!exists(path("files2")));
ATF_REQUIRE( exists(path("files/.")));
ATF_REQUIRE( exists(path("files/..")));
ATF_REQUIRE( exists(path("files/dir")));
ATF_REQUIRE( exists(path("files/reg")));
ATF_REQUIRE(!exists(path("files/foo")));
}
ATF_TEST_CASE(is_executable);
ATF_TEST_CASE_HEAD(is_executable)
{
set_md_var("descr", "Tests the is_executable function");
}
ATF_TEST_CASE_BODY(is_executable)
{
using atf::fs::is_executable;
using atf::fs::path;
create_files();
ATF_REQUIRE( is_executable(path("files")));
ATF_REQUIRE( is_executable(path("files/.")));
ATF_REQUIRE( is_executable(path("files/..")));
ATF_REQUIRE( is_executable(path("files/dir")));
ATF_REQUIRE(!is_executable(path("non-existent")));
ATF_REQUIRE(!is_executable(path("files/reg")));
ATF_REQUIRE(::chmod("files/reg", 0755) != -1);
ATF_REQUIRE( is_executable(path("files/reg")));
}
ATF_TEST_CASE(remove);
ATF_TEST_CASE_HEAD(remove)
{
set_md_var("descr", "Tests the remove function");
}
ATF_TEST_CASE_BODY(remove)
{
using atf::fs::exists;
using atf::fs::path;
using atf::fs::remove;
create_files();
ATF_REQUIRE( exists(path("files/reg")));
remove(path("files/reg"));
ATF_REQUIRE(!exists(path("files/reg")));
ATF_REQUIRE( exists(path("files/dir")));
ATF_REQUIRE_THROW(atf::system_error, remove(path("files/dir")));
ATF_REQUIRE( exists(path("files/dir")));
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the tests for the "path" class.
ATF_ADD_TEST_CASE(tcs, path_normalize);
ATF_ADD_TEST_CASE(tcs, path_is_absolute);
ATF_ADD_TEST_CASE(tcs, path_is_root);
ATF_ADD_TEST_CASE(tcs, path_branch_path);
ATF_ADD_TEST_CASE(tcs, path_leaf_name);
ATF_ADD_TEST_CASE(tcs, path_compare_equal);
ATF_ADD_TEST_CASE(tcs, path_compare_different);
ATF_ADD_TEST_CASE(tcs, path_concat);
ATF_ADD_TEST_CASE(tcs, path_to_absolute);
ATF_ADD_TEST_CASE(tcs, path_op_less);
// Add the tests for the "file_info" class.
ATF_ADD_TEST_CASE(tcs, file_info_stat);
ATF_ADD_TEST_CASE(tcs, file_info_perms);
// Add the tests for the "directory" class.
ATF_ADD_TEST_CASE(tcs, directory_read);
ATF_ADD_TEST_CASE(tcs, directory_names);
ATF_ADD_TEST_CASE(tcs, directory_file_info);
// Add the tests for the free functions.
ATF_ADD_TEST_CASE(tcs, exists);
ATF_ADD_TEST_CASE(tcs, is_executable);
ATF_ADD_TEST_CASE(tcs, remove);
}

384
atf-c++/detail/parser.cpp Normal file
View File

@ -0,0 +1,384 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <sstream>
#include "parser.hpp"
#include "sanity.hpp"
#include "text.hpp"
namespace impl = atf::parser;
#define IMPL_NAME "atf::parser"
// ------------------------------------------------------------------------
// The "parse_error" class.
// ------------------------------------------------------------------------
impl::parse_error::parse_error(size_t line, std::string msg) :
std::runtime_error(msg),
std::pair< size_t, std::string >(line, msg)
{
}
impl::parse_error::~parse_error(void)
throw()
{
}
const char*
impl::parse_error::what(void)
const throw()
{
try {
std::ostringstream oss;
oss << "LONELY PARSE ERROR: " << first << ": " << second;
m_msg = oss.str();
return m_msg.c_str();
} catch (...) {
return "Could not format message for parsing error.";
}
}
impl::parse_error::operator std::string(void)
const
{
return atf::text::to_string(first) + ": " + second;
}
// ------------------------------------------------------------------------
// The "parse_errors" class.
// ------------------------------------------------------------------------
impl::parse_errors::parse_errors(void) :
std::runtime_error("No parsing errors yet")
{
m_msg.clear();
}
impl::parse_errors::~parse_errors(void)
throw()
{
}
const char*
impl::parse_errors::what(void)
const throw()
{
try {
m_msg = atf::text::join(*this, "\n");
return m_msg.c_str();
} catch (...) {
return "Could not format messages for parsing errors.";
}
}
// ------------------------------------------------------------------------
// The "format_error" class.
// ------------------------------------------------------------------------
impl::format_error::format_error(const std::string& w) :
std::runtime_error(w.c_str())
{
}
// ------------------------------------------------------------------------
// The "token" class.
// ------------------------------------------------------------------------
impl::token::token(void) :
m_inited(false)
{
}
impl::token::token(size_t p_line,
const token_type& p_type,
const std::string& p_text) :
m_inited(true),
m_line(p_line),
m_type(p_type),
m_text(p_text)
{
}
size_t
impl::token::lineno(void)
const
{
return m_line;
}
const impl::token_type&
impl::token::type(void)
const
{
return m_type;
}
const std::string&
impl::token::text(void)
const
{
return m_text;
}
impl::token::operator bool(void)
const
{
return m_inited;
}
bool
impl::token::operator!(void)
const
{
return !m_inited;
}
// ------------------------------------------------------------------------
// The "header_entry" class.
// ------------------------------------------------------------------------
impl::header_entry::header_entry(void)
{
}
impl::header_entry::header_entry(const std::string& n, const std::string& v,
attrs_map as) :
m_name(n),
m_value(v),
m_attrs(as)
{
}
const std::string&
impl::header_entry::name(void) const
{
return m_name;
}
const std::string&
impl::header_entry::value(void) const
{
return m_value;
}
const impl::attrs_map&
impl::header_entry::attrs(void) const
{
return m_attrs;
}
bool
impl::header_entry::has_attr(const std::string& n) const
{
return m_attrs.find(n) != m_attrs.end();
}
const std::string&
impl::header_entry::get_attr(const std::string& n) const
{
attrs_map::const_iterator iter = m_attrs.find(n);
PRE(iter != m_attrs.end());
return (*iter).second;
}
// ------------------------------------------------------------------------
// The header tokenizer.
// ------------------------------------------------------------------------
namespace header {
static const impl::token_type eof_type = 0;
static const impl::token_type nl_type = 1;
static const impl::token_type text_type = 2;
static const impl::token_type colon_type = 3;
static const impl::token_type semicolon_type = 4;
static const impl::token_type dblquote_type = 5;
static const impl::token_type equal_type = 6;
class tokenizer : public impl::tokenizer< std::istream > {
public:
tokenizer(std::istream& is, size_t curline) :
impl::tokenizer< std::istream >
(is, true, eof_type, nl_type, text_type, curline)
{
add_delim(';', semicolon_type);
add_delim(':', colon_type);
add_delim('=', equal_type);
add_quote('"', dblquote_type);
}
};
static
impl::parser< header::tokenizer >&
read(impl::parser< header::tokenizer >& p, impl::header_entry& he)
{
using namespace header;
impl::token t = p.expect(text_type, nl_type, "a header name");
if (t.type() == nl_type) {
he = impl::header_entry();
return p;
}
std::string hdr_name = t.text();
t = p.expect(colon_type, "`:'");
t = p.expect(text_type, "a textual value");
std::string hdr_value = t.text();
impl::attrs_map attrs;
for (;;) {
t = p.expect(eof_type, semicolon_type, nl_type,
"eof, `;' or new line");
if (t.type() == eof_type || t.type() == nl_type)
break;
t = p.expect(text_type, "an attribute name");
std::string attr_name = t.text();
t = p.expect(equal_type, "`='");
t = p.expect(text_type, "word or quoted string");
std::string attr_value = t.text();
attrs[attr_name] = attr_value;
}
he = impl::header_entry(hdr_name, hdr_value, attrs);
return p;
}
static
std::ostream&
write(std::ostream& os, const impl::header_entry& he)
{
std::string line = he.name() + ": " + he.value();
impl::attrs_map as = he.attrs();
for (impl::attrs_map::const_iterator iter = as.begin(); iter != as.end();
iter++) {
PRE((*iter).second.find('\"') == std::string::npos);
line += "; " + (*iter).first + "=\"" + (*iter).second + "\"";
}
os << line << "\n";
return os;
}
} // namespace header
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
std::pair< size_t, impl::headers_map >
impl::read_headers(std::istream& is, size_t curline)
{
using impl::format_error;
headers_map hm;
//
// Grammar
//
// header = entry+ nl
// entry = line nl
// line = text colon text
// (semicolon (text equal (text | dblquote string dblquote)))*
// string = quoted_string
//
header::tokenizer tkz(is, curline);
impl::parser< header::tokenizer > p(tkz);
bool first = true;
for (;;) {
try {
header_entry he;
if (!header::read(p, he).good() || he.name().empty())
break;
if (first && he.name() != "Content-Type")
throw format_error("Could not determine content type");
else
first = false;
hm[he.name()] = he;
} catch (const impl::parse_error& pe) {
p.add_error(pe);
p.reset(header::nl_type);
}
}
if (!is.good())
throw format_error("Unexpected end of stream");
return std::pair< size_t, headers_map >(tkz.lineno(), hm);
}
void
impl::write_headers(const impl::headers_map& hm, std::ostream& os)
{
PRE(!hm.empty());
headers_map::const_iterator ct = hm.find("Content-Type");
PRE(ct != hm.end());
header::write(os, (*ct).second);
for (headers_map::const_iterator iter = hm.begin(); iter != hm.end();
iter++) {
if ((*iter).first != "Content-Type")
header::write(os, (*iter).second);
}
os << "\n";
}
void
impl::validate_content_type(const impl::headers_map& hm, const std::string& fmt,
int version)
{
using impl::format_error;
headers_map::const_iterator iter = hm.find("Content-Type");
if (iter == hm.end())
throw format_error("Could not determine content type");
const header_entry& he = (*iter).second;
if (he.value() != fmt)
throw format_error("Mismatched content type: expected `" + fmt +
"' but got `" + he.value() + "'");
if (!he.has_attr("version"))
throw format_error("Could not determine version");
const std::string& vstr = atf::text::to_string(version);
if (he.get_attr("version") != vstr)
throw format_error("Mismatched version: expected `" +
vstr + "' but got `" +
he.get_attr("version") + "'");
}

607
atf-c++/detail/parser.hpp Normal file
View File

@ -0,0 +1,607 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_PARSER_HPP_)
#define _ATF_CXX_PARSER_HPP_
#include <istream>
#include <map>
#include <ostream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace atf {
namespace parser {
// ------------------------------------------------------------------------
// The "parse_error" class.
// ------------------------------------------------------------------------
class parse_error : public std::runtime_error,
public std::pair< size_t, std::string > {
mutable std::string m_msg;
public:
parse_error(size_t, std::string);
~parse_error(void) throw();
const char* what(void) const throw();
operator std::string(void) const;
};
// ------------------------------------------------------------------------
// The "parse_errors" class.
// ------------------------------------------------------------------------
class parse_errors : public std::runtime_error,
public std::vector< parse_error > {
std::vector< parse_error > m_errors;
mutable std::string m_msg;
public:
parse_errors(void);
~parse_errors(void) throw();
const char* what(void) const throw();
};
// ------------------------------------------------------------------------
// The "format_error" class.
// ------------------------------------------------------------------------
class format_error : public std::runtime_error {
public:
format_error(const std::string&);
};
// ------------------------------------------------------------------------
// The "token" class.
// ------------------------------------------------------------------------
typedef int token_type;
//!
//! \brief Representation of a read token.
//!
//! A pair that contains the information of a token read from a stream.
//! It contains the token's type and its associated data, if any.
//!
struct token {
bool m_inited;
size_t m_line;
token_type m_type;
std::string m_text;
public:
token(void);
token(size_t, const token_type&, const std::string& = "");
size_t lineno(void) const;
const token_type& type(void) const;
const std::string& text(void) const;
operator bool(void) const;
bool operator!(void) const;
};
// ------------------------------------------------------------------------
// The "tokenizer" class.
// ------------------------------------------------------------------------
//!
//! \brief A stream tokenizer.
//!
//! This template implements an extremely simple, line-oriented stream
//! tokenizer. It is only able to recognize one character-long delimiters,
//! random-length keywords, skip whitespace and, anything that does not
//! match these rules is supposed to be a word.
//!
//! Parameter IS: The input stream's type.
//!
template< class IS >
class tokenizer {
IS& m_is;
size_t m_lineno;
token m_la;
bool m_skipws;
token_type m_eof_type, m_nl_type, m_text_type;
std::map< char, token_type > m_delims_map;
std::string m_delims_str;
char m_quotech;
token_type m_quotetype;
std::map< std::string, token_type > m_keywords_map;
token_type alloc_type(void);
template< class TKZ >
friend
class parser;
public:
tokenizer(IS&, bool, const token_type&, const token_type&,
const token_type&, size_t = 1);
size_t lineno(void) const;
void add_delim(char, const token_type&);
void add_keyword(const std::string&, const token_type&);
void add_quote(char, const token_type&);
token next(void);
std::string rest_of_line(void);
};
template< class IS >
tokenizer< IS >::tokenizer(IS& p_is,
bool p_skipws,
const token_type& p_eof_type,
const token_type& p_nl_type,
const token_type& p_text_type,
size_t p_lineno) :
m_is(p_is),
m_lineno(p_lineno),
m_skipws(p_skipws),
m_eof_type(p_eof_type),
m_nl_type(p_nl_type),
m_text_type(p_text_type),
m_quotech(-1)
{
}
template< class IS >
size_t
tokenizer< IS >::lineno(void)
const
{
return m_lineno;
}
template< class IS >
void
tokenizer< IS >::add_delim(char delim, const token_type& type)
{
m_delims_map[delim] = type;
m_delims_str += delim;
}
template< class IS >
void
tokenizer< IS >::add_keyword(const std::string& keyword,
const token_type& type)
{
m_keywords_map[keyword] = type;
}
template< class IS >
void
tokenizer< IS >::add_quote(char ch, const token_type& type)
{
m_quotech = ch;
m_quotetype = type;
}
template< class IS >
token
tokenizer< IS >::next(void)
{
if (m_la) {
token t = m_la;
m_la = token();
if (t.type() == m_nl_type)
m_lineno++;
return t;
}
char ch;
std::string text;
bool done = false, quoted = false;
token t(m_lineno, m_eof_type, "<<EOF>>");
while (!done && m_is.get(ch).good()) {
if (ch == m_quotech) {
if (text.empty()) {
bool escaped = false;
while (!done && m_is.get(ch).good()) {
if (!escaped) {
if (ch == '\\')
escaped = true;
else if (ch == '\n') {
m_la = token(m_lineno, m_nl_type, "<<NEWLINE>>");
throw parse_error(t.lineno(),
"Missing double quotes before "
"end of line");
} else if (ch == m_quotech)
done = true;
else
text += ch;
} else {
text += ch;
escaped = false;
}
}
if (!m_is.good())
throw parse_error(t.lineno(),
"Missing double quotes before "
"end of file");
t = token(m_lineno, m_text_type, text);
quoted = true;
} else {
m_is.unget();
done = true;
}
} else {
typename std::map< char, token_type >::const_iterator idelim;
idelim = m_delims_map.find(ch);
if (idelim != m_delims_map.end()) {
done = true;
if (text.empty())
t = token(m_lineno, (*idelim).second,
std::string("") + ch);
else
m_is.unget();
} else if (ch == '\n') {
done = true;
if (text.empty())
t = token(m_lineno, m_nl_type, "<<NEWLINE>>");
else
m_is.unget();
} else if (m_skipws && (ch == ' ' || ch == '\t')) {
if (!text.empty())
done = true;
} else
text += ch;
}
}
if (!quoted && !text.empty()) {
typename std::map< std::string, token_type >::const_iterator ikw;
ikw = m_keywords_map.find(text);
if (ikw != m_keywords_map.end())
t = token(m_lineno, (*ikw).second, text);
else
t = token(m_lineno, m_text_type, text);
}
if (t.type() == m_nl_type)
m_lineno++;
return t;
}
template< class IS >
std::string
tokenizer< IS >::rest_of_line(void)
{
std::string str;
while (m_is.good() && m_is.peek() != '\n')
str += m_is.get();
return str;
}
// ------------------------------------------------------------------------
// The "parser" class.
// ------------------------------------------------------------------------
template< class TKZ >
class parser {
TKZ& m_tkz;
token m_last;
parse_errors m_errors;
bool m_thrown;
public:
parser(TKZ& tkz);
~parser(void);
bool good(void) const;
void add_error(const parse_error&);
bool has_errors(void) const;
token next(void);
std::string rest_of_line(void);
token reset(const token_type&);
token
expect(const token_type&,
const std::string&);
token
expect(const token_type&,
const token_type&,
const std::string&);
token
expect(const token_type&,
const token_type&,
const token_type&,
const std::string&);
token
expect(const token_type&,
const token_type&,
const token_type&,
const token_type&,
const std::string&);
token
expect(const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const std::string&);
token
expect(const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const token_type&,
const std::string&);
};
template< class TKZ >
parser< TKZ >::parser(TKZ& tkz) :
m_tkz(tkz),
m_thrown(false)
{
}
template< class TKZ >
parser< TKZ >::~parser(void)
{
if (!m_errors.empty() && !m_thrown)
throw m_errors;
}
template< class TKZ >
bool
parser< TKZ >::good(void)
const
{
return m_tkz.m_is.good();
}
template< class TKZ >
void
parser< TKZ >::add_error(const parse_error& pe)
{
m_errors.push_back(pe);
}
template< class TKZ >
bool
parser< TKZ >::has_errors(void)
const
{
return !m_errors.empty();
}
template< class TKZ >
token
parser< TKZ >::next(void)
{
token t = m_tkz.next();
m_last = t;
if (t.type() == m_tkz.m_eof_type) {
if (!m_errors.empty()) {
m_thrown = true;
throw m_errors;
}
}
return t;
}
template< class TKZ >
std::string
parser< TKZ >::rest_of_line(void)
{
return m_tkz.rest_of_line();
}
template< class TKZ >
token
parser< TKZ >::reset(const token_type& stop)
{
token t = m_last;
while (t.type() != m_tkz.m_eof_type && t.type() != stop)
t = next();
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const std::string& textual)
{
token t = next();
if (t.type() != t1)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const token_type& t2,
const std::string& textual)
{
token t = next();
if (t.type() != t1 && t.type() != t2)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const token_type& t2,
const token_type& t3,
const std::string& textual)
{
token t = next();
if (t.type() != t1 && t.type() != t2 && t.type() != t3)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const token_type& t2,
const token_type& t3,
const token_type& t4,
const std::string& textual)
{
token t = next();
if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
t.type() != t4)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const token_type& t2,
const token_type& t3,
const token_type& t4,
const token_type& t5,
const token_type& t6,
const token_type& t7,
const std::string& textual)
{
token t = next();
if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
t.type() != t4 && t.type() != t5 && t.type() != t6 &&
t.type() != t7)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
template< class TKZ >
token
parser< TKZ >::expect(const token_type& t1,
const token_type& t2,
const token_type& t3,
const token_type& t4,
const token_type& t5,
const token_type& t6,
const token_type& t7,
const token_type& t8,
const std::string& textual)
{
token t = next();
if (t.type() != t1 && t.type() != t2 && t.type() != t3 &&
t.type() != t4 && t.type() != t5 && t.type() != t6 &&
t.type() != t7 && t.type() != t8)
throw parse_error(t.lineno(),
"Unexpected token `" + t.text() +
"'; expected " + textual);
return t;
}
#define ATF_PARSER_CALLBACK(parser, func) \
do { \
if (!(parser).has_errors()) \
func; \
} while (false)
// ------------------------------------------------------------------------
// Header parsing.
// ------------------------------------------------------------------------
typedef std::map< std::string, std::string > attrs_map;
class header_entry {
std::string m_name;
std::string m_value;
attrs_map m_attrs;
public:
header_entry(void);
header_entry(const std::string&, const std::string&,
attrs_map = attrs_map());
const std::string& name(void) const;
const std::string& value(void) const;
const attrs_map& attrs(void) const;
bool has_attr(const std::string&) const;
const std::string& get_attr(const std::string&) const;
};
typedef std::map< std::string, header_entry > headers_map;
std::pair< size_t, headers_map > read_headers(std::istream&, size_t);
void write_headers(const headers_map&, std::ostream&);
void validate_content_type(const headers_map&, const std::string&, int);
} // namespace parser
} // namespace atf
#endif // !defined(_ATF_CXX_PARSER_HPP_)

File diff suppressed because it is too large Load Diff

355
atf-c++/detail/process.cpp Normal file
View File

@ -0,0 +1,355 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <signal.h>
#include "../../atf-c/error.h"
#include "../../atf-c/detail/process.h"
}
#include <iostream>
#include "exceptions.hpp"
#include "process.hpp"
#include "sanity.hpp"
namespace detail = atf::process::detail;
namespace impl = atf::process;
#define IMPL_NAME "atf::process"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
template< class C >
atf::utils::auto_array< const char* >
collection_to_argv(const C& c)
{
atf::utils::auto_array< const char* > argv(new const char*[c.size() + 1]);
std::size_t pos = 0;
for (typename C::const_iterator iter = c.begin(); iter != c.end();
iter++) {
argv[pos] = (*iter).c_str();
pos++;
}
INV(pos == c.size());
argv[pos] = NULL;
return argv;
}
template< class C >
C
argv_to_collection(const char* const* argv)
{
C c;
for (const char* const* iter = argv; *iter != NULL; iter++)
c.push_back(std::string(*iter));
return c;
}
// ------------------------------------------------------------------------
// The "argv_array" type.
// ------------------------------------------------------------------------
impl::argv_array::argv_array(void) :
m_exec_argv(collection_to_argv(m_args))
{
}
impl::argv_array::argv_array(const char* arg1, ...)
{
m_args.push_back(arg1);
{
va_list ap;
const char* nextarg;
va_start(ap, arg1);
while ((nextarg = va_arg(ap, const char*)) != NULL)
m_args.push_back(nextarg);
va_end(ap);
}
ctor_init_exec_argv();
}
impl::argv_array::argv_array(const char* const* ca) :
m_args(argv_to_collection< args_vector >(ca)),
m_exec_argv(collection_to_argv(m_args))
{
}
impl::argv_array::argv_array(const argv_array& a) :
m_args(a.m_args),
m_exec_argv(collection_to_argv(m_args))
{
}
void
impl::argv_array::ctor_init_exec_argv(void)
{
m_exec_argv = collection_to_argv(m_args);
}
const char* const*
impl::argv_array::exec_argv(void)
const
{
return m_exec_argv.get();
}
impl::argv_array::size_type
impl::argv_array::size(void)
const
{
return m_args.size();
}
const char*
impl::argv_array::operator[](int idx)
const
{
return m_args[idx].c_str();
}
impl::argv_array::const_iterator
impl::argv_array::begin(void)
const
{
return m_args.begin();
}
impl::argv_array::const_iterator
impl::argv_array::end(void)
const
{
return m_args.end();
}
impl::argv_array&
impl::argv_array::operator=(const argv_array& a)
{
if (this != &a) {
m_args = a.m_args;
m_exec_argv = collection_to_argv(m_args);
}
return *this;
}
// ------------------------------------------------------------------------
// The "stream" types.
// ------------------------------------------------------------------------
impl::basic_stream::basic_stream(void) :
m_inited(false)
{
}
impl::basic_stream::~basic_stream(void)
{
if (m_inited)
atf_process_stream_fini(&m_sb);
}
const atf_process_stream_t*
impl::basic_stream::get_sb(void)
const
{
INV(m_inited);
return &m_sb;
}
impl::stream_capture::stream_capture(void)
{
atf_error_t err = atf_process_stream_init_capture(&m_sb);
if (atf_is_error(err))
throw_atf_error(err);
m_inited = true;
}
impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
{
atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
if (atf_is_error(err))
throw_atf_error(err);
m_inited = true;
}
impl::stream_inherit::stream_inherit(void)
{
atf_error_t err = atf_process_stream_init_inherit(&m_sb);
if (atf_is_error(err))
throw_atf_error(err);
m_inited = true;
}
impl::stream_redirect_fd::stream_redirect_fd(const int fd)
{
atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
if (atf_is_error(err))
throw_atf_error(err);
m_inited = true;
}
impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
{
atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
if (atf_is_error(err))
throw_atf_error(err);
m_inited = true;
}
// ------------------------------------------------------------------------
// The "status" type.
// ------------------------------------------------------------------------
impl::status::status(atf_process_status_t& s) :
m_status(s)
{
}
impl::status::~status(void)
{
atf_process_status_fini(&m_status);
}
bool
impl::status::exited(void)
const
{
return atf_process_status_exited(&m_status);
}
int
impl::status::exitstatus(void)
const
{
return atf_process_status_exitstatus(&m_status);
}
bool
impl::status::signaled(void)
const
{
return atf_process_status_signaled(&m_status);
}
int
impl::status::termsig(void)
const
{
return atf_process_status_termsig(&m_status);
}
bool
impl::status::coredump(void)
const
{
return atf_process_status_coredump(&m_status);
}
// ------------------------------------------------------------------------
// The "child" type.
// ------------------------------------------------------------------------
impl::child::child(atf_process_child_t& c) :
m_child(c),
m_waited(false)
{
}
impl::child::~child(void)
{
if (!m_waited) {
::kill(atf_process_child_pid(&m_child), SIGTERM);
atf_process_status_t s;
atf_error_t err = atf_process_child_wait(&m_child, &s);
INV(!atf_is_error(err));
atf_process_status_fini(&s);
}
}
impl::status
impl::child::wait(void)
{
atf_process_status_t s;
atf_error_t err = atf_process_child_wait(&m_child, &s);
if (atf_is_error(err))
throw_atf_error(err);
m_waited = true;
return status(s);
}
pid_t
impl::child::pid(void)
const
{
return atf_process_child_pid(&m_child);
}
int
impl::child::stdout_fd(void)
{
return atf_process_child_stdout(&m_child);
}
int
impl::child::stderr_fd(void)
{
return atf_process_child_stderr(&m_child);
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
void
detail::flush_streams(void)
{
// This is a weird hack to ensure that the output of the parent process
// is flushed before executing a child which prevents, for example, the
// output of the atf-run hooks to appear before the output of atf-run
// itself.
//
// TODO: This should only be executed when inheriting the stdout or
// stderr file descriptors. However, the flushing is specific to the
// iostreams, so we cannot do it from the C library where all the process
// logic is performed. Come up with a better design.
std::cout.flush();
std::cerr.flush();
}

280
atf-c++/detail/process.hpp Normal file
View File

@ -0,0 +1,280 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_PROCESS_HPP_)
#define _ATF_CXX_PROCESS_HPP_
extern "C" {
#include <sys/types.h>
#include "../../atf-c/error.h"
#include "../../atf-c/detail/process.h"
}
#include <string>
#include <vector>
#include "exceptions.hpp"
#include "fs.hpp"
#include "../utils.hpp"
namespace atf {
namespace process {
class child;
class status;
// ------------------------------------------------------------------------
// The "argv_array" type.
// ------------------------------------------------------------------------
class argv_array {
typedef std::vector< std::string > args_vector;
args_vector m_args;
// TODO: This is immutable, so we should be able to use
// std::tr1::shared_array instead when it becomes widely available.
// The reason would be to remove all copy constructors and assignment
// operators from this class.
utils::auto_array< const char* > m_exec_argv;
void ctor_init_exec_argv(void);
public:
typedef args_vector::const_iterator const_iterator;
typedef args_vector::size_type size_type;
argv_array(void);
argv_array(const char*, ...);
explicit argv_array(const char* const*);
template< class C > explicit argv_array(const C&);
argv_array(const argv_array&);
const char* const* exec_argv(void) const;
size_type size(void) const;
const char* operator[](int) const;
const_iterator begin(void) const;
const_iterator end(void) const;
argv_array& operator=(const argv_array&);
};
template< class C >
argv_array::argv_array(const C& c)
{
for (typename C::const_iterator iter = c.begin(); iter != c.end();
iter++)
m_args.push_back(*iter);
ctor_init_exec_argv();
}
// ------------------------------------------------------------------------
// The "stream" types.
// ------------------------------------------------------------------------
class basic_stream {
protected:
atf_process_stream_t m_sb;
bool m_inited;
const atf_process_stream_t* get_sb(void) const;
public:
basic_stream(void);
~basic_stream(void);
};
class stream_capture : basic_stream {
// Allow access to the getters.
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
public:
stream_capture(void);
};
class stream_connect : basic_stream {
// Allow access to the getters.
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
public:
stream_connect(const int, const int);
};
class stream_inherit : basic_stream {
// Allow access to the getters.
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
public:
stream_inherit(void);
};
class stream_redirect_fd : basic_stream {
// Allow access to the getters.
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
public:
stream_redirect_fd(const int);
};
class stream_redirect_path : basic_stream {
// Allow access to the getters.
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
public:
stream_redirect_path(const fs::path&);
};
// ------------------------------------------------------------------------
// The "status" type.
// ------------------------------------------------------------------------
class status {
atf_process_status_t m_status;
friend class child;
template< class OutStream, class ErrStream > friend
status exec(const atf::fs::path&, const argv_array&,
const OutStream&, const ErrStream&, void (*)(void));
status(atf_process_status_t&);
public:
~status(void);
bool exited(void) const;
int exitstatus(void) const;
bool signaled(void) const;
int termsig(void) const;
bool coredump(void) const;
};
// ------------------------------------------------------------------------
// The "child" type.
// ------------------------------------------------------------------------
class child {
atf_process_child_t m_child;
bool m_waited;
template< class OutStream, class ErrStream > friend
child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
child(atf_process_child_t& c);
public:
~child(void);
status wait(void);
pid_t pid(void) const;
int stdout_fd(void);
int stderr_fd(void);
};
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
namespace detail {
void flush_streams(void);
} // namespace detail
// TODO: The void* cookie can probably be templatized, thus also allowing
// const data structures.
template< class OutStream, class ErrStream >
child
fork(void (*start)(void*), const OutStream& outsb,
const ErrStream& errsb, void* v)
{
atf_process_child_t c;
detail::flush_streams();
atf_error_t err = atf_process_fork(&c, start, outsb.get_sb(),
errsb.get_sb(), v);
if (atf_is_error(err))
throw_atf_error(err);
return child(c);
}
template< class OutStream, class ErrStream >
status
exec(const atf::fs::path& prog, const argv_array& argv,
const OutStream& outsb, const ErrStream& errsb,
void (*prehook)(void))
{
atf_process_status_t s;
detail::flush_streams();
atf_error_t err = atf_process_exec_array(&s, prog.c_path(),
argv.exec_argv(),
outsb.get_sb(),
errsb.get_sb(),
prehook);
if (atf_is_error(err))
throw_atf_error(err);
return status(s);
}
template< class OutStream, class ErrStream >
status
exec(const atf::fs::path& prog, const argv_array& argv,
const OutStream& outsb, const ErrStream& errsb)
{
return exec(prog, argv, outsb, errsb, NULL);
}
} // namespace process
} // namespace atf
#endif // !defined(_ATF_CXX_PROCESS_HPP_)

View File

@ -0,0 +1,357 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstdlib>
#include <cstring>
#include "../macros.hpp"
#include "process.hpp"
#include "test_helpers.hpp"
// TODO: Testing the fork function is a huge task and I'm afraid of
// copy/pasting tons of stuff from the C version. I'd rather not do that
// until some code can be shared, which cannot happen until the C++ binding
// is cleaned by a fair amount. Instead... just rely (at the moment) on
// the system tests for the tools using this module.
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
static
std::size_t
array_size(const char* const* array)
{
std::size_t size = 0;
for (const char* const* ptr = array; *ptr != NULL; ptr++)
size++;
return size;
}
static
atf::process::status
exec_process_helpers(const atf::tests::tc& tc, const char* helper_name)
{
using atf::process::exec;
std::vector< std::string > argv;
argv.push_back(get_process_helpers_path(tc).leaf_name());
argv.push_back(helper_name);
return exec(get_process_helpers_path(tc),
atf::process::argv_array(argv),
atf::process::stream_inherit(),
atf::process::stream_inherit());
}
// ------------------------------------------------------------------------
// Tests for the "argv_array" type.
// ------------------------------------------------------------------------
ATF_TEST_CASE(argv_array_init_carray);
ATF_TEST_CASE_HEAD(argv_array_init_carray)
{
set_md_var("descr", "Tests that argv_array is correctly constructed "
"from a C-style array of strings");
}
ATF_TEST_CASE_BODY(argv_array_init_carray)
{
{
const char* const carray[] = { NULL };
atf::process::argv_array argv(carray);
ATF_REQUIRE_EQ(argv.size(), 0);
}
{
const char* const carray[] = { "arg0", NULL };
atf::process::argv_array argv(carray);
ATF_REQUIRE_EQ(argv.size(), 1);
ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
}
{
const char* const carray[] = { "arg0", "arg1", "arg2", NULL };
atf::process::argv_array argv(carray);
ATF_REQUIRE_EQ(argv.size(), 3);
ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
ATF_REQUIRE(std::strcmp(argv[1], carray[1]) == 0);
ATF_REQUIRE(std::strcmp(argv[2], carray[2]) == 0);
}
}
ATF_TEST_CASE(argv_array_init_col);
ATF_TEST_CASE_HEAD(argv_array_init_col)
{
set_md_var("descr", "Tests that argv_array is correctly constructed "
"from a string collection");
}
ATF_TEST_CASE_BODY(argv_array_init_col)
{
{
std::vector< std::string > col;
atf::process::argv_array argv(col);
ATF_REQUIRE_EQ(argv.size(), 0);
}
{
std::vector< std::string > col;
col.push_back("arg0");
atf::process::argv_array argv(col);
ATF_REQUIRE_EQ(argv.size(), 1);
ATF_REQUIRE_EQ(argv[0], col[0]);
}
{
std::vector< std::string > col;
col.push_back("arg0");
col.push_back("arg1");
col.push_back("arg2");
atf::process::argv_array argv(col);
ATF_REQUIRE_EQ(argv.size(), 3);
ATF_REQUIRE_EQ(argv[0], col[0]);
ATF_REQUIRE_EQ(argv[1], col[1]);
ATF_REQUIRE_EQ(argv[2], col[2]);
}
}
ATF_TEST_CASE(argv_array_init_empty);
ATF_TEST_CASE_HEAD(argv_array_init_empty)
{
set_md_var("descr", "Tests that argv_array is correctly constructed "
"by the default constructor");
}
ATF_TEST_CASE_BODY(argv_array_init_empty)
{
atf::process::argv_array argv;
ATF_REQUIRE_EQ(argv.size(), 0);
}
ATF_TEST_CASE(argv_array_init_varargs);
ATF_TEST_CASE_HEAD(argv_array_init_varargs)
{
set_md_var("descr", "Tests that argv_array is correctly constructed "
"from a variable list of arguments");
}
ATF_TEST_CASE_BODY(argv_array_init_varargs)
{
{
atf::process::argv_array argv("arg0", NULL);
ATF_REQUIRE_EQ(argv.size(), 1);
ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
}
{
atf::process::argv_array argv("arg0", "arg1", "arg2", NULL);
ATF_REQUIRE_EQ(argv.size(), 3);
ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
ATF_REQUIRE_EQ(argv[1], std::string("arg1"));
ATF_REQUIRE_EQ(argv[2], std::string("arg2"));
}
}
ATF_TEST_CASE(argv_array_assign);
ATF_TEST_CASE_HEAD(argv_array_assign)
{
set_md_var("descr", "Tests that assigning an argv_array works");
}
ATF_TEST_CASE_BODY(argv_array_assign)
{
using atf::process::argv_array;
const char* const carray1[] = { "arg1", NULL };
const char* const carray2[] = { "arg1", "arg2", NULL };
std::auto_ptr< argv_array > argv1(new argv_array(carray1));
std::auto_ptr< argv_array > argv2(new argv_array(carray2));
*argv2 = *argv1;
ATF_REQUIRE_EQ(argv2->size(), argv1->size());
ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
argv1.release();
{
const char* const* eargv2 = argv2->exec_argv();
ATF_REQUIRE(std::strcmp(eargv2[0], carray1[0]) == 0);
ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
}
argv2.release();
}
ATF_TEST_CASE(argv_array_copy);
ATF_TEST_CASE_HEAD(argv_array_copy)
{
set_md_var("descr", "Tests that copying an argv_array constructed from "
"a C-style array of strings works");
}
ATF_TEST_CASE_BODY(argv_array_copy)
{
using atf::process::argv_array;
const char* const carray[] = { "arg0", NULL };
std::auto_ptr< argv_array > argv1(new argv_array(carray));
std::auto_ptr< argv_array > argv2(new argv_array(*argv1));
ATF_REQUIRE_EQ(argv2->size(), argv1->size());
ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
argv1.release();
{
const char* const* eargv2 = argv2->exec_argv();
ATF_REQUIRE(std::strcmp(eargv2[0], carray[0]) == 0);
ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
}
argv2.release();
}
ATF_TEST_CASE(argv_array_exec_argv);
ATF_TEST_CASE_HEAD(argv_array_exec_argv)
{
set_md_var("descr", "Tests that the exec argv provided by an argv_array "
"is correct");
}
ATF_TEST_CASE_BODY(argv_array_exec_argv)
{
using atf::process::argv_array;
{
argv_array argv;
const char* const* eargv = argv.exec_argv();
ATF_REQUIRE_EQ(array_size(eargv), 0);
ATF_REQUIRE_EQ(eargv[0], static_cast< const char* >(NULL));
}
{
const char* const carray[] = { "arg0", NULL };
argv_array argv(carray);
const char* const* eargv = argv.exec_argv();
ATF_REQUIRE_EQ(array_size(eargv), 1);
ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
}
{
std::vector< std::string > col;
col.push_back("arg0");
argv_array argv(col);
const char* const* eargv = argv.exec_argv();
ATF_REQUIRE_EQ(array_size(eargv), 1);
ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
}
}
ATF_TEST_CASE(argv_array_iter);
ATF_TEST_CASE_HEAD(argv_array_iter)
{
set_md_var("descr", "Tests that an argv_array can be iterated");
}
ATF_TEST_CASE_BODY(argv_array_iter)
{
using atf::process::argv_array;
std::vector< std::string > vector;
vector.push_back("arg0");
vector.push_back("arg1");
vector.push_back("arg2");
argv_array argv(vector);
ATF_REQUIRE_EQ(argv.size(), 3);
std::vector< std::string >::size_type pos = 0;
for (argv_array::const_iterator iter = argv.begin(); iter != argv.end();
iter++) {
ATF_REQUIRE_EQ(*iter, vector[pos]);
pos++;
}
}
// ------------------------------------------------------------------------
// Tests cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(exec_failure);
ATF_TEST_CASE_HEAD(exec_failure)
{
set_md_var("descr", "Tests execing a command that reports failure");
}
ATF_TEST_CASE_BODY(exec_failure)
{
const atf::process::status s = exec_process_helpers(*this, "exit-failure");
ATF_REQUIRE(s.exited());
ATF_REQUIRE_EQ(s.exitstatus(), EXIT_FAILURE);
}
ATF_TEST_CASE(exec_success);
ATF_TEST_CASE_HEAD(exec_success)
{
set_md_var("descr", "Tests execing a command that reports success");
}
ATF_TEST_CASE_BODY(exec_success)
{
const atf::process::status s = exec_process_helpers(*this, "exit-success");
ATF_REQUIRE(s.exited());
ATF_REQUIRE_EQ(s.exitstatus(), EXIT_SUCCESS);
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the "argv_array" type.
ATF_ADD_TEST_CASE(tcs, argv_array_assign);
ATF_ADD_TEST_CASE(tcs, argv_array_copy);
ATF_ADD_TEST_CASE(tcs, argv_array_exec_argv);
ATF_ADD_TEST_CASE(tcs, argv_array_init_carray);
ATF_ADD_TEST_CASE(tcs, argv_array_init_col);
ATF_ADD_TEST_CASE(tcs, argv_array_init_empty);
ATF_ADD_TEST_CASE(tcs, argv_array_init_varargs);
ATF_ADD_TEST_CASE(tcs, argv_array_iter);
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, exec_failure);
ATF_ADD_TEST_CASE(tcs, exec_success);
}

37
atf-c++/detail/sanity.hpp Normal file
View File

@ -0,0 +1,37 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_SANITY_HPP_)
#define _ATF_CXX_SANITY_HPP_
extern "C" {
#include "../../atf-c/detail/sanity.h"
}
#endif // !defined(_ATF_CXX_SANITY_HPP_)

View File

@ -0,0 +1,41 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "../macros.hpp"
ATF_TEST_CASE_WITHOUT_HEAD(nothing);
ATF_TEST_CASE_BODY(nothing)
{
// TODO
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, nothing);
}

View File

@ -0,0 +1,160 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <regex.h>
}
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "../check.hpp"
#include "../config.hpp"
#include "../macros.hpp"
#include "fs.hpp"
#include "process.hpp"
#include "test_helpers.hpp"
void
build_check_cxx_o_aux(const atf::fs::path& sfile, const char* failmsg,
const bool expect_pass)
{
std::vector< std::string > optargs;
optargs.push_back("-I" + atf::config::get("atf_includedir"));
optargs.push_back("-Wall");
optargs.push_back("-Werror");
const bool result = atf::check::build_cxx_o(
sfile.str(), "test.o", atf::process::argv_array(optargs));
if ((expect_pass && !result) || (!expect_pass && result))
ATF_FAIL(failmsg);
}
void
build_check_cxx_o(const atf::tests::tc& tc, const char* sfile,
const char* failmsg, const bool expect_pass)
{
const atf::fs::path sfilepath =
atf::fs::path(tc.get_config_var("srcdir")) / sfile;
build_check_cxx_o_aux(sfilepath, failmsg, expect_pass);
}
void
header_check(const char *hdrname)
{
std::ofstream srcfile("test.c");
ATF_REQUIRE(srcfile);
srcfile << "#include <" << hdrname << ">\n";
srcfile.close();
const std::string failmsg = std::string("Header check failed; ") +
hdrname + " is not self-contained";
build_check_cxx_o_aux(atf::fs::path("test.c"), failmsg.c_str(), true);
}
atf::fs::path
get_process_helpers_path(const atf::tests::tc& tc)
{
return atf::fs::path(tc.get_config_var("srcdir")) /
".." / "atf-c" / "detail" / "process_helpers";
}
bool
grep_file(const char* name, const char* regex)
{
std::ifstream is(name);
ATF_REQUIRE(is);
bool found = false;
std::string line;
std::getline(is, line);
while (!found && is.good()) {
if (grep_string(line, regex))
found = true;
else
std::getline(is, line);
}
return found;
}
bool
grep_string(const std::string& str, const char* regex)
{
int res;
regex_t preg;
std::cout << "Looking for '" << regex << "' in '" << str << "'\n";
ATF_REQUIRE(::regcomp(&preg, regex, REG_EXTENDED) == 0);
res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
ATF_REQUIRE(res == 0 || res == REG_NOMATCH);
::regfree(&preg);
return res == 0;
}
void
test_helpers_detail::check_equal(const char* expected[],
const string_vector& actual)
{
const char** expected_iter = expected;
string_vector::const_iterator actual_iter = actual.begin();
bool equals = true;
while (equals && *expected_iter != NULL && actual_iter != actual.end()) {
if (*expected_iter != *actual_iter) {
equals = false;
} else {
expected_iter++;
actual_iter++;
}
}
if (equals && ((*expected_iter == NULL && actual_iter != actual.end()) ||
(*expected_iter != NULL && actual_iter == actual.end())))
equals = false;
if (!equals) {
std::cerr << "EXPECTED:\n";
for (expected_iter = expected; *expected_iter != NULL; expected_iter++)
std::cerr << *expected_iter << "\n";
std::cerr << "ACTUAL:\n";
for (actual_iter = actual.begin(); actual_iter != actual.end();
actual_iter++)
std::cerr << *actual_iter << "\n";
ATF_FAIL("Expected results differ to actual values");
}
}

View File

@ -0,0 +1,166 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if defined(TESTS_ATF_ATF_CXX_TEST_HELPERS_H)
# error "Cannot include test_helpers.hpp more than once."
#else
# define TESTS_ATF_ATF_CXX_TEST_HELPERS_H
#endif
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <utility>
#include "../macros.hpp"
#include "../tests.hpp"
#include "parser.hpp"
#include "process.hpp"
#include "text.hpp"
#define HEADER_TC(name, hdrname) \
ATF_TEST_CASE(name); \
ATF_TEST_CASE_HEAD(name) \
{ \
set_md_var("descr", "Tests that the " hdrname " file can be " \
"included on its own, without any prerequisites"); \
} \
ATF_TEST_CASE_BODY(name) \
{ \
header_check(hdrname); \
}
#define BUILD_TC(name, sfile, descr, failmsg) \
ATF_TEST_CASE(name); \
ATF_TEST_CASE_HEAD(name) \
{ \
set_md_var("descr", descr); \
} \
ATF_TEST_CASE_BODY(name) \
{ \
build_check_cxx_o(*this, sfile, failmsg, true); \
}
#define BUILD_TC_FAIL(name, sfile, descr, failmsg) \
ATF_TEST_CASE(name); \
ATF_TEST_CASE_HEAD(name) \
{ \
set_md_var("descr", descr); \
} \
ATF_TEST_CASE_BODY(name) \
{ \
build_check_cxx_o(*this, sfile, failmsg, false); \
}
namespace atf {
namespace tests {
class tc;
}
}
void header_check(const char*);
void build_check_cxx_o(const atf::tests::tc&, const char*, const char*, bool);
atf::fs::path get_process_helpers_path(const atf::tests::tc&);
bool grep_file(const char*, const char*);
bool grep_string(const std::string&, const char*);
struct run_h_tc_data {
const atf::tests::vars_map& m_config;
run_h_tc_data(const atf::tests::vars_map& config) :
m_config(config) {}
};
template< class TestCase >
void
run_h_tc_child(void* v)
{
run_h_tc_data* data = static_cast< run_h_tc_data* >(v);
TestCase tc;
tc.init(data->m_config);
tc.run("result");
std::exit(EXIT_SUCCESS);
}
template< class TestCase >
void
run_h_tc(atf::tests::vars_map config = atf::tests::vars_map())
{
run_h_tc_data data(config);
atf::process::child c = atf::process::fork(
run_h_tc_child< TestCase >,
atf::process::stream_redirect_path(atf::fs::path("stdout")),
atf::process::stream_redirect_path(atf::fs::path("stderr")),
&data);
const atf::process::status s = c.wait();
ATF_REQUIRE(s.exited());
}
namespace test_helpers_detail {
typedef std::vector< std::string > string_vector;
template< class Reader >
std::pair< string_vector, string_vector >
do_read(const char* input)
{
string_vector errors;
std::istringstream is(input);
Reader reader(is);
try {
reader.read();
} catch (const atf::parser::parse_errors& pes) {
for (std::vector< atf::parser::parse_error >::const_iterator iter =
pes.begin(); iter != pes.end(); iter++)
errors.push_back(*iter);
} catch (const atf::parser::parse_error& pe) {
ATF_FAIL("Raised a lonely parse error: " +
atf::text::to_string(pe.first) + ": " + pe.second);
}
return std::make_pair(reader.m_calls, errors);
}
void check_equal(const char*[], const string_vector&);
} // namespace test_helpers_detail
template< class Reader >
void
do_parser_test(const char* input, const char* exp_calls[],
const char* exp_errors[])
{
const std::pair< test_helpers_detail::string_vector,
test_helpers_detail::string_vector >
actual = test_helpers_detail::do_read< Reader >(input);
test_helpers_detail::check_equal(exp_calls, actual.first);
test_helpers_detail::check_equal(exp_errors, actual.second);
}

160
atf-c++/detail/text.cpp Normal file
View File

@ -0,0 +1,160 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <regex.h>
}
#include <cctype>
#include <cstring>
extern "C" {
#include "../../atf-c/error.h"
#include "../../atf-c/detail/text.h"
}
#include "exceptions.hpp"
#include "text.hpp"
namespace impl = atf::text;
#define IMPL_NAME "atf::text"
char*
impl::duplicate(const char* str)
{
char* copy = new char[std::strlen(str) + 1];
std::strcpy(copy, str);
return copy;
}
bool
impl::match(const std::string& str, const std::string& regex)
{
bool found;
// Special case: regcomp does not like empty regular expressions.
if (regex.empty()) {
found = str.empty();
} else {
::regex_t preg;
if (::regcomp(&preg, regex.c_str(), REG_EXTENDED) != 0)
throw std::runtime_error("Invalid regular expression '" + regex +
"'");
const int res = ::regexec(&preg, str.c_str(), 0, NULL, 0);
regfree(&preg);
if (res != 0 && res != REG_NOMATCH)
throw std::runtime_error("Invalid regular expression " + regex);
found = res == 0;
}
return found;
}
std::string
impl::to_lower(const std::string& str)
{
std::string lc;
for (std::string::const_iterator iter = str.begin(); iter != str.end();
iter++)
lc += std::tolower(*iter);
return lc;
}
std::vector< std::string >
impl::split(const std::string& str, const std::string& delim)
{
std::vector< std::string > words;
std::string::size_type pos = 0, newpos = 0;
while (pos < str.length() && newpos != std::string::npos) {
newpos = str.find(delim, pos);
if (newpos != pos)
words.push_back(str.substr(pos, newpos - pos));
pos = newpos + delim.length();
}
return words;
}
std::string
impl::trim(const std::string& str)
{
std::string::size_type pos1 = str.find_first_not_of(" \t");
std::string::size_type pos2 = str.find_last_not_of(" \t");
if (pos1 == std::string::npos && pos2 == std::string::npos)
return "";
else if (pos1 == std::string::npos)
return str.substr(0, str.length() - pos2);
else if (pos2 == std::string::npos)
return str.substr(pos1);
else
return str.substr(pos1, pos2 - pos1 + 1);
}
bool
impl::to_bool(const std::string& str)
{
bool b;
atf_error_t err = atf_text_to_bool(str.c_str(), &b);
if (atf_is_error(err))
throw_atf_error(err);
return b;
}
int64_t
impl::to_bytes(std::string str)
{
if (str.empty())
throw std::runtime_error("Empty value");
const char unit = str[str.length() - 1];
int64_t multiplier;
switch (unit) {
case 'k': case 'K': multiplier = 1 << 10; break;
case 'm': case 'M': multiplier = 1 << 20; break;
case 'g': case 'G': multiplier = 1 << 30; break;
case 't': case 'T': multiplier = int64_t(1) << 40; break;
default:
if (!std::isdigit(unit))
throw std::runtime_error(std::string("Unknown size unit '") + unit
+ "'");
multiplier = 1;
}
if (multiplier != 1)
str.erase(str.length() - 1);
return to_type< int64_t >(str) * multiplier;
}

153
atf-c++/detail/text.hpp Normal file
View File

@ -0,0 +1,153 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_TEXT_HPP_)
#define _ATF_CXX_TEXT_HPP_
extern "C" {
#include <stdint.h>
}
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
namespace atf {
namespace text {
//!
//! \brief Duplicates a C string using the new[] allocator.
//!
//! Replaces the functionality of strdup by using the new[] allocator and
//! thus allowing the resulting memory to be managed by utils::auto_array.
//!
char* duplicate(const char*);
//!
//! \brief Joins multiple words into a string.
//!
//! Joins a list of words into a string, separating them using the provided
//! separator. Empty words are not omitted.
//!
template< class T >
std::string
join(const T& words, const std::string& separator)
{
std::string str;
typename T::const_iterator iter = words.begin();
bool done = iter == words.end();
while (!done) {
str += *iter;
iter++;
if (iter != words.end())
str += separator;
else
done = true;
}
return str;
}
//!
//! \brief Checks if the string matches a regular expression.
//!
bool match(const std::string&, const std::string&);
//!
//! \brief Splits a string into words.
//!
//! Splits the given string into multiple words, all separated by the
//! given delimiter. Multiple occurrences of the same delimiter are
//! not condensed so that rejoining the words later on using the same
//! delimiter results in the original string.
//!
std::vector< std::string > split(const std::string&, const std::string&);
//!
//! \brief Removes whitespace from the beginning and end of a string.
//!
std::string trim(const std::string&);
//!
//! \brief Converts a string to a boolean value.
//!
bool to_bool(const std::string&);
//!
//! \brief Converts the given string to a bytes size.
//!
int64_t to_bytes(std::string);
//!
//! \brief Changes the case of a string to lowercase.
//!
//! Returns a new string that is a lowercased version of the original
//! one.
//!
std::string to_lower(const std::string&);
//!
//! \brief Converts the given object to a string.
//!
//! Returns a string with the representation of the given object. There
//! must exist an operator<< method for that object.
//!
template< class T >
std::string
to_string(const T& ob)
{
std::ostringstream ss;
ss << ob;
return ss.str();
}
//!
//! \brief Converts the given string to another type.
//!
//! Attempts to convert the given string to the requested type. Throws
//! an exception if the conversion failed.
//!
template< class T >
T
to_type(const std::string& str)
{
std::istringstream ss(str);
T value;
ss >> value;
if (!ss.eof() || (ss.eof() && (ss.fail() || ss.bad())))
throw std::runtime_error("Cannot convert string to requested type");
return value;
}
} // namespace text
} // namespace atf
#endif // !defined(_ATF_CXX_TEXT_HPP_)

View File

@ -0,0 +1,390 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
#include <set>
#include <vector>
#include "../macros.hpp"
#include "text.hpp"
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(duplicate);
ATF_TEST_CASE_HEAD(duplicate)
{
set_md_var("descr", "Tests the duplicate function");
}
ATF_TEST_CASE_BODY(duplicate)
{
using atf::text::duplicate;
const char* orig = "foo";
char* copy = duplicate(orig);
ATF_REQUIRE_EQ(std::strlen(copy), 3);
ATF_REQUIRE(std::strcmp(copy, "foo") == 0);
std::strcpy(copy, "bar");
ATF_REQUIRE(std::strcmp(copy, "bar") == 0);
ATF_REQUIRE(std::strcmp(orig, "foo") == 0);
}
ATF_TEST_CASE(join);
ATF_TEST_CASE_HEAD(join)
{
set_md_var("descr", "Tests the join function");
}
ATF_TEST_CASE_BODY(join)
{
using atf::text::join;
// First set of tests using a non-sorted collection, std::vector.
{
std::vector< std::string > words;
std::string str;
words.clear();
str = join(words, ",");
ATF_REQUIRE_EQ(str, "");
words.clear();
words.push_back("");
str = join(words, ",");
ATF_REQUIRE_EQ(str, "");
words.clear();
words.push_back("");
words.push_back("");
str = join(words, ",");
ATF_REQUIRE_EQ(str, ",");
words.clear();
words.push_back("foo");
words.push_back("");
words.push_back("baz");
str = join(words, ",");
ATF_REQUIRE_EQ(str, "foo,,baz");
words.clear();
words.push_back("foo");
words.push_back("bar");
words.push_back("baz");
str = join(words, ",");
ATF_REQUIRE_EQ(str, "foo,bar,baz");
}
// Second set of tests using a sorted collection, std::set.
{
std::set< std::string > words;
std::string str;
words.clear();
str = join(words, ",");
ATF_REQUIRE_EQ(str, "");
words.clear();
words.insert("");
str = join(words, ",");
ATF_REQUIRE_EQ(str, "");
words.clear();
words.insert("foo");
words.insert("");
words.insert("baz");
str = join(words, ",");
ATF_REQUIRE_EQ(str, ",baz,foo");
words.clear();
words.insert("foo");
words.insert("bar");
words.insert("baz");
str = join(words, ",");
ATF_REQUIRE_EQ(str, "bar,baz,foo");
}
}
ATF_TEST_CASE(match);
ATF_TEST_CASE_HEAD(match)
{
set_md_var("descr", "Tests the match function");
}
ATF_TEST_CASE_BODY(match)
{
using atf::text::match;
ATF_REQUIRE_THROW(std::runtime_error, match("", "["));
ATF_REQUIRE(match("", ""));
ATF_REQUIRE(!match("foo", ""));
ATF_REQUIRE(match("", ".*"));
ATF_REQUIRE(match("", "[a-z]*"));
ATF_REQUIRE(match("hello", "hello"));
ATF_REQUIRE(match("hello", "[a-z]+"));
ATF_REQUIRE(match("hello", "^[a-z]+$"));
ATF_REQUIRE(!match("hello", "helooo"));
ATF_REQUIRE(!match("hello", "[a-z]+5"));
ATF_REQUIRE(!match("hello", "^ [a-z]+$"));
}
ATF_TEST_CASE(split);
ATF_TEST_CASE_HEAD(split)
{
set_md_var("descr", "Tests the split function");
}
ATF_TEST_CASE_BODY(split)
{
using atf::text::split;
std::vector< std::string > words;
words = split("", " ");
ATF_REQUIRE_EQ(words.size(), 0);
words = split(" ", " ");
ATF_REQUIRE_EQ(words.size(), 0);
words = split(" ", " ");
ATF_REQUIRE_EQ(words.size(), 0);
words = split("a b", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "a");
ATF_REQUIRE_EQ(words[1], "b");
words = split("a b c d", " ");
ATF_REQUIRE_EQ(words.size(), 4);
ATF_REQUIRE_EQ(words[0], "a");
ATF_REQUIRE_EQ(words[1], "b");
ATF_REQUIRE_EQ(words[2], "c");
ATF_REQUIRE_EQ(words[3], "d");
words = split("foo bar", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
words = split("foo bar baz foobar", " ");
ATF_REQUIRE_EQ(words.size(), 4);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
ATF_REQUIRE_EQ(words[2], "baz");
ATF_REQUIRE_EQ(words[3], "foobar");
words = split(" foo bar", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
words = split("foo bar", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
words = split("foo bar ", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
words = split(" foo bar ", " ");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "foo");
ATF_REQUIRE_EQ(words[1], "bar");
}
ATF_TEST_CASE(split_delims);
ATF_TEST_CASE_HEAD(split_delims)
{
set_md_var("descr", "Tests the split function using different delimiters");
}
ATF_TEST_CASE_BODY(split_delims)
{
using atf::text::split;
std::vector< std::string > words;
words = split("", "/");
ATF_REQUIRE_EQ(words.size(), 0);
words = split(" ", "/");
ATF_REQUIRE_EQ(words.size(), 1);
ATF_REQUIRE_EQ(words[0], " ");
words = split(" ", "/");
ATF_REQUIRE_EQ(words.size(), 1);
ATF_REQUIRE_EQ(words[0], " ");
words = split("a/b", "/");
ATF_REQUIRE_EQ(words.size(), 2);
ATF_REQUIRE_EQ(words[0], "a");
ATF_REQUIRE_EQ(words[1], "b");
words = split("aLONGDELIMbcdLONGDELIMef", "LONGDELIM");
ATF_REQUIRE_EQ(words.size(), 3);
ATF_REQUIRE_EQ(words[0], "a");
ATF_REQUIRE_EQ(words[1], "bcd");
ATF_REQUIRE_EQ(words[2], "ef");
}
ATF_TEST_CASE(trim);
ATF_TEST_CASE_HEAD(trim)
{
set_md_var("descr", "Tests the trim function");
}
ATF_TEST_CASE_BODY(trim)
{
using atf::text::trim;
ATF_REQUIRE_EQ(trim(""), "");
ATF_REQUIRE_EQ(trim(" "), "");
ATF_REQUIRE_EQ(trim("\t"), "");
ATF_REQUIRE_EQ(trim(" foo"), "foo");
ATF_REQUIRE_EQ(trim("\t foo"), "foo");
ATF_REQUIRE_EQ(trim(" \tfoo"), "foo");
ATF_REQUIRE_EQ(trim("foo\t "), "foo");
ATF_REQUIRE_EQ(trim("foo \t"), "foo");
ATF_REQUIRE_EQ(trim("foo bar"), "foo bar");
ATF_REQUIRE_EQ(trim("\t foo bar"), "foo bar");
ATF_REQUIRE_EQ(trim(" \tfoo bar"), "foo bar");
ATF_REQUIRE_EQ(trim("foo bar\t "), "foo bar");
ATF_REQUIRE_EQ(trim("foo bar \t"), "foo bar");
}
ATF_TEST_CASE(to_bool);
ATF_TEST_CASE_HEAD(to_bool)
{
set_md_var("descr", "Tests the to_string function");
}
ATF_TEST_CASE_BODY(to_bool)
{
using atf::text::to_bool;
ATF_REQUIRE(to_bool("true"));
ATF_REQUIRE(to_bool("TRUE"));
ATF_REQUIRE(to_bool("yes"));
ATF_REQUIRE(to_bool("YES"));
ATF_REQUIRE(!to_bool("false"));
ATF_REQUIRE(!to_bool("FALSE"));
ATF_REQUIRE(!to_bool("no"));
ATF_REQUIRE(!to_bool("NO"));
ATF_REQUIRE_THROW(std::runtime_error, to_bool(""));
ATF_REQUIRE_THROW(std::runtime_error, to_bool("tru"));
ATF_REQUIRE_THROW(std::runtime_error, to_bool("true2"));
ATF_REQUIRE_THROW(std::runtime_error, to_bool("fals"));
ATF_REQUIRE_THROW(std::runtime_error, to_bool("false2"));
}
ATF_TEST_CASE(to_bytes);
ATF_TEST_CASE_HEAD(to_bytes)
{
set_md_var("descr", "Tests the to_bytes function");
}
ATF_TEST_CASE_BODY(to_bytes)
{
using atf::text::to_bytes;
ATF_REQUIRE_EQ(0, to_bytes("0"));
ATF_REQUIRE_EQ(12345, to_bytes("12345"));
ATF_REQUIRE_EQ(2 * 1024, to_bytes("2k"));
ATF_REQUIRE_EQ(4 * 1024 * 1024, to_bytes("4m"));
ATF_REQUIRE_EQ(int64_t(8) * 1024 * 1024 * 1024, to_bytes("8g"));
ATF_REQUIRE_EQ(int64_t(16) * 1024 * 1024 * 1024 * 1024, to_bytes("16t"));
ATF_REQUIRE_THROW_RE(std::runtime_error, "Empty", to_bytes(""));
ATF_REQUIRE_THROW_RE(std::runtime_error, "Unknown size unit 'd'",
to_bytes("12d"));
ATF_REQUIRE_THROW(std::runtime_error, to_bytes(" "));
ATF_REQUIRE_THROW(std::runtime_error, to_bytes(" k"));
}
ATF_TEST_CASE(to_string);
ATF_TEST_CASE_HEAD(to_string)
{
set_md_var("descr", "Tests the to_string function");
}
ATF_TEST_CASE_BODY(to_string)
{
using atf::text::to_string;
ATF_REQUIRE_EQ(to_string('a'), "a");
ATF_REQUIRE_EQ(to_string("a"), "a");
ATF_REQUIRE_EQ(to_string(5), "5");
}
ATF_TEST_CASE(to_type);
ATF_TEST_CASE_HEAD(to_type)
{
set_md_var("descr", "Tests the to_type function");
}
ATF_TEST_CASE_BODY(to_type)
{
using atf::text::to_type;
ATF_REQUIRE_EQ(to_type< int >("0"), 0);
ATF_REQUIRE_EQ(to_type< int >("1234"), 1234);
ATF_REQUIRE_THROW(std::runtime_error, to_type< int >(" "));
ATF_REQUIRE_THROW(std::runtime_error, to_type< int >("0 a"));
ATF_REQUIRE_THROW(std::runtime_error, to_type< int >("a"));
ATF_REQUIRE_EQ(to_type< float >("0.5"), 0.5);
ATF_REQUIRE_EQ(to_type< float >("1234.5"), 1234.5);
ATF_REQUIRE_THROW(std::runtime_error, to_type< float >("0.5 a"));
ATF_REQUIRE_THROW(std::runtime_error, to_type< float >("a"));
ATF_REQUIRE_EQ(to_type< std::string >("a"), "a");
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, duplicate);
ATF_ADD_TEST_CASE(tcs, join);
ATF_ADD_TEST_CASE(tcs, match);
ATF_ADD_TEST_CASE(tcs, split);
ATF_ADD_TEST_CASE(tcs, split_delims);
ATF_ADD_TEST_CASE(tcs, trim);
ATF_ADD_TEST_CASE(tcs, to_bool);
ATF_ADD_TEST_CASE(tcs, to_bytes);
ATF_ADD_TEST_CASE(tcs, to_string);
ATF_ADD_TEST_CASE(tcs, to_type);
}

173
atf-c++/detail/ui.cpp Normal file
View File

@ -0,0 +1,173 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
}
#include <sstream>
#include "env.hpp"
#include "text.hpp"
#include "sanity.hpp"
#include "text.hpp"
#include "ui.hpp"
namespace impl = atf::ui;
#define IMPL_NAME "atf::ui"
static
size_t
terminal_width(void)
{
static bool done = false;
static size_t width = 0;
if (!done) {
if (atf::env::has("COLUMNS")) {
const std::string cols = atf::env::get("COLUMNS");
if (cols.length() > 0) {
width = atf::text::to_type< size_t >(cols);
}
} else {
struct winsize ws;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
width = ws.ws_col;
}
if (width >= 80)
width -= 5;
done = true;
}
return width;
}
static
std::string
format_paragraph(const std::string& text,
const std::string& tag,
const bool first,
const bool repeat,
const size_t col)
{
PRE(text.find('\n') == std::string::npos);
const std::string pad(col - tag.length(), ' ');
const std::string fullpad(col, ' ');
std::string formatted;
if (first || repeat)
formatted = tag + pad;
else
formatted = fullpad;
INV(formatted.length() == col);
size_t curcol = col;
const size_t maxcol = terminal_width();
std::vector< std::string > words = atf::text::split(text, " ");
for (std::vector< std::string >::const_iterator iter = words.begin();
iter != words.end(); iter++) {
const std::string& word = *iter;
if (iter != words.begin() && maxcol > 0 &&
curcol + word.length() + 1 > maxcol) {
if (repeat)
formatted += '\n' + tag + pad;
else
formatted += '\n' + fullpad;
curcol = col;
} else if (iter != words.begin()) {
formatted += ' ';
curcol++;
}
formatted += word;
curcol += word.length();
}
return formatted;
}
std::string
impl::format_error(const std::string& prog_name, const std::string& error)
{
return format_text_with_tag("ERROR: " + error, prog_name + ": ", true);
}
std::string
impl::format_info(const std::string& prog_name, const std::string& msg)
{
return format_text_with_tag(msg, prog_name + ": ", true);
}
std::string
impl::format_text(const std::string& text)
{
return format_text_with_tag(text, "", false, 0);
}
std::string
impl::format_text_with_tag(const std::string& text, const std::string& tag,
bool repeat, size_t col)
{
PRE(col == 0 || col >= tag.length());
if (col == 0)
col = tag.length();
std::string formatted;
std::vector< std::string > lines = atf::text::split(text, "\n");
for (std::vector< std::string >::const_iterator iter = lines.begin();
iter != lines.end(); iter++) {
const std::string& line = *iter;
formatted += format_paragraph(line, tag, iter == lines.begin(),
repeat, col);
if (iter + 1 != lines.end()) {
if (repeat)
formatted += "\n" + tag + "\n";
else
formatted += "\n\n";
}
}
return formatted;
}
std::string
impl::format_warning(const std::string& prog_name, const std::string& error)
{
return format_text_with_tag("WARNING: " + error, prog_name + ": ", true);
}

105
atf-c++/detail/ui.hpp Normal file
View File

@ -0,0 +1,105 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_UI_HPP_)
#define _ATF_CXX_UI_HPP_
#include <string>
namespace atf {
namespace ui {
//!
//! \brief Formats an error message to fit on screen.
//!
//! Given the program's name and an error message, properly formats it to
//! fit on screen.
//!
//! The program's name is not stored globally to prevent the usage of this
//! function from inside the library. Making it a explicit parameter
//! restricts its usage to the frontend.
//!
std::string format_error(const std::string&, const std::string&);
//!
//! \brief Formats an informational message to fit on screen.
//!
//! Given the program's name and an informational message, properly formats
//! it to fit on screen.
//!
//! The program's name is not stored globally to prevent the usage of this
//! function from inside the library. Making it a explicit parameter
//! restricts its usage to the frontend.
//!
std::string format_info(const std::string&, const std::string&);
//!
//! \brief Formats a block of text to fit nicely on screen.
//!
//! Given a text, which is composed of multiple paragraphs separated by
//! a single '\n' character, reformats it to fill on the current screen's
//! width with proper line wrapping.
//!
//! This is just a special case of format_text_with_tag, provided for
//! simplicity.
//!
std::string format_text(const std::string&);
//!
//! \brief Formats a block of text to fit nicely on screen, prepending a
//! tag to it.
//!
//! Given a text, which is composed of multiple paragraphs separated by
//! a single '\n' character, reformats it to fill on the current screen's
//! width with proper line wrapping. The text is prepended with a tag;
//! i.e. a word that is printed at the beginning of the first paragraph and
//! optionally repeated at the beginning of each word. The last parameter
//! specifies the column on which the text should start, and that position
//! must be greater than the tag's length or 0, in which case it
//! automatically takes the correct value.
//!
std::string format_text_with_tag(const std::string&, const std::string&,
bool, size_t = 0);
//!
//! \brief Formats a warning message to fit on screen.
//!
//! Given the program's name and a warning message, properly formats it to
//! fit on screen.
//!
//! The program's name is not stored globally to prevent the usage of this
//! function from inside the library. Making it a explicit parameter
//! restricts its usage to the frontend.
//!
std::string format_warning(const std::string&, const std::string&);
} // namespace ui
} // namespace atf
#endif // !defined(_ATF_CXX_UI_HPP_)

462
atf-c++/detail/ui_test.cpp Normal file
View File

@ -0,0 +1,462 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2009 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <cstring>
#include <iostream>
#include "../macros.hpp"
#include "env.hpp"
#include "ui.hpp"
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
struct test {
const char *tc;
const char *tag;
bool repeat;
size_t col;
const char *fmt;
const char *result;
} tests[] = {
//
// wo_tag
//
{
"wo_tag",
"",
false,
0,
"12345",
"12345",
},
{
"wo_tag",
"",
false,
0,
"12345 ",
"12345",
},
{
"wo_tag",
"",
false,
0,
"12345 7890",
"12345 7890",
},
{
"wo_tag",
"",
false,
0,
"12345 789012 45",
"12345 789012 45",
},
{
"wo_tag",
"",
false,
0,
"12345 789012 456",
"12345 789012\n456",
},
{
"wo_tag",
"",
false,
0,
"1234567890123456",
"1234567890123456",
},
// TODO(jmmv): Fix the code to pass this test...
// {
// "wo_tag",
// "",
// false,
// 0,
// " 2345678901234567",
// "\n2345678901234567",
// },
{
"wo_tag",
"",
false,
0,
"12345 789012345 78",
"12345 789012345\n78",
},
//
// wo_tag_col
//
{
"wo_tag_col",
"",
false,
10,
"12345",
" 12345",
},
{
"wo_tag_col",
"",
false,
10,
"12345 7890",
" 12345\n"
" 7890",
},
{
"wo_tag_col",
"",
false,
10,
"1 3 5 7 9",
" 1 3 5\n"
" 7 9",
},
//
// w_tag_no_repeat
//
{
"w_tag_no_repeat",
"1234: ",
false,
0,
"789012345",
"1234: 789012345",
},
{
"w_tag_no_repeat",
"1234: ",
false,
0,
"789 1234 56789",
"1234: 789 1234\n"
" 56789",
},
{
"w_tag_no_repeat",
"1234: ",
false,
0,
"789012345",
"1234: 789012345",
},
{
"w_tag_no_repeat",
"1234: ",
false,
0,
"789012345 7890",
"1234: 789012345\n"
" 7890",
},
//
// w_tag_repeat
//
{
"w_tag_repeat",
"1234: ",
true,
0,
"789012345",
"1234: 789012345",
},
{
"w_tag_repeat",
"1234: ",
true,
0,
"789 1234 56789",
"1234: 789 1234\n"
"1234: 56789",
},
{
"w_tag_repeat",
"1234: ",
true,
0,
"789012345",
"1234: 789012345",
},
{
"w_tag_no_repeat",
"1234: ",
true,
0,
"789012345 7890",
"1234: 789012345\n"
"1234: 7890",
},
//
// w_tag_col
//
{
"w_tag_col",
"1234:",
false,
10,
"1 3 5",
"1234: 1 3 5",
},
{
"w_tag_col",
"1234:",
false,
10,
"1 3 5 7 9",
"1234: 1 3 5\n"
" 7 9",
},
{
"w_tag_col",
"1234:",
true,
10,
"1 3 5 7 9",
"1234: 1 3 5\n"
"1234: 7 9",
},
//
// paragraphs
//
{
"paragraphs",
"",
false,
0,
"1 3 5\n\n",
"1 3 5"
},
{
"paragraphs",
"",
false,
0,
"1 3 5\n2 4 6",
"1 3 5\n\n2 4 6"
},
{
"paragraphs",
"",
false,
0,
"1234 6789 123456\n2 4 6",
"1234 6789\n123456\n\n2 4 6"
},
{
"paragraphs",
"12: ",
false,
0,
"56789 123456\n2 4 6",
"12: 56789\n 123456\n\n 2 4 6"
},
{
"paragraphs",
"12: ",
true,
0,
"56789 123456\n2 4 6",
"12: 56789\n12: 123456\n12: \n12: 2 4 6"
},
{
"paragraphs",
"12:",
false,
4,
"56789 123456\n2 4 6",
"12: 56789\n 123456\n\n 2 4 6"
},
{
"paragraphs",
"12:",
true,
4,
"56789 123456\n2 4 6",
"12: 56789\n12: 123456\n12:\n12: 2 4 6"
},
//
// end
//
{
NULL,
NULL,
false,
0,
NULL,
NULL,
},
};
static
void
run_tests(const char *tc)
{
struct test *t;
std::cout << "Running tests for " << tc << "\n";
atf::env::set("COLUMNS", "15");
for (t = &tests[0]; t->tc != NULL; t++) {
if (std::strcmp(t->tc, tc) == 0) {
std::cout << "\n";
std::cout << "Testing with tag '" << t->tag << "', '"
<< (t->repeat ? "repeat" : "no repeat") << "', col "
<< t->col << "\n";
std::cout << "Input: >>>" << t->fmt << "<<<\n";
std::cout << "Expected output: >>>" << t->result << "<<<\n";
std::string result = atf::ui::format_text_with_tag(t->fmt, t->tag,
t->repeat, t->col);
std::cout << "Output : >>>" << result << "<<<\n";
ATF_REQUIRE_EQ(t->result, result);
}
}
}
ATF_TEST_CASE(wo_tag);
ATF_TEST_CASE_HEAD(wo_tag)
{
set_md_var("descr", "Checks formatting without tags");
}
ATF_TEST_CASE_BODY(wo_tag)
{
run_tests("wo_tag");
}
ATF_TEST_CASE(wo_tag_col);
ATF_TEST_CASE_HEAD(wo_tag_col)
{
set_md_var("descr", "Checks formatting without tags and with a non-zero "
"starting column");
}
ATF_TEST_CASE_BODY(wo_tag_col)
{
run_tests("wo_tag_col");
}
ATF_TEST_CASE(w_tag_no_repeat);
ATF_TEST_CASE_HEAD(w_tag_no_repeat)
{
set_md_var("descr", "Checks formatting with a tag");
}
ATF_TEST_CASE_BODY(w_tag_no_repeat)
{
run_tests("w_tag_no_repeat");
}
ATF_TEST_CASE(w_tag_repeat);
ATF_TEST_CASE_HEAD(w_tag_repeat)
{
set_md_var("descr", "Checks formatting with a tag and repeating it on "
"each line");
}
ATF_TEST_CASE_BODY(w_tag_repeat)
{
run_tests("w_tag_repeat");
}
ATF_TEST_CASE(w_tag_col);
ATF_TEST_CASE_HEAD(w_tag_col)
{
set_md_var("descr", "Checks formatting with a tag and starting at a "
"column greater than its length");
}
ATF_TEST_CASE_BODY(w_tag_col)
{
run_tests("w_tag_col");
}
ATF_TEST_CASE(paragraphs);
ATF_TEST_CASE_HEAD(paragraphs)
{
set_md_var("descr", "Checks formatting a string that contains multiple "
"paragraphs");
}
ATF_TEST_CASE_BODY(paragraphs)
{
run_tests("paragraphs");
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, wo_tag);
ATF_ADD_TEST_CASE(tcs, wo_tag_col);
ATF_ADD_TEST_CASE(tcs, w_tag_no_repeat);
ATF_ADD_TEST_CASE(tcs, w_tag_repeat);
ATF_ADD_TEST_CASE(tcs, w_tag_col);
ATF_ADD_TEST_CASE(tcs, paragraphs);
}

222
atf-c++/macros.hpp Normal file
View File

@ -0,0 +1,222 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_MACROS_HPP_)
#define _ATF_CXX_MACROS_HPP_
#include <sstream>
#include <stdexcept>
#include <vector>
#include <atf-c++/tests.hpp>
// Do not define inline methods for the test case classes. Doing so
// significantly increases the memory requirements of GNU G++ during
// compilation.
#define ATF_TEST_CASE_WITHOUT_HEAD(name) \
namespace { \
class atfu_tc_ ## name : public atf::tests::tc { \
void body(void) const; \
public: \
atfu_tc_ ## name(void); \
}; \
static atfu_tc_ ## name* atfu_tcptr_ ## name; \
atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, false) {} \
}
#define ATF_TEST_CASE(name) \
namespace { \
class atfu_tc_ ## name : public atf::tests::tc { \
void head(void); \
void body(void) const; \
public: \
atfu_tc_ ## name(void); \
}; \
static atfu_tc_ ## name* atfu_tcptr_ ## name; \
atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, false) {} \
}
#define ATF_TEST_CASE_WITH_CLEANUP(name) \
namespace { \
class atfu_tc_ ## name : public atf::tests::tc { \
void head(void); \
void body(void) const; \
void cleanup(void) const; \
public: \
atfu_tc_ ## name(void); \
}; \
static atfu_tc_ ## name* atfu_tcptr_ ## name; \
atfu_tc_ ## name::atfu_tc_ ## name(void) : atf::tests::tc(#name, true) {} \
}
#define ATF_TEST_CASE_NAME(name) atfu_tc_ ## name
#define ATF_TEST_CASE_USE(name) (atfu_tcptr_ ## name) = NULL
#define ATF_TEST_CASE_HEAD(name) \
void \
atfu_tc_ ## name::head(void)
#define ATF_TEST_CASE_BODY(name) \
void \
atfu_tc_ ## name::body(void) \
const
#define ATF_TEST_CASE_CLEANUP(name) \
void \
atfu_tc_ ## name::cleanup(void) \
const
#define ATF_FAIL(reason) atf::tests::tc::fail(reason)
#define ATF_SKIP(reason) atf::tests::tc::skip(reason)
#define ATF_PASS() atf::tests::tc::pass()
#define ATF_REQUIRE(x) \
do { \
if (!(x)) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " << #x << " not met"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} while (false)
#define ATF_REQUIRE_EQ(x, y) \
do { \
if ((x) != (y)) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " << #x << " != " << #y \
<< " (" << (x) << " != " << (y) << ")"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} while (false)
#define ATF_REQUIRE_IN(element, collection) \
ATF_REQUIRE((collection).find(element) != (collection).end())
#define ATF_REQUIRE_NOT_IN(element, collection) \
ATF_REQUIRE((collection).find(element) == (collection).end())
#define ATF_REQUIRE_MATCH(regexp, string) \
do { \
if (!atf::tests::detail::match(regexp, string)) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": '" << string << "' does not " \
<< "match regexp '" << regexp << "'"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} while (false)
#define ATF_REQUIRE_THROW(e, x) \
do { \
try { \
x; \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " did not throw " \
#e " as expected"; \
atf::tests::tc::fail(atfu_ss.str()); \
} catch (const e&) { \
} catch (const std::exception& atfu_e) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
"unexpected error (not " #e "): " << atfu_e.what(); \
atf::tests::tc::fail(atfu_ss.str()); \
} catch (...) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
"unexpected error (not " #e ")"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} while (false)
#define ATF_REQUIRE_THROW_RE(type, regexp, x) \
do { \
try { \
x; \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " did not throw " \
#type " as expected"; \
atf::tests::tc::fail(atfu_ss.str()); \
} catch (const type& e) { \
if (!atf::tests::detail::match(regexp, e.what())) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " threw " #type "(" \
<< e.what() << "), but does not match '" << regexp \
<< "'"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} catch (const std::exception& atfu_e) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
"unexpected error (not " #type "): " << atfu_e.what(); \
atf::tests::tc::fail(atfu_ss.str()); \
} catch (...) { \
std::ostringstream atfu_ss; \
atfu_ss << "Line " << __LINE__ << ": " #x " threw an " \
"unexpected error (not " #type ")"; \
atf::tests::tc::fail(atfu_ss.str()); \
} \
} while (false)
#define ATF_CHECK_ERRNO(exp_errno, bool_expr) \
atf::tests::tc::check_errno(__FILE__, __LINE__, exp_errno, #bool_expr, \
bool_expr)
#define ATF_REQUIRE_ERRNO(exp_errno, bool_expr) \
atf::tests::tc::require_errno(__FILE__, __LINE__, exp_errno, #bool_expr, \
bool_expr)
#define ATF_INIT_TEST_CASES(tcs) \
namespace atf { \
namespace tests { \
int run_tp(int, char* const*, \
void (*)(std::vector< atf::tests::tc * >&)); \
} \
} \
\
static void atfu_init_tcs(std::vector< atf::tests::tc * >&); \
\
int \
main(int argc, char* const* argv) \
{ \
return atf::tests::run_tp(argc, argv, atfu_init_tcs); \
} \
\
static \
void \
atfu_init_tcs(std::vector< atf::tests::tc * >& tcs)
#define ATF_ADD_TEST_CASE(tcs, tcname) \
do { \
atfu_tcptr_ ## tcname = new atfu_tc_ ## tcname(); \
(tcs).push_back(atfu_tcptr_ ## tcname); \
} while (0);
#endif // !defined(_ATF_CXX_MACROS_HPP_)

130
atf-c++/macros_hpp_test.cpp Normal file
View File

@ -0,0 +1,130 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <stdexcept>
#include <atf-c++/macros.hpp>
void
atf_check_errno_semicolons(void)
{
// Check that ATF_CHECK_ERRNO does not contain a semicolon that would
// cause an empty-statement that confuses some compilers.
ATF_CHECK_ERRNO(1, 1 == 1);
ATF_CHECK_ERRNO(2, 2 == 2);
}
void
atf_require_inside_if(void)
{
// Make sure that ATF_REQUIRE can be used inside an if statement that
// does not have braces. Earlier versions of it generated an error
// if there was an else clause because they confused the compiler
// by defining an unprotected nested if.
if (true)
ATF_REQUIRE(true);
else
ATF_REQUIRE(true);
}
void
atf_require_eq_inside_if(void)
{
// Make sure that ATF_REQUIRE_EQ can be used inside an if statement
// that does not have braces. Earlier versions of it generated an
// error if there was an else clause because they confused the
// compiler by defining an unprotected nested if.
if (true)
ATF_REQUIRE_EQ(true, true);
else
ATF_REQUIRE_EQ(true, true);
}
void
atf_require_throw_runtime_error(void)
{
// Check that we can pass std::runtime_error to ATF_REQUIRE_THROW.
// Earlier versions generated a warning because the macro's code also
// attempted to capture this exception, and thus we had a duplicate
// catch clause.
ATF_REQUIRE_THROW(std::runtime_error, (void)0);
}
void
atf_require_throw_inside_if(void)
{
// Make sure that ATF_REQUIRE_THROW can be used inside an if statement
// that does not have braces. Earlier versions of it generated an
// error because a trailing ; after a catch block was not allowed.
if (true)
ATF_REQUIRE_THROW(std::runtime_error, (void)0);
else
ATF_REQUIRE_THROW(std::runtime_error, (void)1);
}
void
atf_require_errno_semicolons(void)
{
// Check that ATF_REQUIRE_ERRNO does not contain a semicolon that would
// cause an empty-statement that confuses some compilers.
ATF_REQUIRE_ERRNO(1, 1 == 1);
ATF_REQUIRE_ERRNO(2, 2 == 2);
}
// Test case names should not be expanded during instatiation so that they
// can have the exact same name as macros.
#define TEST_MACRO_1 invalid + name
#define TEST_MACRO_2 invalid + name
#define TEST_MACRO_3 invalid + name
ATF_TEST_CASE(TEST_MACRO_1);
ATF_TEST_CASE_HEAD(TEST_MACRO_1) { }
ATF_TEST_CASE_BODY(TEST_MACRO_1) { }
void instantiate_1(void) {
ATF_TEST_CASE_USE(TEST_MACRO_1);
atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_1)();
delete the_test;
}
ATF_TEST_CASE_WITH_CLEANUP(TEST_MACRO_2);
ATF_TEST_CASE_HEAD(TEST_MACRO_2) { }
ATF_TEST_CASE_BODY(TEST_MACRO_2) { }
ATF_TEST_CASE_CLEANUP(TEST_MACRO_2) { }
void instatiate_2(void) {
ATF_TEST_CASE_USE(TEST_MACRO_2);
atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_2)();
delete the_test;
}
ATF_TEST_CASE_WITH_CLEANUP(TEST_MACRO_3);
ATF_TEST_CASE_HEAD(TEST_MACRO_3) { }
ATF_TEST_CASE_BODY(TEST_MACRO_3) { }
ATF_TEST_CASE_CLEANUP(TEST_MACRO_3) { }
void instatiate_3(void) {
ATF_TEST_CASE_USE(TEST_MACRO_3);
atf::tests::tc* the_test = new ATF_TEST_CASE_NAME(TEST_MACRO_3)();
delete the_test;
}

793
atf-c++/macros_test.cpp Normal file
View File

@ -0,0 +1,793 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <fcntl.h>
#include <unistd.h>
}
#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include "macros.hpp"
#include "detail/fs.hpp"
#include "detail/process.hpp"
#include "detail/sanity.hpp"
#include "detail/test_helpers.hpp"
#include "detail/text.hpp"
// ------------------------------------------------------------------------
// Auxiliary functions.
// ------------------------------------------------------------------------
static
void
create_ctl_file(const char *name)
{
ATF_REQUIRE(open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644) != -1);
}
// ------------------------------------------------------------------------
// Auxiliary test cases.
// ------------------------------------------------------------------------
ATF_TEST_CASE(h_pass);
ATF_TEST_CASE_HEAD(h_pass)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_pass)
{
create_ctl_file("before");
ATF_PASS();
create_ctl_file("after");
}
ATF_TEST_CASE(h_fail);
ATF_TEST_CASE_HEAD(h_fail)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_fail)
{
create_ctl_file("before");
ATF_FAIL("Failed on purpose");
create_ctl_file("after");
}
ATF_TEST_CASE(h_skip);
ATF_TEST_CASE_HEAD(h_skip)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_skip)
{
create_ctl_file("before");
ATF_SKIP("Skipped on purpose");
create_ctl_file("after");
}
ATF_TEST_CASE(h_require);
ATF_TEST_CASE_HEAD(h_require)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require)
{
bool condition = atf::text::to_bool(get_config_var("condition"));
create_ctl_file("before");
ATF_REQUIRE(condition);
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_eq);
ATF_TEST_CASE_HEAD(h_require_eq)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_eq)
{
long v1 = atf::text::to_type< long >(get_config_var("v1"));
long v2 = atf::text::to_type< long >(get_config_var("v2"));
create_ctl_file("before");
ATF_REQUIRE_EQ(v1, v2);
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_in);
ATF_TEST_CASE_HEAD(h_require_in)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_in)
{
const std::string element = get_config_var("value");
std::set< std::string > collection;
collection.insert("foo");
collection.insert("bar");
collection.insert("baz");
create_ctl_file("before");
ATF_REQUIRE_IN(element, collection);
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_match);
ATF_TEST_CASE_HEAD(h_require_match)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_match)
{
const std::string regexp = get_config_var("regexp");
const std::string string = get_config_var("string");
create_ctl_file("before");
ATF_REQUIRE_MATCH(regexp, string);
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_not_in);
ATF_TEST_CASE_HEAD(h_require_not_in)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_not_in)
{
const std::string element = get_config_var("value");
std::set< std::string > collection;
collection.insert("foo");
collection.insert("bar");
collection.insert("baz");
create_ctl_file("before");
ATF_REQUIRE_NOT_IN(element, collection);
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_throw);
ATF_TEST_CASE_HEAD(h_require_throw)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_throw)
{
create_ctl_file("before");
if (get_config_var("what") == "throw_int")
ATF_REQUIRE_THROW(std::runtime_error, if (1) throw int(5));
else if (get_config_var("what") == "throw_rt")
ATF_REQUIRE_THROW(std::runtime_error,
if (1) throw std::runtime_error("e"));
else if (get_config_var("what") == "no_throw_rt")
ATF_REQUIRE_THROW(std::runtime_error,
if (0) throw std::runtime_error("e"));
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_throw_re);
ATF_TEST_CASE_HEAD(h_require_throw_re)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_throw_re)
{
create_ctl_file("before");
if (get_config_var("what") == "throw_int")
ATF_REQUIRE_THROW_RE(std::runtime_error, "5", if (1) throw int(5));
else if (get_config_var("what") == "throw_rt_match")
ATF_REQUIRE_THROW_RE(std::runtime_error, "foo.*baz",
if (1) throw std::runtime_error("a foo bar baz"));
else if (get_config_var("what") == "throw_rt_no_match")
ATF_REQUIRE_THROW_RE(std::runtime_error, "foo.*baz",
if (1) throw std::runtime_error("baz foo bar a"));
else if (get_config_var("what") == "no_throw_rt")
ATF_REQUIRE_THROW_RE(std::runtime_error, "e",
if (0) throw std::runtime_error("e"));
create_ctl_file("after");
}
static int
errno_fail_stub(const int raised_errno)
{
errno = raised_errno;
return -1;
}
static int
errno_ok_stub(void)
{
return 0;
}
ATF_TEST_CASE(h_check_errno);
ATF_TEST_CASE_HEAD(h_check_errno)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_check_errno)
{
create_ctl_file("before");
if (get_config_var("what") == "no_error")
ATF_CHECK_ERRNO(-1, errno_ok_stub() == -1);
else if (get_config_var("what") == "errno_ok")
ATF_CHECK_ERRNO(2, errno_fail_stub(2) == -1);
else if (get_config_var("what") == "errno_fail")
ATF_CHECK_ERRNO(3, errno_fail_stub(4) == -1);
else
UNREACHABLE;
create_ctl_file("after");
}
ATF_TEST_CASE(h_require_errno);
ATF_TEST_CASE_HEAD(h_require_errno)
{
set_md_var("descr", "Helper test case");
}
ATF_TEST_CASE_BODY(h_require_errno)
{
create_ctl_file("before");
if (get_config_var("what") == "no_error")
ATF_REQUIRE_ERRNO(-1, errno_ok_stub() == -1);
else if (get_config_var("what") == "errno_ok")
ATF_REQUIRE_ERRNO(2, errno_fail_stub(2) == -1);
else if (get_config_var("what") == "errno_fail")
ATF_REQUIRE_ERRNO(3, errno_fail_stub(4) == -1);
else
UNREACHABLE;
create_ctl_file("after");
}
// ------------------------------------------------------------------------
// Test cases for the macros.
// ------------------------------------------------------------------------
ATF_TEST_CASE(pass);
ATF_TEST_CASE_HEAD(pass)
{
set_md_var("descr", "Tests the ATF_PASS macro");
}
ATF_TEST_CASE_BODY(pass)
{
ATF_TEST_CASE_USE(h_pass);
run_h_tc< ATF_TEST_CASE_NAME(h_pass) >();
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
}
ATF_TEST_CASE(fail);
ATF_TEST_CASE_HEAD(fail)
{
set_md_var("descr", "Tests the ATF_FAIL macro");
}
ATF_TEST_CASE_BODY(fail)
{
ATF_TEST_CASE_USE(h_fail);
run_h_tc< ATF_TEST_CASE_NAME(h_fail) >();
ATF_REQUIRE(grep_file("result", "^failed: Failed on purpose"));
ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
}
ATF_TEST_CASE(skip);
ATF_TEST_CASE_HEAD(skip)
{
set_md_var("descr", "Tests the ATF_SKIP macro");
}
ATF_TEST_CASE_BODY(skip)
{
ATF_TEST_CASE_USE(h_skip);
run_h_tc< ATF_TEST_CASE_NAME(h_skip) >();
ATF_REQUIRE(grep_file("result", "^skipped: Skipped on purpose"));
ATF_REQUIRE(atf::fs::exists(atf::fs::path("before")));
ATF_REQUIRE(!atf::fs::exists(atf::fs::path("after")));
}
ATF_TEST_CASE(require);
ATF_TEST_CASE_HEAD(require)
{
set_md_var("descr", "Tests the ATF_REQUIRE macro");
}
ATF_TEST_CASE_BODY(require)
{
struct test {
const char *cond;
bool ok;
} *t, tests[] = {
{ "false", false },
{ "true", true },
{ NULL, false }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->cond != NULL; t++) {
atf::tests::vars_map config;
config["condition"] = t->cond;
std::cout << "Checking with a " << t->cond << " value\n";
ATF_TEST_CASE_USE(h_require);
run_h_tc< ATF_TEST_CASE_NAME(h_require) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
ATF_REQUIRE(grep_file("result", "^failed: .*condition not met"));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_eq);
ATF_TEST_CASE_HEAD(require_eq)
{
set_md_var("descr", "Tests the ATF_REQUIRE_EQ macro");
}
ATF_TEST_CASE_BODY(require_eq)
{
struct test {
const char *v1;
const char *v2;
bool ok;
} *t, tests[] = {
{ "1", "1", true },
{ "1", "2", false },
{ "2", "1", false },
{ "2", "2", true },
{ NULL, NULL, false }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->v1 != NULL; t++) {
atf::tests::vars_map config;
config["v1"] = t->v1;
config["v2"] = t->v2;
std::cout << "Checking with " << t->v1 << ", " << t->v2
<< " and expecting " << (t->ok ? "true" : "false")
<< "\n";
ATF_TEST_CASE_USE(h_require_eq);
run_h_tc< ATF_TEST_CASE_NAME(h_require_eq) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
ATF_REQUIRE(grep_file("result", "^failed: .*v1 != v2"));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_in);
ATF_TEST_CASE_HEAD(require_in)
{
set_md_var("descr", "Tests the ATF_REQUIRE_IN macro");
}
ATF_TEST_CASE_BODY(require_in)
{
struct test {
const char *value;
bool ok;
} *t, tests[] = {
{ "foo", true },
{ "bar", true },
{ "baz", true },
{ "xxx", false },
{ "fooa", false },
{ "foo ", false },
{ NULL, false }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->value != NULL; t++) {
atf::tests::vars_map config;
config["value"] = t->value;
ATF_TEST_CASE_USE(h_require_in);
run_h_tc< ATF_TEST_CASE_NAME(h_require_in) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
ATF_REQUIRE(grep_file("result", "^failed: "));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_match);
ATF_TEST_CASE_HEAD(require_match)
{
set_md_var("descr", "Tests the ATF_REQUIRE_MATCH macro");
}
ATF_TEST_CASE_BODY(require_match)
{
struct test {
const char *regexp;
const char *string;
bool ok;
} *t, tests[] = {
{ "foo.*bar", "this is a foo, bar, baz", true },
{ "bar.*baz", "this is a baz, bar, foo", false },
{ NULL, NULL, false }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->regexp != NULL; t++) {
atf::tests::vars_map config;
config["regexp"] = t->regexp;
config["string"] = t->string;
std::cout << "Checking with " << t->regexp << ", " << t->string
<< " and expecting " << (t->ok ? "true" : "false")
<< "\n";
ATF_TEST_CASE_USE(h_require_match);
run_h_tc< ATF_TEST_CASE_NAME(h_require_match) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
ATF_REQUIRE(grep_file("result", "^failed: "));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_not_in);
ATF_TEST_CASE_HEAD(require_not_in)
{
set_md_var("descr", "Tests the ATF_REQUIRE_NOT_IN macro");
}
ATF_TEST_CASE_BODY(require_not_in)
{
struct test {
const char *value;
bool ok;
} *t, tests[] = {
{ "foo", false },
{ "bar", false },
{ "baz", false },
{ "xxx", true },
{ "fooa", true },
{ "foo ", true },
{ NULL, false }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->value != NULL; t++) {
atf::tests::vars_map config;
config["value"] = t->value;
ATF_TEST_CASE_USE(h_require_not_in);
run_h_tc< ATF_TEST_CASE_NAME(h_require_not_in) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
ATF_REQUIRE(grep_file("result", "^failed: "));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_throw);
ATF_TEST_CASE_HEAD(require_throw)
{
set_md_var("descr", "Tests the ATF_REQUIRE_THROW macro");
}
ATF_TEST_CASE_BODY(require_throw)
{
struct test {
const char *what;
bool ok;
const char *msg;
} *t, tests[] = {
{ "throw_int", false, "unexpected error" },
{ "throw_rt", true, NULL },
{ "no_throw_rt", false, "did not throw" },
{ NULL, false, NULL }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->what != NULL; t++) {
atf::tests::vars_map config;
config["what"] = t->what;
std::cout << "Checking with " << t->what << " and expecting "
<< (t->ok ? "true" : "false") << "\n";
ATF_TEST_CASE_USE(h_require_throw);
run_h_tc< ATF_TEST_CASE_NAME(h_require_throw) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
std::cout << "Checking that message contains '" << t->msg
<< "'\n";
std::string exp_result = std::string("^failed: .*") + t->msg;
ATF_REQUIRE(grep_file("result", exp_result.c_str()));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_throw_re);
ATF_TEST_CASE_HEAD(require_throw_re)
{
set_md_var("descr", "Tests the ATF_REQUIRE_THROW_RE macro");
}
ATF_TEST_CASE_BODY(require_throw_re)
{
struct test {
const char *what;
bool ok;
const char *msg;
} *t, tests[] = {
{ "throw_int", false, "unexpected error" },
{ "throw_rt_match", true, NULL },
{ "throw_rt_no_match", false,
"threw.*runtime_error\\(baz foo bar a\\).*"
"does not match 'foo\\.\\*baz'" },
{ "no_throw_rt", false, "did not throw" },
{ NULL, false, NULL }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->what != NULL; t++) {
atf::tests::vars_map config;
config["what"] = t->what;
std::cout << "Checking with " << t->what << " and expecting "
<< (t->ok ? "true" : "false") << "\n";
ATF_TEST_CASE_USE(h_require_throw_re);
run_h_tc< ATF_TEST_CASE_NAME(h_require_throw_re) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
std::cout << "Checking that message contains '" << t->msg
<< "'\n";
std::string exp_result = std::string("^failed: .*") + t->msg;
ATF_REQUIRE(grep_file("result", exp_result.c_str()));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
ATF_TEST_CASE(check_errno);
ATF_TEST_CASE_HEAD(check_errno)
{
set_md_var("descr", "Tests the ATF_CHECK_ERRNO macro");
}
ATF_TEST_CASE_BODY(check_errno)
{
struct test {
const char *what;
bool ok;
const char *msg;
} *t, tests[] = {
{ "no_error", false,
"Expected true value in errno_ok_stub\\(\\) == -1" },
{ "errno_ok", true, NULL },
{ "errno_fail", false,
"Expected errno 3, got 4, in errno_fail_stub\\(4\\) == -1" },
{ NULL, false, NULL }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->what != NULL; t++) {
atf::tests::vars_map config;
config["what"] = t->what;
ATF_TEST_CASE_USE(h_check_errno);
run_h_tc< ATF_TEST_CASE_NAME(h_check_errno) >(config);
ATF_REQUIRE(atf::fs::exists(before));
ATF_REQUIRE(atf::fs::exists(after));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
} else {
ATF_REQUIRE(grep_file("result", "^failed"));
std::string exp_result = "macros_test.cpp:[0-9]+: " +
std::string(t->msg) + "$";
ATF_REQUIRE(grep_file("stderr", exp_result.c_str()));
}
atf::fs::remove(before);
atf::fs::remove(after);
}
}
ATF_TEST_CASE(require_errno);
ATF_TEST_CASE_HEAD(require_errno)
{
set_md_var("descr", "Tests the ATF_REQUIRE_ERRNO macro");
}
ATF_TEST_CASE_BODY(require_errno)
{
struct test {
const char *what;
bool ok;
const char *msg;
} *t, tests[] = {
{ "no_error", false,
"Expected true value in errno_ok_stub\\(\\) == -1" },
{ "errno_ok", true, NULL },
{ "errno_fail", false,
"Expected errno 3, got 4, in errno_fail_stub\\(4\\) == -1" },
{ NULL, false, NULL }
};
const atf::fs::path before("before");
const atf::fs::path after("after");
for (t = &tests[0]; t->what != NULL; t++) {
atf::tests::vars_map config;
config["what"] = t->what;
ATF_TEST_CASE_USE(h_require_errno);
run_h_tc< ATF_TEST_CASE_NAME(h_require_errno) >(config);
ATF_REQUIRE(atf::fs::exists(before));
if (t->ok) {
ATF_REQUIRE(grep_file("result", "^passed"));
ATF_REQUIRE(atf::fs::exists(after));
} else {
std::string exp_result = "^failed: .*macros_test.cpp:[0-9]+: " +
std::string(t->msg) + "$";
ATF_REQUIRE(grep_file("result", exp_result.c_str()));
ATF_REQUIRE(!atf::fs::exists(after));
}
atf::fs::remove(before);
if (t->ok)
atf::fs::remove(after);
}
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/macros.hpp");
BUILD_TC(use, "macros_hpp_test.cpp",
"Tests that the macros provided by the atf-c++/macros.hpp file "
"do not cause syntax errors when used",
"Build of macros_hpp_test.cpp failed; some macros in "
"atf-c++/macros.hpp are broken");
BUILD_TC_FAIL(detect_unused_tests, "unused_test.cpp",
"Tests that defining an unused test case raises a warning (and thus "
"an error)",
"Build of unused_test.cpp passed; unused test cases are not properly "
"detected");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the macros.
ATF_ADD_TEST_CASE(tcs, pass);
ATF_ADD_TEST_CASE(tcs, fail);
ATF_ADD_TEST_CASE(tcs, skip);
ATF_ADD_TEST_CASE(tcs, check_errno);
ATF_ADD_TEST_CASE(tcs, require);
ATF_ADD_TEST_CASE(tcs, require_eq);
ATF_ADD_TEST_CASE(tcs, require_in);
ATF_ADD_TEST_CASE(tcs, require_match);
ATF_ADD_TEST_CASE(tcs, require_not_in);
ATF_ADD_TEST_CASE(tcs, require_throw);
ATF_ADD_TEST_CASE(tcs, require_throw_re);
ATF_ADD_TEST_CASE(tcs, require_errno);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
ATF_ADD_TEST_CASE(tcs, use);
ATF_ADD_TEST_CASE(tcs, detect_unused_tests);
}

149
atf-c++/pkg_config_test.sh Normal file
View File

@ -0,0 +1,149 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2008 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The following tests assume that the atfc++.pc file is installed in a
# directory that is known by pkg-config. Otherwise they will fail,
# and you will be required to adjust PKG_CONFIG_PATH accordingly.
#
# It would be possible to bypass this requirement by setting the path
# explicitly during the tests, but then this would not do a real check
# to ensure that the installation is working.
require_pc()
{
pkg-config ${1} || atf_fail "pkg-config could not locate ${1}.pc;" \
"maybe need to set PKG_CONFIG_PATH?"
}
check_version()
{
atf_check -s eq:0 -o save:stdout -e empty -x \
"atf-version | head -n 1 | cut -d ' ' -f 4"
ver1=$(cat stdout)
echo "Version reported by atf-version: ${ver1}"
atf_check -s eq:0 -o save:stdout -e empty pkg-config --modversion "${1}"
ver2=$(cat stdout)
echo "Version reported by pkg-config: ${ver2}"
atf_check_equal ${ver1} ${ver2}
}
atf_test_case version
version_head()
{
atf_set "descr" "Checks that the version in atf-c++ is correct"
atf_set "require.progs" "pkg-config"
}
version_body()
{
require_pc "atf-c++"
check_version "atf-c++"
}
atf_test_case build
build_head()
{
atf_set "descr" "Checks that a test program can be built against" \
"the C++ library based on the pkg-config information"
atf_set "require.progs" "pkg-config"
}
build_body()
{
require_pc "atf-c++"
atf_check -s eq:0 -o save:stdout -e empty \
pkg-config --variable=cxx atf-c++
cxx=$(cat stdout)
echo "Compiler is: ${cxx}"
atf_require_prog ${cxx}
cat >tp.cpp <<EOF
#include <iostream>
#include <atf-c++.hpp>
ATF_TEST_CASE(tc);
ATF_TEST_CASE_HEAD(tc) {
set_md_var("descr", "A test case");
}
ATF_TEST_CASE_BODY(tc) {
std::cout << "Running\n";
}
ATF_INIT_TEST_CASES(tcs) {
ATF_ADD_TEST_CASE(tcs, tc);
}
EOF
atf_check -s eq:0 -o save:stdout -e empty pkg-config --cflags atf-c++
cxxflags=$(cat stdout)
echo "CXXFLAGS are: ${cxxflags}"
atf_check -s eq:0 -o save:stdout -e empty \
pkg-config --libs-only-L --libs-only-other atf-c++
ldflags=$(cat stdout)
atf_check -s eq:0 -o save:stdout -e empty \
pkg-config --libs-only-l atf-c++
libs=$(cat stdout)
echo "LDFLAGS are: ${ldflags}"
echo "LIBS are: ${libs}"
atf_check -s eq:0 -o empty -e empty ${cxx} ${cxxflags} -o tp.o -c tp.cpp
atf_check -s eq:0 -o empty -e empty ${cxx} ${ldflags} -o tp tp.o ${libs}
libpath=
for f in ${ldflags}; do
case ${f} in
-L*)
dir=$(echo ${f} | sed -e 's,^-L,,')
if [ -z "${libpath}" ]; then
libpath="${dir}"
else
libpath="${libpath}:${dir}"
fi
;;
*)
;;
esac
done
atf_check -s eq:0 -o empty -e empty test -x tp
atf_check -s eq:0 -o match:'Running' -e empty -x \
"LD_LIBRARY_PATH=${libpath} ./tp tc"
}
atf_init_test_cases()
{
atf_add_test_case version
atf_add_test_case build
}
# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4

710
atf-c++/tests.cpp Normal file
View File

@ -0,0 +1,710 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
}
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <vector>
extern "C" {
#include "atf-c/error.h"
#include "atf-c/tc.h"
#include "atf-c/utils.h"
}
#include "tests.hpp"
#include "detail/application.hpp"
#include "detail/env.hpp"
#include "detail/exceptions.hpp"
#include "detail/fs.hpp"
#include "detail/parser.hpp"
#include "detail/sanity.hpp"
#include "detail/text.hpp"
namespace impl = atf::tests;
namespace detail = atf::tests::detail;
#define IMPL_NAME "atf::tests"
// ------------------------------------------------------------------------
// The "atf_tp_writer" class.
// ------------------------------------------------------------------------
detail::atf_tp_writer::atf_tp_writer(std::ostream& os) :
m_os(os),
m_is_first(true)
{
atf::parser::headers_map hm;
atf::parser::attrs_map ct_attrs;
ct_attrs["version"] = "1";
hm["Content-Type"] = atf::parser::header_entry("Content-Type",
"application/X-atf-tp", ct_attrs);
atf::parser::write_headers(hm, m_os);
}
void
detail::atf_tp_writer::start_tc(const std::string& ident)
{
if (!m_is_first)
m_os << "\n";
m_os << "ident: " << ident << "\n";
m_os.flush();
}
void
detail::atf_tp_writer::end_tc(void)
{
if (m_is_first)
m_is_first = false;
}
void
detail::atf_tp_writer::tc_meta_data(const std::string& name,
const std::string& value)
{
PRE(name != "ident");
m_os << name << ": " << value << "\n";
m_os.flush();
}
// ------------------------------------------------------------------------
// Free helper functions.
// ------------------------------------------------------------------------
bool
detail::match(const std::string& regexp, const std::string& str)
{
return atf::text::match(str, regexp);
}
// ------------------------------------------------------------------------
// The "tc" class.
// ------------------------------------------------------------------------
static std::map< atf_tc_t*, impl::tc* > wraps;
static std::map< const atf_tc_t*, const impl::tc* > cwraps;
struct impl::tc_impl : atf::utils::noncopyable {
std::string m_ident;
atf_tc_t m_tc;
bool m_has_cleanup;
tc_impl(const std::string& ident, const bool has_cleanup) :
m_ident(ident),
m_has_cleanup(has_cleanup)
{
}
static void
wrap_head(atf_tc_t *tc)
{
std::map< atf_tc_t*, impl::tc* >::iterator iter = wraps.find(tc);
INV(iter != wraps.end());
(*iter).second->head();
}
static void
wrap_body(const atf_tc_t *tc)
{
std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
cwraps.find(tc);
INV(iter != cwraps.end());
try {
(*iter).second->body();
} catch (const std::exception& e) {
(*iter).second->fail("Caught unhandled exception: " + std::string(
e.what()));
} catch (...) {
(*iter).second->fail("Caught unknown exception");
}
}
static void
wrap_cleanup(const atf_tc_t *tc)
{
std::map< const atf_tc_t*, const impl::tc* >::const_iterator iter =
cwraps.find(tc);
INV(iter != cwraps.end());
(*iter).second->cleanup();
}
};
impl::tc::tc(const std::string& ident, const bool has_cleanup) :
pimpl(new tc_impl(ident, has_cleanup))
{
}
impl::tc::~tc(void)
{
cwraps.erase(&pimpl->m_tc);
wraps.erase(&pimpl->m_tc);
atf_tc_fini(&pimpl->m_tc);
}
void
impl::tc::init(const vars_map& config)
{
atf_error_t err;
utils::auto_array< const char * > array(
new const char*[(config.size() * 2) + 1]);
const char **ptr = array.get();
for (vars_map::const_iterator iter = config.begin();
iter != config.end(); iter++) {
*ptr = (*iter).first.c_str();
*(ptr + 1) = (*iter).second.c_str();
ptr += 2;
}
*ptr = NULL;
wraps[&pimpl->m_tc] = this;
cwraps[&pimpl->m_tc] = this;
err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head,
pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL,
array.get());
if (atf_is_error(err))
throw_atf_error(err);
}
bool
impl::tc::has_config_var(const std::string& var)
const
{
return atf_tc_has_config_var(&pimpl->m_tc, var.c_str());
}
bool
impl::tc::has_md_var(const std::string& var)
const
{
return atf_tc_has_md_var(&pimpl->m_tc, var.c_str());
}
const std::string
impl::tc::get_config_var(const std::string& var)
const
{
return atf_tc_get_config_var(&pimpl->m_tc, var.c_str());
}
const std::string
impl::tc::get_config_var(const std::string& var, const std::string& defval)
const
{
return atf_tc_get_config_var_wd(&pimpl->m_tc, var.c_str(), defval.c_str());
}
const std::string
impl::tc::get_md_var(const std::string& var)
const
{
return atf_tc_get_md_var(&pimpl->m_tc, var.c_str());
}
const impl::vars_map
impl::tc::get_md_vars(void)
const
{
vars_map vars;
char **array = atf_tc_get_md_vars(&pimpl->m_tc);
try {
char **ptr;
for (ptr = array; *ptr != NULL; ptr += 2)
vars[*ptr] = *(ptr + 1);
} catch (...) {
atf_utils_free_charpp(array);
throw;
}
return vars;
}
void
impl::tc::set_md_var(const std::string& var, const std::string& val)
{
atf_error_t err = atf_tc_set_md_var(&pimpl->m_tc, var.c_str(), val.c_str());
if (atf_is_error(err))
throw_atf_error(err);
}
void
impl::tc::run(const std::string& resfile)
const
{
atf_error_t err = atf_tc_run(&pimpl->m_tc, resfile.c_str());
if (atf_is_error(err))
throw_atf_error(err);
}
void
impl::tc::run_cleanup(void)
const
{
atf_error_t err = atf_tc_cleanup(&pimpl->m_tc);
if (atf_is_error(err))
throw_atf_error(err);
}
void
impl::tc::head(void)
{
}
void
impl::tc::cleanup(void)
const
{
}
void
impl::tc::require_prog(const std::string& prog)
const
{
atf_tc_require_prog(prog.c_str());
}
void
impl::tc::pass(void)
{
atf_tc_pass();
}
void
impl::tc::fail(const std::string& reason)
{
atf_tc_fail("%s", reason.c_str());
}
void
impl::tc::fail_nonfatal(const std::string& reason)
{
atf_tc_fail_nonfatal("%s", reason.c_str());
}
void
impl::tc::skip(const std::string& reason)
{
atf_tc_skip("%s", reason.c_str());
}
void
impl::tc::check_errno(const char* file, const int line, const int exp_errno,
const char* expr_str, const bool result)
{
atf_tc_check_errno(file, line, exp_errno, expr_str, result);
}
void
impl::tc::require_errno(const char* file, const int line, const int exp_errno,
const char* expr_str, const bool result)
{
atf_tc_require_errno(file, line, exp_errno, expr_str, result);
}
void
impl::tc::expect_pass(void)
{
atf_tc_expect_pass();
}
void
impl::tc::expect_fail(const std::string& reason)
{
atf_tc_expect_fail("%s", reason.c_str());
}
void
impl::tc::expect_exit(const int exitcode, const std::string& reason)
{
atf_tc_expect_exit(exitcode, "%s", reason.c_str());
}
void
impl::tc::expect_signal(const int signo, const std::string& reason)
{
atf_tc_expect_signal(signo, "%s", reason.c_str());
}
void
impl::tc::expect_death(const std::string& reason)
{
atf_tc_expect_death("%s", reason.c_str());
}
void
impl::tc::expect_timeout(const std::string& reason)
{
atf_tc_expect_timeout("%s", reason.c_str());
}
// ------------------------------------------------------------------------
// The "tp" class.
// ------------------------------------------------------------------------
class tp : public atf::application::app {
public:
typedef std::vector< impl::tc * > tc_vector;
private:
static const char* m_description;
bool m_lflag;
atf::fs::path m_resfile;
std::string m_srcdir_arg;
atf::fs::path m_srcdir;
atf::tests::vars_map m_vars;
std::string specific_args(void) const;
options_set specific_options(void) const;
void process_option(int, const char*);
void (*m_add_tcs)(tc_vector&);
tc_vector m_tcs;
void parse_vflag(const std::string&);
void handle_srcdir(void);
tc_vector init_tcs(void);
enum tc_part {
BODY,
CLEANUP,
};
void list_tcs(void);
impl::tc* find_tc(tc_vector, const std::string&);
static std::pair< std::string, tc_part > process_tcarg(const std::string&);
int run_tc(const std::string&);
public:
tp(void (*)(tc_vector&));
~tp(void);
int main(void);
};
const char* tp::m_description =
"This is an independent atf test program.";
tp::tp(void (*add_tcs)(tc_vector&)) :
app(m_description, "atf-test-program(1)", "atf(7)", false),
m_lflag(false),
m_resfile("/dev/stdout"),
m_srcdir("."),
m_add_tcs(add_tcs)
{
}
tp::~tp(void)
{
for (tc_vector::iterator iter = m_tcs.begin();
iter != m_tcs.end(); iter++) {
impl::tc* tc = *iter;
delete tc;
}
}
std::string
tp::specific_args(void)
const
{
return "test_case";
}
tp::options_set
tp::specific_options(void)
const
{
using atf::application::option;
options_set opts;
opts.insert(option('l', "", "List test cases and their purpose"));
opts.insert(option('r', "resfile", "The file to which the test program "
"will write the results of the "
"executed test case"));
opts.insert(option('s', "srcdir", "Directory where the test's data "
"files are located"));
opts.insert(option('v', "var=value", "Sets the configuration variable "
"`var' to `value'"));
return opts;
}
void
tp::process_option(int ch, const char* arg)
{
switch (ch) {
case 'l':
m_lflag = true;
break;
case 'r':
m_resfile = atf::fs::path(arg);
break;
case 's':
m_srcdir_arg = arg;
break;
case 'v':
parse_vflag(arg);
break;
default:
UNREACHABLE;
}
}
void
tp::parse_vflag(const std::string& str)
{
if (str.empty())
throw std::runtime_error("-v requires a non-empty argument");
std::vector< std::string > ws = atf::text::split(str, "=");
if (ws.size() == 1 && str[str.length() - 1] == '=') {
m_vars[ws[0]] = "";
} else {
if (ws.size() != 2)
throw std::runtime_error("-v requires an argument of the form "
"var=value");
m_vars[ws[0]] = ws[1];
}
}
void
tp::handle_srcdir(void)
{
if (m_srcdir_arg.empty()) {
m_srcdir = atf::fs::path(m_argv0).branch_path();
if (m_srcdir.leaf_name() == ".libs")
m_srcdir = m_srcdir.branch_path();
} else
m_srcdir = atf::fs::path(m_srcdir_arg);
if (!atf::fs::exists(m_srcdir / m_prog_name))
throw std::runtime_error("Cannot find the test program in the "
"source directory `" + m_srcdir.str() + "'");
if (!m_srcdir.is_absolute())
m_srcdir = m_srcdir.to_absolute();
m_vars["srcdir"] = m_srcdir.str();
}
tp::tc_vector
tp::init_tcs(void)
{
m_add_tcs(m_tcs);
for (tc_vector::iterator iter = m_tcs.begin();
iter != m_tcs.end(); iter++) {
impl::tc* tc = *iter;
tc->init(m_vars);
}
return m_tcs;
}
//
// An auxiliary unary predicate that compares the given test case's
// identifier to the identifier stored in it.
//
class tc_equal_to_ident {
const std::string& m_ident;
public:
tc_equal_to_ident(const std::string& i) :
m_ident(i)
{
}
bool operator()(const impl::tc* tc)
{
return tc->get_md_var("ident") == m_ident;
}
};
void
tp::list_tcs(void)
{
tc_vector tcs = init_tcs();
detail::atf_tp_writer writer(std::cout);
for (tc_vector::const_iterator iter = tcs.begin();
iter != tcs.end(); iter++) {
const impl::vars_map vars = (*iter)->get_md_vars();
{
impl::vars_map::const_iterator iter2 = vars.find("ident");
INV(iter2 != vars.end());
writer.start_tc((*iter2).second);
}
for (impl::vars_map::const_iterator iter2 = vars.begin();
iter2 != vars.end(); iter2++) {
const std::string& key = (*iter2).first;
if (key != "ident")
writer.tc_meta_data(key, (*iter2).second);
}
writer.end_tc();
}
}
impl::tc*
tp::find_tc(tc_vector tcs, const std::string& name)
{
std::vector< std::string > ids;
for (tc_vector::iterator iter = tcs.begin();
iter != tcs.end(); iter++) {
impl::tc* tc = *iter;
if (tc->get_md_var("ident") == name)
return tc;
}
throw atf::application::usage_error("Unknown test case `%s'",
name.c_str());
}
std::pair< std::string, tp::tc_part >
tp::process_tcarg(const std::string& tcarg)
{
const std::string::size_type pos = tcarg.find(':');
if (pos == std::string::npos) {
return std::make_pair(tcarg, BODY);
} else {
const std::string tcname = tcarg.substr(0, pos);
const std::string partname = tcarg.substr(pos + 1);
if (partname == "body")
return std::make_pair(tcname, BODY);
else if (partname == "cleanup")
return std::make_pair(tcname, CLEANUP);
else {
using atf::application::usage_error;
throw usage_error("Invalid test case part `%s'", partname.c_str());
}
}
}
int
tp::run_tc(const std::string& tcarg)
{
const std::pair< std::string, tc_part > fields = process_tcarg(tcarg);
impl::tc* tc = find_tc(init_tcs(), fields.first);
if (!atf::env::has("__RUNNING_INSIDE_ATF_RUN") || atf::env::get(
"__RUNNING_INSIDE_ATF_RUN") != "internal-yes-value")
{
std::cerr << m_prog_name << ": WARNING: Running test cases without "
"atf-run(1) is unsupported\n";
std::cerr << m_prog_name << ": WARNING: No isolation nor timeout "
"control is being applied; you may get unexpected failures; see "
"atf-test-case(4)\n";
}
try {
switch (fields.second) {
case BODY:
tc->run(m_resfile.str());
break;
case CLEANUP:
tc->run_cleanup();
break;
default:
UNREACHABLE;
}
return EXIT_SUCCESS;
} catch (const std::runtime_error& e) {
std::cerr << "ERROR: " << e.what() << "\n";
return EXIT_FAILURE;
}
}
int
tp::main(void)
{
using atf::application::usage_error;
int errcode;
handle_srcdir();
if (m_lflag) {
if (m_argc > 0)
throw usage_error("Cannot provide test case names with -l");
list_tcs();
errcode = EXIT_SUCCESS;
} else {
if (m_argc == 0)
throw usage_error("Must provide a test case name");
else if (m_argc > 1)
throw usage_error("Cannot provide more than one test case name");
INV(m_argc == 1);
errcode = run_tc(m_argv[0]);
}
return errcode;
}
namespace atf {
namespace tests {
int run_tp(int, char* const*, void (*)(tp::tc_vector&));
}
}
int
impl::run_tp(int argc, char* const* argv, void (*add_tcs)(tp::tc_vector&))
{
return tp(add_tcs).run(argc, argv);
}

127
atf-c++/tests.hpp Normal file
View File

@ -0,0 +1,127 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_TESTS_HPP_)
#define _ATF_CXX_TESTS_HPP_
#include <map>
#include <memory>
#include <string>
extern "C" {
#include <atf-c/defs.h>
}
#include <atf-c++/utils.hpp>
namespace atf {
namespace tests {
namespace detail {
class atf_tp_writer {
std::ostream& m_os;
bool m_is_first;
public:
atf_tp_writer(std::ostream&);
void start_tc(const std::string&);
void end_tc(void);
void tc_meta_data(const std::string&, const std::string&);
};
bool match(const std::string&, const std::string&);
} // namespace
// ------------------------------------------------------------------------
// The "vars_map" class.
// ------------------------------------------------------------------------
typedef std::map< std::string, std::string > vars_map;
// ------------------------------------------------------------------------
// The "tc" class.
// ------------------------------------------------------------------------
struct tc_impl;
class tc : utils::noncopyable {
std::auto_ptr< tc_impl > pimpl;
protected:
virtual void head(void);
virtual void body(void) const = 0;
virtual void cleanup(void) const;
void require_prog(const std::string&) const;
friend struct tc_impl;
public:
tc(const std::string&, const bool);
virtual ~tc(void);
void init(const vars_map&);
const std::string get_config_var(const std::string&) const;
const std::string get_config_var(const std::string&, const std::string&)
const;
const std::string get_md_var(const std::string&) const;
const vars_map get_md_vars(void) const;
bool has_config_var(const std::string&) const;
bool has_md_var(const std::string&) const;
void set_md_var(const std::string&, const std::string&);
void run(const std::string&) const;
void run_cleanup(void) const;
// To be called from the child process only.
static void pass(void) ATF_DEFS_ATTRIBUTE_NORETURN;
static void fail(const std::string&) ATF_DEFS_ATTRIBUTE_NORETURN;
static void fail_nonfatal(const std::string&);
static void skip(const std::string&) ATF_DEFS_ATTRIBUTE_NORETURN;
static void check_errno(const char*, const int, const int, const char*,
const bool);
static void require_errno(const char*, const int, const int, const char*,
const bool);
static void expect_pass(void);
static void expect_fail(const std::string&);
static void expect_exit(const int, const std::string&);
static void expect_signal(const int, const std::string&);
static void expect_death(const std::string&);
static void expect_timeout(const std::string&);
};
} // namespace tests
} // namespace atf
#endif // !defined(_ATF_CXX_TESTS_HPP_)

201
atf-c++/tests_test.cpp Normal file
View File

@ -0,0 +1,201 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
}
#include <fstream>
#include <sstream>
#include "macros.hpp"
#include "detail/parser.hpp"
#include "detail/test_helpers.hpp"
// ------------------------------------------------------------------------
// Tests for the "atf_tp_writer" class.
// ------------------------------------------------------------------------
static
void
print_indented(const std::string& str)
{
std::vector< std::string > ws = atf::text::split(str, "\n");
for (std::vector< std::string >::const_iterator iter = ws.begin();
iter != ws.end(); iter++)
std::cout << ">>" << *iter << "<<\n";
}
// XXX Should this string handling and verbosity level be part of the
// ATF_REQUIRE_EQ macro? It may be hard to predict sometimes that a
// string can have newlines in it, and so the error message generated
// at the moment will be bogus if there are some.
static
void
check_equal(const atf::tests::tc& tc, const std::string& str,
const std::string& exp)
{
if (str != exp) {
std::cout << "String equality check failed.\n"
"Adding >> and << to delimit the string boundaries below.\n";
std::cout << "GOT:\n";
print_indented(str);
std::cout << "EXPECTED:\n";
print_indented(exp);
tc.fail("Constructed string differs from the expected one");
}
}
ATF_TEST_CASE(atf_tp_writer);
ATF_TEST_CASE_HEAD(atf_tp_writer)
{
set_md_var("descr", "Verifies the application/X-atf-tp writer");
}
ATF_TEST_CASE_BODY(atf_tp_writer)
{
std::ostringstream expss;
std::ostringstream ss;
#define RESET \
expss.str(""); \
ss.str("")
#define CHECK \
check_equal(*this, ss.str(), expss.str())
{
RESET;
atf::tests::detail::atf_tp_writer w(ss);
expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
CHECK;
}
{
RESET;
atf::tests::detail::atf_tp_writer w(ss);
expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
CHECK;
w.start_tc("test1");
expss << "ident: test1\n";
CHECK;
w.end_tc();
CHECK;
}
{
RESET;
atf::tests::detail::atf_tp_writer w(ss);
expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
CHECK;
w.start_tc("test1");
expss << "ident: test1\n";
CHECK;
w.end_tc();
CHECK;
w.start_tc("test2");
expss << "\nident: test2\n";
CHECK;
w.end_tc();
CHECK;
}
{
RESET;
atf::tests::detail::atf_tp_writer w(ss);
expss << "Content-Type: application/X-atf-tp; version=\"1\"\n\n";
CHECK;
w.start_tc("test1");
expss << "ident: test1\n";
CHECK;
w.tc_meta_data("descr", "the description");
expss << "descr: the description\n";
CHECK;
w.end_tc();
CHECK;
w.start_tc("test2");
expss << "\nident: test2\n";
CHECK;
w.tc_meta_data("descr", "second test case");
expss << "descr: second test case\n";
CHECK;
w.tc_meta_data("require.progs", "/bin/cp");
expss << "require.progs: /bin/cp\n";
CHECK;
w.tc_meta_data("X-custom", "foo bar baz");
expss << "X-custom: foo bar baz\n";
CHECK;
w.end_tc();
CHECK;
}
#undef CHECK
#undef RESET
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/tests.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add tests for the "atf_tp_writer" class.
ATF_ADD_TEST_CASE(tcs, atf_tp_writer);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

52
atf-c++/unused_test.cpp Normal file
View File

@ -0,0 +1,52 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2012 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <atf-c++/macros.hpp>
ATF_TEST_CASE(this_is_used);
ATF_TEST_CASE_HEAD(this_is_used)
{
}
ATF_TEST_CASE_BODY(this_is_used)
{
}
ATF_TEST_CASE(this_is_unused);
ATF_TEST_CASE_HEAD(this_is_unused)
{
}
ATF_TEST_CASE_BODY(this_is_unused)
{
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, this_is_used);
//ATF_ADD_TEST_CASE(tcs, this_is_unused);
}

200
atf-c++/utils.hpp Normal file
View File

@ -0,0 +1,200 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(_ATF_CXX_UTILS_HPP_)
#define _ATF_CXX_UTILS_HPP_
#include <cstddef>
namespace atf {
namespace utils {
// ------------------------------------------------------------------------
// The "auto_array" class.
// ------------------------------------------------------------------------
template< class T >
struct auto_array_ref {
T* m_ptr;
explicit auto_array_ref(T*);
};
template< class T >
auto_array_ref< T >::auto_array_ref(T* ptr) :
m_ptr(ptr)
{
}
template< class T >
class auto_array {
T* m_ptr;
public:
auto_array(T* = NULL) throw();
auto_array(auto_array< T >&) throw();
auto_array(auto_array_ref< T >) throw();
~auto_array(void) throw();
T* get(void) throw();
const T* get(void) const throw();
T* release(void) throw();
void reset(T* = NULL) throw();
auto_array< T >& operator=(auto_array< T >&) throw();
auto_array< T >& operator=(auto_array_ref< T >) throw();
T& operator[](int) throw();
operator auto_array_ref< T >(void) throw();
};
template< class T >
auto_array< T >::auto_array(T* ptr)
throw() :
m_ptr(ptr)
{
}
template< class T >
auto_array< T >::auto_array(auto_array< T >& ptr)
throw() :
m_ptr(ptr.release())
{
}
template< class T >
auto_array< T >::auto_array(auto_array_ref< T > ref)
throw() :
m_ptr(ref.m_ptr)
{
}
template< class T >
auto_array< T >::~auto_array(void)
throw()
{
if (m_ptr != NULL)
delete [] m_ptr;
}
template< class T >
T*
auto_array< T >::get(void)
throw()
{
return m_ptr;
}
template< class T >
const T*
auto_array< T >::get(void)
const throw()
{
return m_ptr;
}
template< class T >
T*
auto_array< T >::release(void)
throw()
{
T* ptr = m_ptr;
m_ptr = NULL;
return ptr;
}
template< class T >
void
auto_array< T >::reset(T* ptr)
throw()
{
if (m_ptr != NULL)
delete [] m_ptr;
m_ptr = ptr;
}
template< class T >
auto_array< T >&
auto_array< T >::operator=(auto_array< T >& ptr)
throw()
{
reset(ptr.release());
return *this;
}
template< class T >
auto_array< T >&
auto_array< T >::operator=(auto_array_ref< T > ref)
throw()
{
if (m_ptr != ref.m_ptr) {
delete [] m_ptr;
m_ptr = ref.m_ptr;
}
return *this;
}
template< class T >
T&
auto_array< T >::operator[](int pos)
throw()
{
return m_ptr[pos];
}
template< class T >
auto_array< T >::operator auto_array_ref< T >(void)
throw()
{
return auto_array_ref< T >(release());
}
// ------------------------------------------------------------------------
// The "noncopyable" class.
// ------------------------------------------------------------------------
class noncopyable {
// The class cannot be empty; otherwise we get ABI-stability warnings
// during the build, which will break it due to strict checking.
int m_noncopyable_dummy;
noncopyable(const noncopyable& nc);
noncopyable& operator=(const noncopyable& nc);
protected:
// Explicitly needed to provide some non-private functions. Otherwise
// we also get some warnings during the build.
noncopyable(void) {}
~noncopyable(void) {}
};
} // namespace utils
} // namespace atf
#endif // !defined(_ATF_CXX_UTILS_HPP_)

310
atf-c++/utils_test.cpp Normal file
View File

@ -0,0 +1,310 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <iostream>
#include "atf-c/defs.h"
#include "macros.hpp"
#include "utils.hpp"
#include "detail/test_helpers.hpp"
// ------------------------------------------------------------------------
// Tests for the "auto_array" class.
// ------------------------------------------------------------------------
class test_array {
public:
int m_value;
static ssize_t m_nblocks;
static
atf::utils::auto_array< test_array >
do_copy(atf::utils::auto_array< test_array >& ta)
{
return atf::utils::auto_array< test_array >(ta);
}
void* operator new(size_t size ATF_DEFS_ATTRIBUTE_UNUSED)
{
ATF_FAIL("New called but should have been new[]");
return new int(5);
}
void* operator new[](size_t size)
{
m_nblocks++;
void* mem = ::operator new(size);
std::cout << "Allocated 'test_array' object " << mem << "\n";
return mem;
}
void operator delete(void* mem ATF_DEFS_ATTRIBUTE_UNUSED)
{
ATF_FAIL("Delete called but should have been delete[]");
}
void operator delete[](void* mem)
{
std::cout << "Releasing 'test_array' object " << mem << "\n";
if (m_nblocks == 0)
ATF_FAIL("Unbalanced delete[]");
m_nblocks--;
::operator delete(mem);
}
};
ssize_t test_array::m_nblocks = 0;
ATF_TEST_CASE(auto_array_scope);
ATF_TEST_CASE_HEAD(auto_array_scope)
{
set_md_var("descr", "Tests the automatic scope handling in the "
"auto_array smart pointer class");
}
ATF_TEST_CASE_BODY(auto_array_scope)
{
using atf::utils::auto_array;
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
{
auto_array< test_array > t(new test_array[10]);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_copy);
ATF_TEST_CASE_HEAD(auto_array_copy)
{
set_md_var("descr", "Tests the auto_array smart pointer class' copy "
"constructor");
}
ATF_TEST_CASE_BODY(auto_array_copy)
{
using atf::utils::auto_array;
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
{
auto_array< test_array > t1(new test_array[10]);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
{
auto_array< test_array > t2(t1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_copy_ref);
ATF_TEST_CASE_HEAD(auto_array_copy_ref)
{
set_md_var("descr", "Tests the auto_array smart pointer class' copy "
"constructor through the auxiliary auto_array_ref object");
}
ATF_TEST_CASE_BODY(auto_array_copy_ref)
{
using atf::utils::auto_array;
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
{
auto_array< test_array > t1(new test_array[10]);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
{
auto_array< test_array > t2 = test_array::do_copy(t1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_get);
ATF_TEST_CASE_HEAD(auto_array_get)
{
set_md_var("descr", "Tests the auto_array smart pointer class' get "
"method");
}
ATF_TEST_CASE_BODY(auto_array_get)
{
using atf::utils::auto_array;
test_array* ta = new test_array[10];
auto_array< test_array > t(ta);
ATF_REQUIRE_EQ(t.get(), ta);
}
ATF_TEST_CASE(auto_array_release);
ATF_TEST_CASE_HEAD(auto_array_release)
{
set_md_var("descr", "Tests the auto_array smart pointer class' release "
"method");
}
ATF_TEST_CASE_BODY(auto_array_release)
{
using atf::utils::auto_array;
test_array* ta1 = new test_array[10];
{
auto_array< test_array > t(ta1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
test_array* ta2 = t.release();
ATF_REQUIRE_EQ(ta2, ta1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
delete [] ta1;
}
ATF_TEST_CASE(auto_array_reset);
ATF_TEST_CASE_HEAD(auto_array_reset)
{
set_md_var("descr", "Tests the auto_array smart pointer class' reset "
"method");
}
ATF_TEST_CASE_BODY(auto_array_reset)
{
using atf::utils::auto_array;
test_array* ta1 = new test_array[10];
test_array* ta2 = new test_array[10];
ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
{
auto_array< test_array > t(ta1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 2);
t.reset(ta2);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
t.reset();
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_assign);
ATF_TEST_CASE_HEAD(auto_array_assign)
{
set_md_var("descr", "Tests the auto_array smart pointer class' "
"assignment operator");
}
ATF_TEST_CASE_BODY(auto_array_assign)
{
using atf::utils::auto_array;
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
{
auto_array< test_array > t1(new test_array[10]);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
{
auto_array< test_array > t2;
t2 = t1;
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_assign_ref);
ATF_TEST_CASE_HEAD(auto_array_assign_ref)
{
set_md_var("descr", "Tests the auto_array smart pointer class' "
"assignment operator through the auxiliary auto_array_ref "
"object");
}
ATF_TEST_CASE_BODY(auto_array_assign_ref)
{
using atf::utils::auto_array;
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
{
auto_array< test_array > t1(new test_array[10]);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
{
auto_array< test_array > t2;
t2 = test_array::do_copy(t1);
ATF_REQUIRE_EQ(test_array::m_nblocks, 1);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_REQUIRE_EQ(test_array::m_nblocks, 0);
}
ATF_TEST_CASE(auto_array_access);
ATF_TEST_CASE_HEAD(auto_array_access)
{
set_md_var("descr", "Tests the auto_array smart pointer class' access "
"operator");
}
ATF_TEST_CASE_BODY(auto_array_access)
{
using atf::utils::auto_array;
auto_array< test_array > t(new test_array[10]);
for (int i = 0; i < 10; i++)
t[i].m_value = i * 2;
for (int i = 0; i < 10; i++)
ATF_REQUIRE_EQ(t[i].m_value, i * 2);
}
// ------------------------------------------------------------------------
// Tests cases for the header file.
// ------------------------------------------------------------------------
HEADER_TC(include, "atf-c++/utils.hpp");
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test for the "auto_array" class.
ATF_ADD_TEST_CASE(tcs, auto_array_scope);
ATF_ADD_TEST_CASE(tcs, auto_array_copy);
ATF_ADD_TEST_CASE(tcs, auto_array_copy_ref);
ATF_ADD_TEST_CASE(tcs, auto_array_get);
ATF_ADD_TEST_CASE(tcs, auto_array_release);
ATF_ADD_TEST_CASE(tcs, auto_array_reset);
ATF_ADD_TEST_CASE(tcs, auto_array_assign);
ATF_ADD_TEST_CASE(tcs, auto_array_assign_ref);
ATF_ADD_TEST_CASE(tcs, auto_array_access);
// Add the test cases for the header file.
ATF_ADD_TEST_CASE(tcs, include);
}

36
atf-c.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Automated Testing Framework (atf)
*
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(ATF_C_H)
#define ATF_C_H
#include <atf-c/error.h>
#include <atf-c/macros.h>
#endif /* !defined(ATF_C_H) */

16
atf-c/Atffile Normal file
View File

@ -0,0 +1,16 @@
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

16
atf-c/Kyuafile Normal file
View File

@ -0,0 +1,16 @@
syntax("kyuafile", 1)
test_suite("atf")
atf_test_program{name="atf_c_test"}
atf_test_program{name="build_test"}
atf_test_program{name="check_test"}
atf_test_program{name="config_test"}
atf_test_program{name="error_test"}
atf_test_program{name="macros_test"}
atf_test_program{name="pkg_config_test"}
atf_test_program{name="tc_test"}
atf_test_program{name="tp_test"}
atf_test_program{name="utils_test"}
include("detail/Kyuafile")

157
atf-c/Makefile.am.inc Normal file
View File

@ -0,0 +1,157 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
lib_LTLIBRARIES += libatf-c.la
libatf_c_la_SOURCES = atf-c/build.c \
atf-c/build.h \
atf-c/check.c \
atf-c/check.h \
atf-c/config.c \
atf-c/config.h \
atf-c/error.c \
atf-c/error.h \
atf-c/error_fwd.h \
atf-c/macros.h \
atf-c/tc.c \
atf-c/tc.h \
atf-c/tp.c \
atf-c/tp.h \
atf-c/utils.c \
atf-c/utils.h
nodist_libatf_c_la_SOURCES = atf-c/defs.h
libatf_c_la_CPPFLAGS = "-DATF_ARCH=\"$(atf_arch)\"" \
"-DATF_BUILD_CC=\"$(ATF_BUILD_CC)\"" \
"-DATF_BUILD_CFLAGS=\"$(ATF_BUILD_CFLAGS)\"" \
"-DATF_BUILD_CPP=\"$(ATF_BUILD_CPP)\"" \
"-DATF_BUILD_CPPFLAGS=\"$(ATF_BUILD_CPPFLAGS)\"" \
"-DATF_BUILD_CXX=\"$(ATF_BUILD_CXX)\"" \
"-DATF_BUILD_CXXFLAGS=\"$(ATF_BUILD_CXXFLAGS)\"" \
"-DATF_CONFDIR=\"$(atf_confdir)\"" \
"-DATF_INCLUDEDIR=\"$(includedir)\"" \
"-DATF_LIBDIR=\"$(libdir)\"" \
"-DATF_LIBEXECDIR=\"$(libexecdir)\"" \
"-DATF_MACHINE=\"$(atf_machine)\"" \
"-DATF_M4=\"$(ATF_M4)\"" \
"-DATF_PKGDATADIR=\"$(pkgdatadir)\"" \
"-DATF_SHELL=\"$(ATF_SHELL)\"" \
"-DATF_WORKDIR=\"$(ATF_WORKDIR)\"" \
-I$(srcdir)/atf-c
libatf_c_la_LDFLAGS = -version-info 0:0:0
# XXX For some reason, the nodist line above does not work as expected.
# Work this problem around.
dist-hook: kill-defs-h
kill-defs-h:
rm -f $(distdir)/atf-c/defs.h
include_HEADERS += atf-c.h
atf_c_HEADERS = atf-c/build.h \
atf-c/check.h \
atf-c/config.h \
atf-c/defs.h \
atf-c/error.h \
atf-c/error_fwd.h \
atf-c/macros.h \
atf-c/tc.h \
atf-c/tp.h \
atf-c/utils.h
atf_cdir = $(includedir)/atf-c
dist_man_MANS += atf-c/atf-c-api.3
atf_aclocal_DATA += atf-c/atf-common.m4 atf-c/atf-c.m4
EXTRA_DIST += atf-c/atf-common.m4 atf-c/atf-c.m4
atf_cpkgconfigdir = $(atf_pkgconfigdir)
atf_cpkgconfig_DATA = atf-c/atf-c.pc
CLEANFILES += atf-c/atf-c.pc
EXTRA_DIST += atf-c/atf-c.pc.in
atf-c/atf-c.pc: $(srcdir)/atf-c/atf-c.pc.in Makefile
test -d atf-c || mkdir -p atf-c
sed -e 's#__ATF_VERSION__#$(PACKAGE_VERSION)#g' \
-e 's#__CC__#$(CC)#g' \
-e 's#__INCLUDEDIR__#$(includedir)#g' \
-e 's#__LIBDIR__#$(libdir)#g' \
<$(srcdir)/atf-c/atf-c.pc.in >atf-c/atf-c.pc.tmp
mv atf-c/atf-c.pc.tmp atf-c/atf-c.pc
tests_atf_c_DATA = atf-c/Atffile \
atf-c/Kyuafile \
atf-c/macros_h_test.c \
atf-c/unused_test.c
tests_atf_cdir = $(pkgtestsdir)/atf-c
EXTRA_DIST += $(tests_atf_c_DATA)
tests_atf_c_PROGRAMS = atf-c/atf_c_test
atf_c_atf_c_test_SOURCES = atf-c/atf_c_test.c
atf_c_atf_c_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/build_test
atf_c_build_test_SOURCES = atf-c/build_test.c atf-c/h_build.h
atf_c_build_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/check_test
atf_c_check_test_SOURCES = atf-c/check_test.c
atf_c_check_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/config_test
atf_c_config_test_SOURCES = atf-c/config_test.c
atf_c_config_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/error_test
atf_c_error_test_SOURCES = atf-c/error_test.c
atf_c_error_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/macros_test
atf_c_macros_test_SOURCES = atf-c/macros_test.c
atf_c_macros_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_SCRIPTS = atf-c/pkg_config_test
CLEANFILES += atf-c/pkg_config_test
EXTRA_DIST += atf-c/pkg_config_test.sh
atf-c/pkg_config_test: $(srcdir)/atf-c/pkg_config_test.sh
test -d atf-c || mkdir -p atf-c
@src="$(srcdir)/atf-c/pkg_config_test.sh"; \
dst="atf-c/pkg_config_test"; $(BUILD_SH_TP)
tests_atf_c_PROGRAMS += atf-c/tc_test
atf_c_tc_test_SOURCES = atf-c/tc_test.c
atf_c_tc_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/tp_test
atf_c_tp_test_SOURCES = atf-c/tp_test.c
atf_c_tp_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
tests_atf_c_PROGRAMS += atf-c/utils_test
atf_c_utils_test_SOURCES = atf-c/utils_test.c atf-c/h_build.h
atf_c_utils_test_LDADD = atf-c/detail/libtest_helpers.la libatf-c.la
include atf-c/detail/Makefile.am.inc
# vim: syntax=make:noexpandtab:shiftwidth=8:softtabstop=8

510
atf-c/atf-c-api.3 Normal file
View File

@ -0,0 +1,510 @@
.\"
.\" Automated Testing Framework (atf)
.\"
.\" Copyright (c) 2008 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
.\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
.\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd December 26, 2010
.Dt ATF-C-API 3
.Os
.Sh NAME
.Nm ATF_CHECK ,
.Nm ATF_CHECK_MSG ,
.Nm ATF_CHECK_EQ ,
.Nm ATF_CHECK_EQ_MSG ,
.Nm ATF_CHECK_STREQ ,
.Nm ATF_CHECK_STREQ_MSG ,
.Nm ATF_CHECK_ERRNO ,
.Nm ATF_REQUIRE ,
.Nm ATF_REQUIRE_MSG ,
.Nm ATF_REQUIRE_EQ ,
.Nm ATF_REQUIRE_EQ_MSG ,
.Nm ATF_REQUIRE_STREQ ,
.Nm ATF_REQUIRE_STREQ_MSG ,
.Nm ATF_REQUIRE_ERRNO ,
.Nm ATF_TC ,
.Nm ATF_TC_BODY ,
.Nm ATF_TC_BODY_NAME ,
.Nm ATF_TC_CLEANUP ,
.Nm ATF_TC_CLEANUP_NAME ,
.Nm ATF_TC_HEAD ,
.Nm ATF_TC_HEAD_NAME ,
.Nm ATF_TC_NAME ,
.Nm ATF_TC_WITH_CLEANUP ,
.Nm ATF_TC_WITHOUT_HEAD ,
.Nm ATF_TP_ADD_TC ,
.Nm ATF_TP_ADD_TCS ,
.Nm atf_tc_get_config_var ,
.Nm atf_tc_get_config_var_wd ,
.Nm atf_tc_get_config_var_as_bool ,
.Nm atf_tc_get_config_var_as_bool_wd ,
.Nm atf_tc_get_config_var_as_long ,
.Nm atf_tc_get_config_var_as_long_wd ,
.Nm atf_no_error ,
.Nm atf_tc_expect_death ,
.Nm atf_tc_expect_exit ,
.Nm atf_tc_expect_fail ,
.Nm atf_tc_expect_pass ,
.Nm atf_tc_expect_signal ,
.Nm atf_tc_expect_timeout ,
.Nm atf_tc_fail ,
.Nm atf_tc_fail_nonfatal ,
.Nm atf_tc_pass ,
.Nm atf_tc_skip
.Nd C API to write ATF-based test programs
.Sh SYNOPSIS
.In atf-c.h
.Fn ATF_CHECK "expression"
.Fn ATF_CHECK_MSG "expression" "fail_msg_fmt" ...
.Fn ATF_CHECK_EQ "expression_1" "expression_2"
.Fn ATF_CHECK_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ...
.Fn ATF_CHECK_STREQ "string_1" "string_2"
.Fn ATF_CHECK_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ...
.Fn ATF_CHECK_ERRNO "exp_errno" "bool_expression"
.Fn ATF_REQUIRE "expression"
.Fn ATF_REQUIRE_MSG "expression" "fail_msg_fmt" ...
.Fn ATF_REQUIRE_EQ "expression_1" "expression_2"
.Fn ATF_REQUIRE_EQ_MSG "expression_1" "expression_2" "fail_msg_fmt" ...
.Fn ATF_REQUIRE_STREQ "string_1" "string_2"
.Fn ATF_REQUIRE_STREQ_MSG "string_1" "string_2" "fail_msg_fmt" ...
.Fn ATF_REQUIRE_ERRNO "exp_errno" "bool_expression"
.Fn ATF_TC "name"
.Fn ATF_TC_BODY "name" "tc"
.Fn ATF_TC_BODY_NAME "name"
.Fn ATF_TC_CLEANUP "name" "tc"
.Fn ATF_TC_CLEANUP_NAME "name"
.Fn ATF_TC_HEAD "name" "tc"
.Fn ATF_TC_HEAD_NAME "name"
.Fn ATF_TC_NAME "name"
.Fn ATF_TC_WITH_CLEANUP "name"
.Fn ATF_TC_WITHOUT_HEAD "name"
.Fn ATF_TP_ADD_TC "tp_name" "tc_name"
.Fn ATF_TP_ADD_TCS "tp_name"
.Fn atf_tc_get_config_var "tc" "varname"
.Fn atf_tc_get_config_var_wd "tc" "variable_name" "default_value"
.Fn atf_tc_get_config_var_as_bool "tc" "variable_name"
.Fn atf_tc_get_config_var_as_bool_wd "tc" "variable_name" "default_value"
.Fn atf_tc_get_config_var_as_long "tc" "variable_name"
.Fn atf_tc_get_config_var_as_long_wd "tc" "variable_name" "default_value"
.Fn atf_no_error
.Fn atf_tc_expect_death "reason" "..."
.Fn atf_tc_expect_exit "exitcode" "reason" "..."
.Fn atf_tc_expect_fail "reason" "..."
.Fn atf_tc_expect_pass
.Fn atf_tc_expect_signal "signo" "reason" "..."
.Fn atf_tc_expect_timeout "reason" "..."
.Fn atf_tc_fail "reason"
.Fn atf_tc_fail_nonfatal "reason"
.Fn atf_tc_pass
.Fn atf_tc_skip "reason"
.Sh DESCRIPTION
The ATF
.Pp
C-based test programs always follow this template:
.Bd -literal -offset indent
.Ns ... C-specific includes go here ...
#include <atf-c.h>
ATF_TC(tc1);
ATF_TC_HEAD(tc1, tc)
{
... first test case's header ...
}
ATF_TC_BODY(tc1, tc)
{
... first test case's body ...
}
ATF_TC_WITH_CLEANUP(tc2);
ATF_TC_HEAD(tc2, tc)
{
... second test case's header ...
}
ATF_TC_BODY(tc2, tc)
{
... second test case's body ...
}
ATF_TC_CLEANUP(tc2, tc)
{
... second test case's cleanup ...
}
ATF_TC_WITHOUT_HEAD(tc3);
ATF_TC_BODY(tc3, tc)
{
... third test case's body ...
}
.Ns ... additional test cases ...
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tcs, tc1);
ATF_TP_ADD_TC(tcs, tc2);
ATF_TP_ADD_TC(tcs, tc3);
... add additional test cases ...
return atf_no_error();
}
.Ed
.Ss Definition of test cases
Test cases have an identifier and are composed of three different parts:
the header, the body and an optional cleanup routine, all of which are
described in
.Xr atf-test-case 4 .
To define test cases, one can use the
.Fn ATF_TC ,
.Fn ATF_TC_WITH_CLEANUP
or the
.Fn ATF_TC_WITHOUT_HEAD
macros, which take a single parameter specifiying the test case's name.
.Fn ATF_TC ,
requires to define a head and a body for the test case,
.Fn ATF_TC_WITH_CLEANUP
requires to define a head, a body and a cleanup for the test case and
.Fn ATF_TC_WITHOUT_HEAD
requires only a body for the test case.
It is important to note that these
.Em do not
set the test case up for execution when the program is run.
In order to do so, a later registration is needed with the
.Fn ATF_TP_ADD_TC
macro detailed in
.Sx Program initialization .
.Pp
Later on, one must define the three parts of the body by means of three
functions.
Their headers are given by the
.Fn ATF_TC_HEAD ,
.Fn ATF_TC_BODY
and
.Fn ATF_TC_CLEANUP
macros, all of which take the test case name provided to the
.Fn ATF_TC
.Fn ATF_TC_WITH_CLEANUP ,
or
.Fn ATF_TC_WITHOUT_HEAD
macros and the name of the variable that will hold a pointer to the
test case data.
Following each of these, a block of code is expected, surrounded by the
opening and closing brackets.
.Ss Program initialization
The library provides a way to easily define the test program's
.Fn main
function.
You should never define one on your own, but rely on the
library to do it for you.
This is done by using the
.Fn ATF_TP_ADD_TCS
macro, which is passed the name of the object that will hold the test
cases; i.e. the test program instance.
This name can be whatever you want as long as it is a valid variable
identifier.
.Pp
After the macro, you are supposed to provide the body of a function, which
should only use the
.Fn ATF_TP_ADD_TC
macro to register the test cases the test program will execute and return
a success error code.
The first parameter of this macro matches the name you provided in the
former call.
The success status can be returned using the
.Fn atf_no_error
function.
.Ss Header definitions
The test case's header can define the meta-data by using the
.Fn atf_tc_set_md_var
method, which takes three parameters: the first one points to the test
case data, the second one specifies the meta-data variable to be set
and the third one specifies its value.
Both of them are strings.
.Ss Configuration variables
The test case has read-only access to the current configuration variables
by means of the
.Ft bool
.Fn atf_tc_has_config_var ,
.Ft const char *
.Fn atf_tc_get_config_var ,
.Ft const char *
.Fn atf_tc_get_config_var_wd ,
.Ft bool
.Fn atf_tc_get_config_var_as_bool ,
.Ft bool
.Fn atf_tc_get_config_var_as_bool_wd ,
.Ft long
.Fn atf_tc_get_config_var_as_long ,
and the
.Ft long
.Fn atf_tc_get_config_var_as_long_wd
functions, which can be called in any of the three parts of a test case.
.Pp
The
.Sq _wd
variants take a default value for the variable which is returned if the
variable is not defined.
The other functions without the
.Sq _wd
suffix
.Em require
the variable to be defined.
.Ss Access to the source directory
It is possible to get the path to the test case's source directory from any
of its three components by querying the
.Sq srcdir
configuration variable.
.Ss Requiring programs
Aside from the
.Va require.progs
meta-data variable available in the header only, one can also check for
additional programs in the test case's body by using the
.Fn atf_tc_require_prog
function, which takes the base name or full path of a single binary.
Relative paths are forbidden.
If it is not found, the test case will be automatically skipped.
.Ss Test case finalization
The test case finalizes either when the body reaches its end, at which
point the test is assumed to have
.Em passed ,
unless any non-fatal errors were raised using
.Fn atf_tc_fail_nonfatal ,
or at any explicit call to
.Fn atf_tc_pass ,
.Fn atf_tc_fail
or
.Fn atf_tc_skip .
These three functions terminate the execution of the test case immediately.
The cleanup routine will be processed afterwards in a completely automated
way, regardless of the test case's termination reason.
.Pp
.Fn atf_tc_pass
does not take any parameters.
.Fn atf_tc_fail ,
.Fn atf_tc_fail_nonfatal
and
.Fn atf_tc_skip
take a format string and a variable list of parameters, which describe, in
a user-friendly manner, why the test case failed or was skipped,
respectively.
It is very important to provide a clear error message in both cases so that
the user can quickly know why the test did not pass.
.Ss Expectations
Everything explained in the previous section changes when the test case
expectations are redefined by the programmer.
.Pp
Each test case has an internal state called
.Sq expect
that describes what the test case expectations are at any point in time.
The value of this property can change during execution by any of:
.Bl -tag -width indent
.It Fn atf_tc_expect_death "reason" "..."
Expects the test case to exit prematurely regardless of the nature of the
exit.
.It Fn atf_tc_expect_exit "exitcode" "reason" "..."
Expects the test case to exit cleanly.
If
.Va exitcode
is not
.Sq -1 ,
.Xr atf-run 1
will validate that the exit code of the test case matches the one provided
in this call.
Otherwise, the exact value will be ignored.
.It Fn atf_tc_expect_fail "reason" "..."
Any failure (be it fatal or non-fatal) raised in this mode is recorded.
However, such failures do not report the test case as failed; instead, the
test case finalizes cleanly and is reported as
.Sq expected failure ;
this report includes the provided
.Fa reason
as part of it.
If no error is raised while running in this mode, then the test case is
reported as
.Sq failed .
.Pp
This mode is useful to reproduce actual known bugs in tests.
Whenever the developer fixes the bug later on, the test case will start
reporting a failure, signaling the developer that the test case must be
adjusted to the new conditions.
In this situation, it is useful, for example, to set
.Fa reason
as the bug number for tracking purposes.
.It Fn atf_tc_expect_pass
This is the normal mode of execution.
In this mode, any failure is reported as such to the user and the test case
is marked as
.Sq failed .
.It Fn atf_tc_expect_signal "signo" "reason" "..."
Expects the test case to terminate due to the reception of a signal.
If
.Va signo
is not
.Sq -1 ,
.Xr atf-run 1
will validate that the signal that terminated the test case matches the one
provided in this call.
Otherwise, the exact value will be ignored.
.It Fn atf_tc_expect_timeout "reason" "..."
Expects the test case to execute for longer than its timeout.
.El
.Ss Helper macros for common checks
The library provides several macros that are very handy in multiple
situations.
These basically check some condition after executing a given statement or
processing a given expression and, if the condition is not met, they
report the test case as failed.
.Pp
The
.Sq REQUIRE
variant of the macros immediately abort the test case as soon as an error
condition is detected by calling the
.Fn atf_tc_fail
function.
Use this variant whenever it makes now sense to continue the execution of a
test case when the checked condition is not met.
The
.Sq CHECK
variant, on the other hand, reports a failure as soon as it is encountered
using the
.Fn atf_tc_fail_nonfatal
function, but the execution of the test case continues as if nothing had
happened.
Use this variant whenever the checked condition is important as a result of
the test case, but there are other conditions that can be subsequently
checked on the same run without aborting.
.Pp
Additionally, the
.Sq MSG
variants take an extra set of parameters to explicitly specify the failure
message.
This failure message is formatted according to the
.Xr printf 3
formatters.
.Pp
.Fn ATF_CHECK ,
.Fn ATF_CHECK_MSG ,
.Fn ATF_REQUIRE
and
.Fn ATF_REQUIRE_MSG
take an expression and fail if the expression evaluates to false.
.Pp
.Fn ATF_CHECK_EQ ,
.Fn ATF_CHECK_EQ_MSG ,
.Fn ATF_REQUIRE_EQ
and
.Fn ATF_REQUIRE_EQ_MSG
take two expressions and fail if the two evaluated values are not equal.
.Pp
.Fn ATF_CHECK_STREQ ,
.Fn ATF_CHECK_STREQ_MSG ,
.Fn ATF_REQUIRE_STREQ
and
.Fn ATF_REQUIRE_STREQ_MSG
take two strings and fail if the two are not equal character by character.
.Pp
.Fn ATF_CHECK_ERRNO
and
.Fn ATF_REQUIRE_ERRNO
take, first, the error code that the check is expecting to find in the
.Va errno
variable and, second, a boolean expression that, if evaluates to true,
means that a call failed and
.Va errno
has to be checked against the first value.
.Sh EXAMPLES
The following shows a complete test program with a single test case that
validates the addition operator:
.Bd -literal -offset indent
#include <atf-c.h>
ATF_TC(addition);
ATF_TC_HEAD(addition, tc)
{
atf_tc_set_md_var(tc, "descr",
"Sample tests for the addition operator");
}
ATF_TC_BODY(addition, tc)
{
ATF_CHECK_EQ(0 + 0, 0);
ATF_CHECK_EQ(0 + 1, 1);
ATF_CHECK_EQ(1 + 0, 1);
ATF_CHECK_EQ(1 + 1, 2);
ATF_CHECK_EQ(100 + 200, 300);
}
ATF_TC(string_formatting);
ATF_TC_HEAD(string_formatting, tc)
{
atf_tc_set_md_var(tc, "descr",
"Sample tests for the snprintf");
}
ATF_TC_BODY(string_formatting, tc)
{
char buf[1024];
snprintf(buf, sizeof(buf), "a %s", "string");
ATF_CHECK_STREQ_MSG("a string", buf, "%s is not working");
}
ATF_TC(open_failure);
ATF_TC_HEAD(open_failure, tc)
{
atf_tc_set_md_var(tc, "descr",
"Sample tests for the open function");
}
ATF_TC_BODY(open_failure, tc)
{
ATF_CHECK_ERRNO(ENOENT, open("non-existent", O_RDONLY) == -1);
}
ATF_TC(known_bug);
ATF_TC_HEAD(known_bug, tc)
{
atf_tc_set_md_var(tc, "descr",
"Reproduces a known bug");
}
ATF_TC_BODY(known_bug, tc)
{
atf_tc_expect_fail("See bug number foo/bar");
ATF_CHECK_EQ(3, 1 + 1);
atf_tc_expect_pass();
ATF_CHECK_EQ(3, 1 + 2);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, addition);
ATF_TP_ADD_TC(tp, string_formatting);
ATF_TP_ADD_TC(tp, open_failure);
ATF_TP_ADD_TC(tp, known_bug);
return atf_no_error();
}
.Ed
.Sh SEE ALSO
.Xr atf-test-program 1 ,
.Xr atf-test-case 4 ,
.Xr atf 7

48
atf-c/atf-c.m4 Normal file
View File

@ -0,0 +1,48 @@
dnl
dnl Automated Testing Framework (atf)
dnl
dnl Copyright 2011 Google Inc.
dnl All rights reserved.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions are
dnl met:
dnl
dnl * Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl * Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in the
dnl documentation and/or other materials provided with the distribution.
dnl * Neither the name of Google Inc. nor the names of its contributors
dnl may be used to endorse or promote products derived from this software
dnl without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl ATF_CHECK_C([version-spec])
dnl
dnl Checks if atf-c is present. If version-spec is provided, ensures that
dnl the installed version of atf-sh matches the required version. This
dnl argument must be something like '>= 0.14' and accepts any version
dnl specification supported by pkg-config.
dnl
dnl Defines and substitutes ATF_C_CFLAGS and ATF_C_LIBS with the compiler
dnl and linker flags need to build against atf-c.
AC_DEFUN([ATF_CHECK_C], [
spec="atf-c[]m4_default_nblank([ $1], [])"
_ATF_CHECK_ARG_WITH(
[PKG_CHECK_MODULES([ATF_CXX], [${spec}],
[found=yes found_atf_c=yes], [found=no])],
[required ${spec} not found])
])

11
atf-c/atf-c.pc.in Normal file
View File

@ -0,0 +1,11 @@
# ATF pkg-config file
cc=__CC__
includedir=__INCLUDEDIR__
libdir=__LIBDIR__
Name: atf-c
Description: Automated Testing Framework (C binding)
Version: __ATF_VERSION__
Cflags: -I${includedir}
Libs: -L${libdir} -latf-c

92
atf-c/atf-common.m4 Normal file
View File

@ -0,0 +1,92 @@
dnl
dnl Automated Testing Framework (atf)
dnl
dnl Copyright 2011 Google Inc.
dnl All rights reserved.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions are
dnl met:
dnl
dnl * Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl * Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in the
dnl documentation and/or other materials provided with the distribution.
dnl * Neither the name of Google Inc. nor the names of its contributors
dnl may be used to endorse or promote products derived from this software
dnl without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dnl
dnl ATF_ARG_WITH
dnl
dnl Adds a --with-atf flag to the configure script that allows the user to
dnl enable or disable atf support.
dnl
dnl The ATF_CHECK_{C,CXX,SH} macros honor the flag defined herein if
dnl instantiated. If not instantiated, they will request the presence of
dnl the libraries unconditionally.
dnl
dnl Defines the WITH_ATF Automake conditional if ATF has been found by any
dnl of the ATF_CHECK_{C,CXX,SH} macros.
AC_DEFUN([ATF_ARG_WITH], [
m4_define([atf_arg_with_called], [yes])
m4_divert_text([DEFAULTS], [with_atf=auto])
AC_ARG_WITH([atf],
[AS_HELP_STRING([--with-atf=<yes|no|auto>],
[build atf-based test programs])],
[with_atf=${withval}], [with_atf=auto])
m4_divert_text([DEFAULTS], [
found_atf_c=no
found_atf_cxx=no
found_atf_sh=no
])
AM_CONDITIONAL([WITH_ATF], [test x"${found_atf_c}" = x"yes" -o \
x"${found_atf_cxx}" = x"yes" -o \
x"${found_atf_sh}" = x"yes"])
])
dnl _ATF_CHECK_ARG_WITH(check, error_message)
dnl
dnl Internal macro to execute a check conditional on the --with-atf flag
dnl and handle the result accordingly.
dnl
dnl 'check' specifies the piece of code to be run to detect the feature.
dnl This code must set the 'found' shell variable to yes or no depending
dnl on the raw result of the check.
AC_DEFUN([_ATF_CHECK_ARG_WITH], [
m4_ifdef([atf_arg_with_called], [
m4_fatal([ATF_ARG_WITH must be called after the ATF_CHECK_* checks])
])
m4_divert_text([DEFAULTS], [with_atf=yes])
if test x"${with_atf}" = x"no"; then
_found=no
else
$1
if test x"${with_atf}" = x"auto"; then
_found="${found}"
else
if test x"${found}" = x"yes"; then
_found=yes
else
AC_MSG_ERROR([$2])
fi
fi
fi
])

50
atf-c/atf_c_test.c Normal file
View File

@ -0,0 +1,50 @@
/*
* 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 <atf-c.h>
#include "detail/test_helpers.h"
/* ---------------------------------------------------------------------
* Tests cases for the header file.
* --------------------------------------------------------------------- */
HEADER_TC(include, "atf-c.h");
/* ---------------------------------------------------------------------
* Main.
* --------------------------------------------------------------------- */
ATF_TP_ADD_TCS(tp)
{
/* Add the test cases for the header file. */
ATF_TP_ADD_TC(tp, include);
return atf_no_error();
}

281
atf-c/build.c Normal file
View File

@ -0,0 +1,281 @@
/*
* Automated Testing Framework (atf)
*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include "atf-c/build.h"
#include "atf-c/config.h"
#include "atf-c/error.h"
#include "detail/sanity.h"
#include "detail/text.h"
/* ---------------------------------------------------------------------
* Auxiliary functions.
* --------------------------------------------------------------------- */
static
atf_error_t
append_config_var(const char *var, atf_list_t *argv)
{
atf_error_t err;
atf_list_t words;
err = atf_text_split(atf_config_get(var), " ", &words);
if (atf_is_error(err))
goto out;
atf_list_append_list(argv, &words);
out:
return err;
}
static
atf_error_t
append_arg1(const char *arg, atf_list_t *argv)
{
return atf_list_append(argv, strdup(arg), true);
}
static
atf_error_t
append_arg2(const char *flag, const char *arg, atf_list_t *argv)
{
atf_error_t err;
err = append_arg1(flag, argv);
if (!atf_is_error(err))
err = append_arg1(arg, argv);
return err;
}
static
atf_error_t
append_optargs(const char *const optargs[], atf_list_t *argv)
{
atf_error_t err;
err = atf_no_error();
while (*optargs != NULL && !atf_is_error(err)) {
err = append_arg1(strdup(*optargs), argv);
optargs++;
}
return err;
}
static
atf_error_t
append_src_out(const char *src, const char *obj, atf_list_t *argv)
{
atf_error_t err;
err = append_arg2("-o", obj, argv);
if (atf_is_error(err))
goto out;
err = append_arg1("-c", argv);
if (atf_is_error(err))
goto out;
err = append_arg1(src, argv);
out:
return err;
}
static
atf_error_t
list_to_array(const atf_list_t *l, char ***ap)
{
atf_error_t err;
char **a;
a = (char **)malloc((atf_list_size(l) + 1) * sizeof(char *));
if (a == NULL)
err = atf_no_memory_error();
else {
char **aiter;
atf_list_citer_t liter;
aiter = a;
atf_list_for_each_c(liter, l) {
*aiter = strdup((const char *)atf_list_citer_data(liter));
aiter++;
}
*aiter = NULL;
err = atf_no_error();
}
*ap = a; /* Shut up warnings in the caller about uninitialized *ap. */
return err;
}
/* ---------------------------------------------------------------------
* Free functions.
* --------------------------------------------------------------------- */
atf_error_t
atf_build_c_o(const char *sfile,
const char *ofile,
const char *const optargs[],
char ***argv)
{
atf_error_t err;
atf_list_t argv_list;
err = atf_list_init(&argv_list);
if (atf_is_error(err))
goto out;
err = append_config_var("atf_build_cc", &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_config_var("atf_build_cppflags", &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_config_var("atf_build_cflags", &argv_list);
if (atf_is_error(err))
goto out_list;
if (optargs != NULL) {
err = append_optargs(optargs, &argv_list);
if (atf_is_error(err))
goto out_list;
}
err = append_src_out(sfile, ofile, &argv_list);
if (atf_is_error(err))
goto out_list;
err = list_to_array(&argv_list, argv);
if (atf_is_error(err))
goto out_list;
out_list:
atf_list_fini(&argv_list);
out:
return err;
}
atf_error_t
atf_build_cpp(const char *sfile,
const char *ofile,
const char *const optargs[],
char ***argv)
{
atf_error_t err;
atf_list_t argv_list;
err = atf_list_init(&argv_list);
if (atf_is_error(err))
goto out;
err = append_config_var("atf_build_cpp", &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_config_var("atf_build_cppflags", &argv_list);
if (atf_is_error(err))
goto out_list;
if (optargs != NULL) {
err = append_optargs(optargs, &argv_list);
if (atf_is_error(err))
goto out_list;
}
err = append_arg2("-o", ofile, &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_arg1(sfile, &argv_list);
if (atf_is_error(err))
goto out_list;
err = list_to_array(&argv_list, argv);
if (atf_is_error(err))
goto out_list;
out_list:
atf_list_fini(&argv_list);
out:
return err;
}
atf_error_t
atf_build_cxx_o(const char *sfile,
const char *ofile,
const char *const optargs[],
char ***argv)
{
atf_error_t err;
atf_list_t argv_list;
err = atf_list_init(&argv_list);
if (atf_is_error(err))
goto out;
err = append_config_var("atf_build_cxx", &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_config_var("atf_build_cppflags", &argv_list);
if (atf_is_error(err))
goto out_list;
err = append_config_var("atf_build_cxxflags", &argv_list);
if (atf_is_error(err))
goto out_list;
if (optargs != NULL) {
err = append_optargs(optargs, &argv_list);
if (atf_is_error(err))
goto out_list;
}
err = append_src_out(sfile, ofile, &argv_list);
if (atf_is_error(err))
goto out_list;
err = list_to_array(&argv_list, argv);
if (atf_is_error(err))
goto out_list;
out_list:
atf_list_fini(&argv_list);
out:
return err;
}

42
atf-c/build.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Automated Testing Framework (atf)
*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(ATF_C_BUILD_H)
#define ATF_C_BUILD_H
#include <atf-c/error_fwd.h>
atf_error_t atf_build_c_o(const char *, const char *, const char *const [],
char ***);
atf_error_t atf_build_cpp(const char *, const char *, const char *const [],
char ***);
atf_error_t atf_build_cxx_o(const char *, const char *, const char *const [],
char ***);
#endif /* ATF_C_BUILD_H */

268
atf-c/build_test.c Normal file
View File

@ -0,0 +1,268 @@
/*
* Automated Testing Framework (atf)
*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
#include "atf-c/build.h"
#include "atf-c/config.h"
#include "atf-c/utils.h"
#include "detail/env.h"
#include "detail/test_helpers.h"
#include "h_build.h"
/* ---------------------------------------------------------------------
* Auxiliary functions.
* --------------------------------------------------------------------- */
void __atf_config_reinit(void);
static
bool
equal_arrays(const char *const *exp_array, char **actual_array)
{
bool equal;
if (*exp_array == NULL && *actual_array == NULL)
equal = true;
else if (*exp_array == NULL || *actual_array == NULL)
equal = false;
else {
equal = true;
while (*actual_array != NULL) {
if (*exp_array == NULL || strcmp(*exp_array, *actual_array) != 0) {
equal = false;
break;
}
exp_array++;
actual_array++;
}
}
return equal;
}
static
void
check_equal_array(const char *const *exp_array, char **actual_array)
{
{
const char *const *exp_ptr;
printf("Expected arguments:");
for (exp_ptr = exp_array; *exp_ptr != NULL; exp_ptr++)
printf(" '%s'", *exp_ptr);
printf("\n");
}
{
char **actual_ptr;
printf("Returned arguments:");
for (actual_ptr = actual_array; *actual_ptr != NULL; actual_ptr++)
printf(" '%s'", *actual_ptr);
printf("\n");
}
if (!equal_arrays(exp_array, actual_array))
atf_tc_fail_nonfatal("The constructed argv differs from the "
"expected values");
}
static
void
verbose_set_env(const char *var, const char *val)
{
printf("Setting %s to '%s'\n", var, val);
RE(atf_env_set(var, val));
}
/* ---------------------------------------------------------------------
* Internal test cases.
* --------------------------------------------------------------------- */
ATF_TC(equal_arrays);
ATF_TC_HEAD(equal_arrays, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests the test case internal "
"equal_arrays function");
}
ATF_TC_BODY(equal_arrays, tc)
{
{
const char *const exp[] = { NULL };
char *actual[] = { NULL };
ATF_CHECK(equal_arrays(exp, actual));
}
{
const char *const exp[] = { NULL };
char *actual[2] = { strdup("foo"), NULL };
ATF_CHECK(!equal_arrays(exp, actual));
free(actual[0]);
}
{
const char *const exp[] = { "foo", NULL };
char *actual[] = { NULL };
ATF_CHECK(!equal_arrays(exp, actual));
}
{
const char *const exp[] = { "foo", NULL };
char *actual[2] = { strdup("foo"), NULL };
ATF_CHECK(equal_arrays(exp, actual));
free(actual[0]);
}
}
/* ---------------------------------------------------------------------
* Test cases for the free functions.
* --------------------------------------------------------------------- */
ATF_TC(c_o);
ATF_TC_HEAD(c_o, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests the atf_build_c_o function");
}
ATF_TC_BODY(c_o, tc)
{
struct c_o_test *test;
for (test = c_o_tests; test->expargv[0] != NULL; test++) {
printf("> Test: %s\n", test->msg);
verbose_set_env("ATF_BUILD_CC", test->cc);
verbose_set_env("ATF_BUILD_CFLAGS", test->cflags);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
__atf_config_reinit();
{
char **argv;
if (test->hasoptargs)
RE(atf_build_c_o(test->sfile, test->ofile, test->optargs,
&argv));
else
RE(atf_build_c_o(test->sfile, test->ofile, NULL, &argv));
check_equal_array(test->expargv, argv);
atf_utils_free_charpp(argv);
}
}
}
ATF_TC(cpp);
ATF_TC_HEAD(cpp, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests the atf_build_cpp function");
}
ATF_TC_BODY(cpp, tc)
{
struct cpp_test *test;
for (test = cpp_tests; test->expargv[0] != NULL; test++) {
printf("> Test: %s\n", test->msg);
verbose_set_env("ATF_BUILD_CPP", test->cpp);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
__atf_config_reinit();
{
char **argv;
if (test->hasoptargs)
RE(atf_build_cpp(test->sfile, test->ofile, test->optargs,
&argv));
else
RE(atf_build_cpp(test->sfile, test->ofile, NULL, &argv));
check_equal_array(test->expargv, argv);
atf_utils_free_charpp(argv);
}
}
}
ATF_TC(cxx_o);
ATF_TC_HEAD(cxx_o, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests the atf_build_cxx_o function");
}
ATF_TC_BODY(cxx_o, tc)
{
struct cxx_o_test *test;
for (test = cxx_o_tests; test->expargv[0] != NULL; test++) {
printf("> Test: %s\n", test->msg);
verbose_set_env("ATF_BUILD_CXX", test->cxx);
verbose_set_env("ATF_BUILD_CXXFLAGS", test->cxxflags);
verbose_set_env("ATF_BUILD_CPPFLAGS", test->cppflags);
__atf_config_reinit();
{
char **argv;
if (test->hasoptargs)
RE(atf_build_cxx_o(test->sfile, test->ofile, test->optargs,
&argv));
else
RE(atf_build_cxx_o(test->sfile, test->ofile, NULL, &argv));
check_equal_array(test->expargv, argv);
atf_utils_free_charpp(argv);
}
}
}
/* ---------------------------------------------------------------------
* Tests cases for the header file.
* --------------------------------------------------------------------- */
HEADER_TC(include, "atf-c/build.h");
/* ---------------------------------------------------------------------
* Main.
* --------------------------------------------------------------------- */
ATF_TP_ADD_TCS(tp)
{
/* Add the internal test cases. */
ATF_TP_ADD_TC(tp, equal_arrays);
/* Add the test cases for the free functions. */
ATF_TP_ADD_TC(tp, c_o);
ATF_TP_ADD_TC(tp, cpp);
ATF_TP_ADD_TC(tp, cxx_o);
/* Add the test cases for the header file. */
ATF_TP_ADD_TC(tp, include);
return atf_no_error();
}

488
atf-c/check.c Normal file
View File

@ -0,0 +1,488 @@
/*
* 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/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "atf-c/build.h"
#include "atf-c/check.h"
#include "atf-c/config.h"
#include "atf-c/defs.h"
#include "atf-c/error.h"
#include "atf-c/utils.h"
#include "detail/dynstr.h"
#include "detail/fs.h"
#include "detail/list.h"
#include "detail/process.h"
#include "detail/sanity.h"
/* ---------------------------------------------------------------------
* Auxiliary functions.
* --------------------------------------------------------------------- */
static
atf_error_t
create_tmpdir(atf_fs_path_t *dir)
{
atf_error_t err;
err = atf_fs_path_init_fmt(dir, "%s/check.XXXXXX",
atf_config_get("atf_workdir"));
if (atf_is_error(err))
goto out;
err = atf_fs_mkdtemp(dir);
if (atf_is_error(err)) {
atf_fs_path_fini(dir);
goto out;
}
INV(!atf_is_error(err));
out:
return err;
}
static
void
cleanup_tmpdir(const atf_fs_path_t *dir, const atf_fs_path_t *outfile,
const atf_fs_path_t *errfile)
{
{
atf_error_t err = atf_fs_unlink(outfile);
if (atf_is_error(err)) {
INV(atf_error_is(err, "libc") &&
atf_libc_error_code(err) == ENOENT);
atf_error_free(err);
} else
INV(!atf_is_error(err));
}
{
atf_error_t err = atf_fs_unlink(errfile);
if (atf_is_error(err)) {
INV(atf_error_is(err, "libc") &&
atf_libc_error_code(err) == ENOENT);
atf_error_free(err);
} else
INV(!atf_is_error(err));
}
{
atf_error_t err = atf_fs_rmdir(dir);
INV(!atf_is_error(err));
}
}
static
int
const_execvp(const char *file, const char *const *argv)
{
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
return execvp(file, UNCONST(argv));
#undef UNCONST
}
static
atf_error_t
init_sb(const atf_fs_path_t *path, atf_process_stream_t *sb)
{
atf_error_t err;
if (path == NULL)
err = atf_process_stream_init_inherit(sb);
else
err = atf_process_stream_init_redirect_path(sb, path);
return err;
}
static
atf_error_t
init_sbs(const atf_fs_path_t *outfile, atf_process_stream_t *outsb,
const atf_fs_path_t *errfile, atf_process_stream_t *errsb)
{
atf_error_t err;
err = init_sb(outfile, outsb);
if (atf_is_error(err))
goto out;
err = init_sb(errfile, errsb);
if (atf_is_error(err)) {
atf_process_stream_fini(outsb);
goto out;
}
out:
return err;
}
struct exec_data {
const char *const *m_argv;
};
static void exec_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
static
void
exec_child(void *v)
{
struct exec_data *ea = v;
const_execvp(ea->m_argv[0], ea->m_argv);
fprintf(stderr, "execvp(%s) failed: %s\n", ea->m_argv[0], strerror(errno));
exit(127);
}
static
atf_error_t
fork_and_wait(const char *const *argv, const atf_fs_path_t *outfile,
const atf_fs_path_t *errfile, atf_process_status_t *status)
{
atf_error_t err;
atf_process_child_t child;
atf_process_stream_t outsb, errsb;
struct exec_data ea = { argv };
err = init_sbs(outfile, &outsb, errfile, &errsb);
if (atf_is_error(err))
goto out;
err = atf_process_fork(&child, exec_child, &outsb, &errsb, &ea);
if (atf_is_error(err))
goto out_sbs;
err = atf_process_child_wait(&child, status);
out_sbs:
atf_process_stream_fini(&errsb);
atf_process_stream_fini(&outsb);
out:
return err;
}
static
void
update_success_from_status(const char *progname,
const atf_process_status_t *status, bool *success)
{
bool s = atf_process_status_exited(status) &&
atf_process_status_exitstatus(status) == EXIT_SUCCESS;
if (atf_process_status_exited(status)) {
if (atf_process_status_exitstatus(status) == EXIT_SUCCESS)
INV(s);
else {
INV(!s);
fprintf(stderr, "%s failed with exit code %d\n", progname,
atf_process_status_exitstatus(status));
}
} else if (atf_process_status_signaled(status)) {
INV(!s);
fprintf(stderr, "%s failed due to signal %d%s\n", progname,
atf_process_status_termsig(status),
atf_process_status_coredump(status) ? " (core dumped)" : "");
} else {
INV(!s);
fprintf(stderr, "%s failed due to unknown reason\n", progname);
}
*success = s;
}
static
atf_error_t
array_to_list(const char *const *a, atf_list_t *l)
{
atf_error_t err;
err = atf_list_init(l);
if (atf_is_error(err))
goto out;
while (*a != NULL) {
char *item = strdup(*a);
if (item == NULL) {
err = atf_no_memory_error();
goto out;
}
err = atf_list_append(l, item, true);
if (atf_is_error(err))
goto out;
a++;
}
out:
return err;
}
static void
print_array(const char *const *array, const char *pfx)
{
const char *const *ptr;
printf("%s", pfx);
for (ptr = array; *ptr != NULL; ptr++)
printf(" %s", *ptr);
printf("\n");
}
static
atf_error_t
check_build_run(const char *const *argv, bool *success)
{
atf_error_t err;
atf_process_status_t status;
print_array(argv, ">");
err = fork_and_wait(argv, NULL, NULL, &status);
if (atf_is_error(err))
goto out;
update_success_from_status(argv[0], &status, success);
atf_process_status_fini(&status);
INV(!atf_is_error(err));
out:
return err;
}
/* ---------------------------------------------------------------------
* The "atf_check_result" type.
* --------------------------------------------------------------------- */
struct atf_check_result_impl {
atf_list_t m_argv;
atf_fs_path_t m_dir;
atf_fs_path_t m_stdout;
atf_fs_path_t m_stderr;
atf_process_status_t m_status;
};
static
atf_error_t
atf_check_result_init(atf_check_result_t *r, const char *const *argv,
const atf_fs_path_t *dir)
{
atf_error_t err;
r->pimpl = malloc(sizeof(struct atf_check_result_impl));
if (r->pimpl == NULL)
return atf_no_memory_error();
err = array_to_list(argv, &r->pimpl->m_argv);
if (atf_is_error(err))
goto out;
err = atf_fs_path_copy(&r->pimpl->m_dir, dir);
if (atf_is_error(err))
goto err_argv;
err = atf_fs_path_init_fmt(&r->pimpl->m_stdout, "%s/stdout",
atf_fs_path_cstring(dir));
if (atf_is_error(err))
goto err_dir;
err = atf_fs_path_init_fmt(&r->pimpl->m_stderr, "%s/stderr",
atf_fs_path_cstring(dir));
if (atf_is_error(err))
goto err_stdout;
INV(!atf_is_error(err));
goto out;
err_stdout:
atf_fs_path_fini(&r->pimpl->m_stdout);
err_dir:
atf_fs_path_fini(&r->pimpl->m_dir);
err_argv:
atf_list_fini(&r->pimpl->m_argv);
out:
return err;
}
void
atf_check_result_fini(atf_check_result_t *r)
{
atf_process_status_fini(&r->pimpl->m_status);
cleanup_tmpdir(&r->pimpl->m_dir, &r->pimpl->m_stdout,
&r->pimpl->m_stderr);
atf_fs_path_fini(&r->pimpl->m_stdout);
atf_fs_path_fini(&r->pimpl->m_stderr);
atf_fs_path_fini(&r->pimpl->m_dir);
atf_list_fini(&r->pimpl->m_argv);
free(r->pimpl);
}
const char *
atf_check_result_stdout(const atf_check_result_t *r)
{
return atf_fs_path_cstring(&r->pimpl->m_stdout);
}
const char *
atf_check_result_stderr(const atf_check_result_t *r)
{
return atf_fs_path_cstring(&r->pimpl->m_stderr);
}
bool
atf_check_result_exited(const atf_check_result_t *r)
{
return atf_process_status_exited(&r->pimpl->m_status);
}
int
atf_check_result_exitcode(const atf_check_result_t *r)
{
return atf_process_status_exitstatus(&r->pimpl->m_status);
}
bool
atf_check_result_signaled(const atf_check_result_t *r)
{
return atf_process_status_signaled(&r->pimpl->m_status);
}
int
atf_check_result_termsig(const atf_check_result_t *r)
{
return atf_process_status_termsig(&r->pimpl->m_status);
}
/* ---------------------------------------------------------------------
* Free functions.
* --------------------------------------------------------------------- */
/* XXX: This function shouldn't be in this module. It messes with stdout
* and stderr, and it provides a very high-end interface. This belongs,
* probably, somewhere related to test cases (such as in the tc module). */
atf_error_t
atf_check_build_c_o(const char *sfile,
const char *ofile,
const char *const optargs[],
bool *success)
{
atf_error_t err;
char **argv;
err = atf_build_c_o(sfile, ofile, optargs, &argv);
if (atf_is_error(err))
goto out;
err = check_build_run((const char *const *)argv, success);
atf_utils_free_charpp(argv);
out:
return err;
}
atf_error_t
atf_check_build_cpp(const char *sfile,
const char *ofile,
const char *const optargs[],
bool *success)
{
atf_error_t err;
char **argv;
err = atf_build_cpp(sfile, ofile, optargs, &argv);
if (atf_is_error(err))
goto out;
err = check_build_run((const char *const *)argv, success);
atf_utils_free_charpp(argv);
out:
return err;
}
atf_error_t
atf_check_build_cxx_o(const char *sfile,
const char *ofile,
const char *const optargs[],
bool *success)
{
atf_error_t err;
char **argv;
err = atf_build_cxx_o(sfile, ofile, optargs, &argv);
if (atf_is_error(err))
goto out;
err = check_build_run((const char *const *)argv, success);
atf_utils_free_charpp(argv);
out:
return err;
}
atf_error_t
atf_check_exec_array(const char *const *argv, atf_check_result_t *r)
{
atf_error_t err;
atf_fs_path_t dir;
err = create_tmpdir(&dir);
if (atf_is_error(err))
goto out;
err = atf_check_result_init(r, argv, &dir);
if (atf_is_error(err)) {
atf_error_t err2 = atf_fs_rmdir(&dir);
INV(!atf_is_error(err2));
goto out;
}
err = fork_and_wait(argv, &r->pimpl->m_stdout, &r->pimpl->m_stderr,
&r->pimpl->m_status);
if (atf_is_error(err)) {
atf_check_result_fini(r);
goto out;
}
INV(!atf_is_error(err));
atf_fs_path_fini(&dir);
out:
return err;
}

Some files were not shown because too many files have changed in this diff Show More