Import ATF version 0,16
Discussed with: gibbs, gnn, keramida, mdf, mlaier, Discussed with: Garrett Cooper
This commit is contained in:
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
30
AUTHORS
Normal file
30
AUTHORS
Normal 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
12
Atffile
Normal 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
100
COPYING
Normal 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
232
INSTALL
Normal 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
18
Kyuafile
Normal 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
151
Makefile.am
Normal 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
5264
Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
570
NEWS
Normal file
570
NEWS
Normal 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
40
README
Normal 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
184
TODO
Normal 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
1021
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
48
admin/Makefile.am.inc
Normal file
48
admin/Makefile.am.inc
Normal 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
92
admin/check-install.sh
Executable 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
94
admin/check-style-c.awk
Normal 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
|
82
admin/check-style-common.awk
Normal file
82
admin/check-style-common.awk
Normal 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
90
admin/check-style-cpp.awk
Normal 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
78
admin/check-style-man.awk
Normal 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
106
admin/check-style-shell.awk
Normal 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
189
admin/check-style.sh
Executable 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
310
admin/compile
Executable 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
1522
admin/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1766
admin/config.sub
vendored
Executable file
1766
admin/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
688
admin/depcomp
Executable file
688
admin/depcomp
Executable 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
527
admin/install-sh
Executable 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
9655
admin/ltmain.sh
Normal file
File diff suppressed because it is too large
Load Diff
331
admin/missing
Executable file
331
admin/missing
Executable 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
35
atf-c++.hpp
Normal 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
14
atf-c++/Atffile
Normal 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
14
atf-c++/Kyuafile
Normal 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
111
atf-c++/Makefile.am.inc
Normal 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
420
atf-c++/atf-c++-api.3
Normal 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
48
atf-c++/atf-c++.m4
Normal 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
11
atf-c++/atf-c++.pc.in
Normal 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
48
atf-c++/atf_c++_test.cpp
Normal 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
119
atf-c++/build.cpp
Normal 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
57
atf-c++/build.hpp
Normal 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
247
atf-c++/build_test.cpp
Normal 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
158
atf-c++/check.cpp
Normal 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
133
atf-c++/check.hpp
Normal 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
408
atf-c++/check_test.cpp
Normal 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
123
atf-c++/config.cpp
Normal 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
75
atf-c++/config.hpp
Normal 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
231
atf-c++/config_test.cpp
Normal 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
13
atf-c++/detail/Atffile
Normal 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
13
atf-c++/detail/Kyuafile
Normal 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"}
|
99
atf-c++/detail/Makefile.am.inc
Normal file
99
atf-c++/detail/Makefile.am.inc
Normal 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
|
345
atf-c++/detail/application.cpp
Normal file
345
atf-c++/detail/application.cpp
Normal 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;
|
||||
}
|
115
atf-c++/detail/application.hpp
Normal file
115
atf-c++/detail/application.hpp
Normal 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_)
|
94
atf-c++/detail/application_test.cpp
Normal file
94
atf-c++/detail/application_test.cpp
Normal 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
73
atf-c++/detail/env.cpp
Normal 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
84
atf-c++/detail/env.hpp
Normal 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_)
|
91
atf-c++/detail/env_test.cpp
Normal file
91
atf-c++/detail/env_test.cpp
Normal 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);
|
||||
}
|
157
atf-c++/detail/exceptions.cpp
Normal file
157
atf-c++/detail/exceptions.cpp
Normal 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;
|
||||
}
|
99
atf-c++/detail/exceptions.hpp
Normal file
99
atf-c++/detail/exceptions.hpp
Normal 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_)
|
148
atf-c++/detail/exceptions_test.cpp
Normal file
148
atf-c++/detail/exceptions_test.cpp
Normal 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
81
atf-c++/detail/expand.cpp
Normal 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
82
atf-c++/detail/expand.hpp
Normal 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_)
|
272
atf-c++/detail/expand_test.cpp
Normal file
272
atf-c++/detail/expand_test.cpp
Normal 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
517
atf-c++/detail/fs.cpp
Normal 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
391
atf-c++/detail/fs.hpp
Normal 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
545
atf-c++/detail/fs_test.cpp
Normal 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
384
atf-c++/detail/parser.cpp
Normal 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
607
atf-c++/detail/parser.hpp
Normal 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_)
|
1043
atf-c++/detail/parser_test.cpp
Normal file
1043
atf-c++/detail/parser_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
355
atf-c++/detail/process.cpp
Normal file
355
atf-c++/detail/process.cpp
Normal 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
280
atf-c++/detail/process.hpp
Normal 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_)
|
357
atf-c++/detail/process_test.cpp
Normal file
357
atf-c++/detail/process_test.cpp
Normal 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
37
atf-c++/detail/sanity.hpp
Normal 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_)
|
41
atf-c++/detail/sanity_test.cpp
Normal file
41
atf-c++/detail/sanity_test.cpp
Normal 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);
|
||||
}
|
160
atf-c++/detail/test_helpers.cpp
Normal file
160
atf-c++/detail/test_helpers.cpp
Normal 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");
|
||||
}
|
||||
}
|
166
atf-c++/detail/test_helpers.hpp
Normal file
166
atf-c++/detail/test_helpers.hpp
Normal 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
160
atf-c++/detail/text.cpp
Normal 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
153
atf-c++/detail/text.hpp
Normal 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_)
|
390
atf-c++/detail/text_test.cpp
Normal file
390
atf-c++/detail/text_test.cpp
Normal 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
173
atf-c++/detail/ui.cpp
Normal 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
105
atf-c++/detail/ui.hpp
Normal 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
462
atf-c++/detail/ui_test.cpp
Normal 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
222
atf-c++/macros.hpp
Normal 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
130
atf-c++/macros_hpp_test.cpp
Normal 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
793
atf-c++/macros_test.cpp
Normal 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
149
atf-c++/pkg_config_test.sh
Normal 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
710
atf-c++/tests.cpp
Normal 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
127
atf-c++/tests.hpp
Normal 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
201
atf-c++/tests_test.cpp
Normal 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
52
atf-c++/unused_test.cpp
Normal 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
200
atf-c++/utils.hpp
Normal 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
310
atf-c++/utils_test.cpp
Normal 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
36
atf-c.h
Normal 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
16
atf-c/Atffile
Normal 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
16
atf-c/Kyuafile
Normal 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
157
atf-c/Makefile.am.inc
Normal 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
510
atf-c/atf-c-api.3
Normal 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
48
atf-c/atf-c.m4
Normal 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
11
atf-c/atf-c.pc.in
Normal 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
92
atf-c/atf-common.m4
Normal 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
50
atf-c/atf_c_test.c
Normal 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
281
atf-c/build.c
Normal 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
42
atf-c/build.h
Normal 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
268
atf-c/build_test.c
Normal 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
488
atf-c/check.c
Normal 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
Loading…
Reference in New Issue
Block a user