3043. [test] Merged in the NetBSD ATF test framework (currently

version 0.12) for development of future unit tests.
                        Use configure --with-atf to build ATF internally
                        or configure --with-atf=prefix to use an external
                        copy.  [RT #23209]
This commit is contained in:
Evan Hunt 2011-02-26 02:26:33 +00:00
parent 9eecb34b66
commit ef421f66f4
326 changed files with 111016 additions and 8 deletions

5
Atffile Normal file
View file

@ -0,0 +1,5 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = bind9
tp: lib

View file

@ -1,3 +1,9 @@
3043. [test] Merged in the NetBSD ATF test framework (currently
version 0.12) for development of future unit tests.
Use configure --with-atf to build ATF internally
or configure --with-atf=prefix to use an external
copy. [RT #23209]
3042. [bug] dig +trace could fail attempting to use IPv6
addresses on systems with only IPv4 connectivity.
[RT #23797]

View file

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.58 2009/11/26 20:52:44 marka Exp $
# $Id: Makefile.in,v 1.59 2011/02/26 02:26:10 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@
@BIND9_VERSION@
SUBDIRS = make lib bin doc @LIBEXPORT@
SUBDIRS = make unit lib bin doc @LIBEXPORT@
TARGETS =
MANPAGES = isc-config.sh.1
@ -65,6 +65,7 @@ check: test
test:
(cd bin/tests && ${MAKE} ${MAKEDEFS} test)
(test -f unit/unittest.sh && $(SHELL) unit/unittest.sh)
FAQ: FAQ.xml
${XSLTPROC} doc/xsl/isc-docbook-text.xsl FAQ.xml | \

View file

@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl
AC_REVISION($Revision: 1.513 $)
AC_REVISION($Revision: 1.514 $)
AC_INIT(lib/dns/name.c)
AC_PREREQ(2.59)
@ -3033,6 +3033,34 @@ if test "$use_idn" != no; then
fi
AC_SUBST(IDNLIBS)
#
# Check whether to build Automated Test Framework unit tests
#
AC_ARG_WITH(atf,
[ --with-atf=ARG Automated Test Framework support],
atf="$withval", atf="no")
if test "$atf" = yes; then
atf=`pwd`/unit/atf
ATFBUILD=atf-src
AC_SUBST(ATFBUILD)
AC_CONFIG_COMMANDS([atf-config],
[cd unit/atf-src; ./configure --prefix $atfdir; cd ../..],
[atfdir=`pwd`/unit/atf])
AC_MSG_RESULT(building ATF from bind9/unit/atf-src)
fi
ATFLIBS=
if test "$atf" != no; then
AC_DEFINE(ATF_TEST, 1, [define if ATF unit tests are to be built.])
STD_CINCLUDES="$STD_CINCLUDES -I$atf/include"
ATFBIN="$atf/bin"
ATFLIBS="-L $atf/lib -latf-c"
UNITTESTS=tests
fi
AC_SUBST(ATFBIN)
AC_SUBST(ATFLIBS)
AC_SUBST(UNITTESTS)
AC_CHECK_HEADERS(locale.h)
AC_CHECK_FUNCS(setlocale)
@ -3335,6 +3363,7 @@ AC_CONFIG_FILES([
lib/dns/include/Makefile
lib/dns/include/dns/Makefile
lib/dns/include/dst/Makefile
lib/dns/tests/Makefile
lib/export/Makefile
lib/export/dns/Makefile
lib/export/dns/include/Makefile
@ -3395,6 +3424,8 @@ AC_CONFIG_FILES([
lib/tests/Makefile
lib/tests/include/Makefile
lib/tests/include/tests/Makefile
unit/Makefile
unit/unittest.sh
])
#

5
lib/Atffile Normal file
View file

@ -0,0 +1,5 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = bind9
tp: dns

5
lib/dns/Atffile Normal file
View file

@ -0,0 +1,5 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = bind9
tp: tests

View file

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.176 2011/01/13 01:59:27 marka Exp $
# $Id: Makefile.in,v 1.177 2011/02/26 02:26:10 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -99,9 +99,10 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \
version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS}
SRCS = ${DSTSRCS} ${DNSSRCS}
SUBDIRS = include
SUBDIRS = include
TARGETS = include/dns/enumtype.h include/dns/enumclass.h \
include/dns/rdatastruct.h timestamp
TESTDIRS = @UNITTESTS@
DEPENDEXTRA = ./gen -F include/dns/rdatastruct.h \
-s ${srcdir} -d >> Makefile ;

3
lib/dns/tests/.cvsignore Normal file
View file

@ -0,0 +1,3 @@
Makefile
master_test
ncache_test

5
lib/dns/tests/Atffile Normal file
View file

@ -0,0 +1,5 @@
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = bind9
tp-glob: *_test

53
lib/dns/tests/Makefile.in Normal file
View file

@ -0,0 +1,53 @@
# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.2 2011/02/26 02:26:10 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
# Attempt to disable parallel processing.
.NOTPARALLEL:
.NO_PARALLEL:
@BIND9_VERSION@
@BIND9_MAKE_INCLUDES@
CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@
CDEFINES = @USE_OPENSSL@ -DTESTS="\"${top_builddir}/lib/dns/tests/\""
ISCLIBS = ../../isc/libisc.@A@
ISCDEPLIBS = ../../isc/libisc.@A@
DNSLIBS = ../libdns.@A@ @DNS_CRYPTO_LIBS@
DNSDEPLIBS = ../libdns.@A@
LIBS = @LIBS@ @ATFLIBS@
OBJS = dnstest.@O@
SRCS = dnstest.c master_test.c
SUBDIRS =
TARGETS = master_test@EXEEXT@
@BIND9_MAKE_RULES@
master_test@EXEEXT@: master_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
master_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
clean distclean::
rm -f ${TARGETS}

121
lib/dns/tests/dnstest.c Normal file
View file

@ -0,0 +1,121 @@
/*
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dnstest.c,v 1.2 2011/02/26 02:26:11 each Exp $ */
/*! \file */
#include <config.h>
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/entropy.h>
#include <isc/hash.h>
#include <isc/mem.h>
#include <isc/string.h>
#include <isc/util.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/result.h>
#include <dst/dst.h>
#include "dnstest.h"
isc_mem_t *mctx = NULL;
isc_entropy_t *ectx = NULL;
isc_log_t *lctx = NULL;
static isc_boolean_t hash_active = ISC_FALSE, dst_active = ISC_FALSE;
/*
* Logging categories: this needs to match the list in bin/named/log.c.
*/
static isc_logcategory_t categories[] = {
{ "", 0 },
{ "client", 0 },
{ "network", 0 },
{ "update", 0 },
{ "queries", 0 },
{ "unmatched", 0 },
{ "update-security", 0 },
{ "query-errors", 0 },
{ NULL, 0 }
};
isc_result_t
dns_test_begin(FILE *logfile) {
isc_result_t result;
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
CHECK(isc_mem_create(0, 0, &mctx));
CHECK(isc_entropy_create(mctx, &ectx));
CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE));
hash_active = ISC_TRUE;
CHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_BLOCKING));
dst_active = ISC_TRUE;
if (logfile != NULL) {
isc_logdestination_t destination;
isc_logconfig_t *logconfig = NULL;
CHECK(isc_log_create(mctx, &lctx, &logconfig));
isc_log_registercategories(lctx, categories);
isc_log_setcontext(lctx);
dns_log_init(lctx);
dns_log_setcontext(lctx);
destination.file.stream = logfile;
destination.file.name = NULL;
destination.file.versions = ISC_LOG_ROLLNEVER;
destination.file.maximum_size = 0;
CHECK(isc_log_createchannel(logconfig, "stderr",
ISC_LOG_TOFILEDESC,
ISC_LOG_DYNAMIC,
&destination, 0));
CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
}
dns_result_register();
return (ISC_R_SUCCESS);
cleanup:
dns_test_end();
return (result);
}
void
dns_test_end() {
if (lctx != NULL)
isc_log_destroy(&lctx);
if (dst_active) {
dst_lib_destroy();
dst_active = ISC_FALSE;
}
if (hash_active) {
isc_hash_destroy();
hash_active = ISC_FALSE;
}
if (ectx != NULL)
isc_entropy_detach(&ectx);
if (mctx != NULL)
isc_mem_destroy(&mctx);
}

51
lib/dns/tests/dnstest.h Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dnstest.h,v 1.2 2011/02/26 02:26:11 each Exp $ */
/*! \file */
#include <config.h>
#include <isc/buffer.h>
#include <isc/entropy.h>
#include <isc/hash.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/result.h>
#define CHECK(r) \
do { \
result = (r); \
if (result != ISC_R_SUCCESS) \
goto cleanup; \
} while (0)
extern isc_mem_t *mctx;
extern isc_entropy_t *ectx;
extern isc_log_t *lctx;
isc_result_t
dns_test_begin(FILE *logfile);
void
dns_test_end(void);

355
lib/dns/tests/master_test.c Normal file
View file

@ -0,0 +1,355 @@
/*
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master_test.c,v 1.2 2011/02/26 02:26:11 each Exp $ */
/*! \file */
#include <config.h>
#include <atf-c.h>
#include <unistd.h>
#include <dns/cache.h>
#include <dns/callbacks.h>
#include <dns/master.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include "dnstest.h"
/*
* Helper functions
*/
#define BUFLEN 255
#define BIGBUFLEN (64 * 1024)
#define TEST_ORIGIN "test"
static isc_result_t
add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset);
static isc_result_t
add_callback(void *arg, dns_name_t *owner, dns_rdataset_t *dataset) {
char buf[BIGBUFLEN];
isc_buffer_t target;
isc_result_t result;
UNUSED(arg);
isc_buffer_init(&target, buf, BIGBUFLEN);
result = dns_rdataset_totext(dataset, owner, ISC_FALSE, ISC_FALSE,
&target);
return(result);
}
static int
test_master(const char *testfile) {
isc_result_t result;
int len;
char origin[sizeof(TEST_ORIGIN)];
dns_name_t dns_origin;
isc_buffer_t source;
isc_buffer_t target;
unsigned char name_buf[BUFLEN];
dns_rdatacallbacks_t callbacks;
strcpy(origin, TEST_ORIGIN);
len = strlen(origin);
isc_buffer_init(&source, origin, len);
isc_buffer_add(&source, len);
isc_buffer_setactive(&source, len);
isc_buffer_init(&target, name_buf, BUFLEN);
dns_name_init(&dns_origin, NULL);
result = dns_name_fromtext(&dns_origin, &source, dns_rootname,
0, &target);
if (result != ISC_R_SUCCESS)
return(result);
dns_rdatacallbacks_init_stdio(&callbacks);
callbacks.add = add_callback;
/*
* atf-run changes us to a /tmp directory, so tests
* that access test data files must first chdir to the proper
* location.
*/
if (chdir(TESTS) == -1)
return (ISC_R_FAILURE);
result = dns_master_loadfile(testfile, &dns_origin, &dns_origin,
dns_rdataclass_in, ISC_TRUE,
&callbacks, mctx);
return (result);
}
/*
* Individual unit tests
*/
/* Successful load test */
ATF_TC(master_load);
ATF_TC_HEAD(master_load, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() loads a "
"valid master file and returns success");
}
ATF_TC_BODY(master_load, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master1.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/* Unepxected end of file test */
ATF_TC(master_unexpected);
ATF_TC_HEAD(master_unexpected, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
"DNS_R_UNEXPECTED when file ends "
"too soon");
}
ATF_TC_BODY(master_unexpected, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master2.data");
ATF_REQUIRE_EQ(result, ISC_R_UNEXPECTEDEND);
dns_test_end();
}
/* No owner test */
ATF_TC(master_noowner);
ATF_TC_HEAD(master_noowner, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() accepts broken "
"zones with no TTL for first record "
"if it is an SOA");
}
ATF_TC_BODY(master_noowner, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master3.data");
ATF_REQUIRE_EQ(result, DNS_R_NOOWNER);
dns_test_end();
}
/* No TTL test */
ATF_TC(master_nottl);
ATF_TC_HEAD(master_nottl, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
"DNS_R_NOOWNER when no owner name "
"is specified");
}
ATF_TC_BODY(master_nottl, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master4.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/* Bad class test */
ATF_TC(master_badclass);
ATF_TC_HEAD(master_badclass, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() returns "
"DNS_R_BADCLASS when record class "
"doesn't match zone class");
}
ATF_TC_BODY(master_badclass, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master5.data");
ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
dns_test_end();
}
/* DNSKEY test */
ATF_TC(master_dnskey);
ATF_TC_HEAD(master_dnskey, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
"DNSKEY with key material");
}
ATF_TC_BODY(master_dnskey, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master6.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/* DNSKEY with no key material test */
ATF_TC(master_dnsnokey);
ATF_TC_HEAD(master_dnsnokey, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
"DNSKEY with no key material");
}
ATF_TC_BODY(master_dnsnokey, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master7.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/* Include test */
ATF_TC(master_include);
ATF_TC_HEAD(master_include, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
"$INCLUDE");
}
ATF_TC_BODY(master_include, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master8.data");
ATF_REQUIRE_EQ(result, DNS_R_SEENINCLUDE);
dns_test_end();
}
/* Include failure test */
ATF_TC(master_includefail);
ATF_TC_HEAD(master_includefail, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() understands "
"$INCLUDE failures");
}
ATF_TC_BODY(master_includefail, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master9.data");
ATF_REQUIRE_EQ(result, DNS_R_BADCLASS);
dns_test_end();
}
/* Non-empty blank lines test */
ATF_TC(master_blanklines);
ATF_TC_HEAD(master_blanklines, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() handles "
"non-empty blank lines");
}
ATF_TC_BODY(master_blanklines, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master10.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/* SOA leading zeroes test */
ATF_TC(master_leadingzero);
ATF_TC_HEAD(master_leadingzero, tc) {
atf_tc_set_md_var(tc, "descr", "dns_master_loadfile() allows "
"leading zeroes in SOA");
}
ATF_TC_BODY(master_leadingzero, tc) {
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = test_master("testdata/master/master11.data");
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_test_end();
}
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, master_load);
ATF_TP_ADD_TC(tp, master_unexpected);
ATF_TP_ADD_TC(tp, master_noowner);
ATF_TP_ADD_TC(tp, master_nottl);
ATF_TP_ADD_TC(tp, master_badclass);
ATF_TP_ADD_TC(tp, master_dnskey);
ATF_TP_ADD_TC(tp, master_dnsnokey);
ATF_TP_ADD_TC(tp, master_include);
ATF_TP_ADD_TC(tp, master_includefail);
ATF_TP_ADD_TC(tp, master_blanklines);
ATF_TP_ADD_TC(tp, master_leadingzero);
return (atf_no_error());
}

View file

@ -0,0 +1,11 @@
$TTL 1000
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
a in ns ns.vix.com.
a in ns ns2vix.com.
a in ns ns3vix.com.
b in a 1.2.3.4

View file

@ -0,0 +1,7 @@
;
; the following black line contains spaces
;
@ 300 IN A 10.0.0.1
;
;

View file

@ -0,0 +1,6 @@
;
; The following serial number contains a leading 0 and a 9 so the
; we can catch cases where it is incorrectly treated as a octal
; number.
;
@ 300 IN SOA ns hostmaster 00090000 1200 3600 604800 300

View file

@ -0,0 +1,11 @@
$TTL 1000
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
a in ns
a in ns ns2vix.com.
a in ns ns3vix.com.
b in a 1.2.3.4

View file

@ -0,0 +1,11 @@
$TTL 1000
in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
in ns ns.vix.com
in ns ns2vix.com.
a in ns ns3vix.com.
b in a 1.2.3.4

View file

@ -0,0 +1,11 @@
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
a in ns ns.vix.com.
a in ns ns2vix.com.
a in ns ns3vix.com.
b in a 1.2.3.4

View file

@ -0,0 +1,11 @@
$TTL 1000
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
a any ns ns.vix.com.
a in ns ns2vix.com.
a in ns ns3vix.com.
b in a 1.2.3.4

View file

@ -0,0 +1,33 @@
$TTL 1000
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
secure1 3600 IN DNSKEY (
FLAG2|FLAG4|FLAG5|NTYP3|FLAG8|FLAG9|FLAG10|FLAG11|SIG15
3 3
ArT0a8FtOZWEONG2YQVl9+RA34op30JPz4NPEroCxm2yImT2
2OYggnPIzrgayyepgKU1PfTTypnJDTwrSrtISyEsj7tjM7/n
03DP8VWSn0aLwpUuc7Sx9vtM1Wi+YeiA4Bv2Oz1VB9de4qql
sIq+KLn8J4wz95bGnJ0mHUB7oTDJ3Hl1zeaCMdX69Kr46yAY
AvGJJdGGDYxYgxzx2zNdzypkYSkxpdsNqUt38tabSfdvCn12
pnmSWjlVJsjHhsaYnrPhouN5acOXMNbxNVbGU5LZ8Es6EYbV
/7YMt8VUkA8/8UCszBBT7XAJ3OFjiMO8mvxrZZFzvwJlPBQ1
oFq/TNZlSe+N )
secure2 3600 in DNSKEY (
flag2|flag4|flag5|ntyp3|flag8|flag9|flag10|flag11|sig15
3 3
ArT0a8FtOZWEONG2YQVl9+RA34op30JPz4NPEroCxm2yImT2
2OYggnPIzrgayyepgKU1PfTTypnJDTwrSrtISyEsj7tjM7/n
03DP8VWSn0aLwpUuc7Sx9vtM1Wi+YeiA4Bv2Oz1VB9de4qql
sIq+KLn8J4wz95bGnJ0mHUB7oTDJ3Hl1zeaCMdX69Kr46yAY
AvGJJdGGDYxYgxzx2zNdzypkYSkxpdsNqUt38tabSfdvCn12
pnmSWjlVJsjHhsaYnrPhouN5acOXMNbxNVbGU5LZ8Es6EYbV
/7YMt8VUkA8/8UCszBBT7XAJ3OFjiMO8mvxrZZFzvwJlPBQ1
oFq/TNZlSe+N )

View file

@ -0,0 +1,17 @@
$TTL 1000
@ in soa localhost. postmaster.localhost. (
1993050801 ;serial
3600 ;refresh
1800 ;retry
604800 ;expiration
3600 ) ;minimum
secure1 3600 IN DNSKEY (
NOKEY|FLAG2|FLAG4|FLAG5|NTYP3|FLAG8|FLAG9|FLAG10|FLAG11|SIG15
3 3 )
secure2 3600 in DNSKEY (
nokey|flag2|flag4|flag5|ntyp3|flag8|flag9|flag10|flag11|sig15
3 3 )

View file

@ -0,0 +1,4 @@
;
; master7.data contains a good zone file
;
$include testdata/master/master7.data

View file

@ -0,0 +1,4 @@
;
; master5.data is bad
;
$include testdata/master/master5.data

View file

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: rules.in,v 1.68 2009/09/01 18:40:25 jinmei Exp $
# $Id: rules.in,v 1.69 2011/02/26 02:26:11 each Exp $
###
### Common Makefile rules for BIND 9.
@ -50,7 +50,7 @@ top_builddir = @BIND9_TOP_BUILDDIR@
### Makefile may define:
### TARGETS
all: subdirs ${TARGETS}
all: subdirs ${TARGETS} testdirs
###
### Subdirectories
@ -59,11 +59,12 @@ all: subdirs ${TARGETS}
### SUBDIRS
ALL_SUBDIRS = ${SUBDIRS} nulldir
ALL_TESTDIRS = ${TESTDIRS} nulldir
#
# We use a single-colon rule so that additional dependencies of
# subdirectories can be specified after the inclusion of this file.
# The "depend" target is treated the same way.
# The "depend" and "testdirs" targets are treated the same way.
#
subdirs:
@for i in ${ALL_SUBDIRS}; do \
@ -73,6 +74,17 @@ subdirs:
fi; \
done
#
# Tests are built after the targets instead of before
#
testdirs:
@for i in ${ALL_TESTDIRS}; do \
if [ "$$i" != "nulldir" -a -d $$i ]; then \
echo "making all in `pwd`/$$i"; \
(cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" all) || exit 1; \
fi; \
done
install:: all
install clean distclean maintainer-clean doc docclean man manclean::

3
unit/.cvsignore Normal file
View file

@ -0,0 +1,3 @@
Makefile
atf
unittest.sh

40
unit/Makefile.in Normal file
View file

@ -0,0 +1,40 @@
# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.2 2011/02/26 02:26:12 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
SUBDIRS = @ATFBUILD@
TARGETS = atf
@BIND9_MAKE_RULES@
#
# install ATF libraries, if configured with --with-atf
#
atf:
@for i in ${ALL_SUBDIRS}; do \
if [ "$$i" != "nulldir" -a -d $$i ]; then \
(cd $$i; ${MAKE} ${MAKEDEFS} install) || exit 1; \
fi; \
done
clean distclean::
rm -rf ./atf
distclean::
rm unittest.sh

2
unit/README Normal file
View file

@ -0,0 +1,2 @@
These unit tests for BIND 9 are based on the NetBSD Automated Test Framework
release 0.12.

11
unit/atf-src/.cvsignore Normal file
View file

@ -0,0 +1,11 @@
.libs
Makefile
autom4te.cache
bconfig.h
config.log
config.status
configure.lineno
libatf-c++.la
libatf-c.la
libtool
stamp-h1

25
unit/atf-src/AUTHORS Normal file
View file

@ -0,0 +1,25 @@
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.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

11
unit/atf-src/Atffile Normal file
View file

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

70
unit/atf-src/COPYING Normal file
View file

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

223
unit/atf-src/INSTALL Normal file
View file

@ -0,0 +1,223 @@
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.1
* GNU libtool 2.2.6b
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.
The following flags are specific to ATF's 'configure' script:
* --enable-developer
Possible values: yes, no
Default: Depends on the version number. Stable versions define this to
'no' while all others have it set to 'yes'.
Enables several features useful for development, such as the inclusion of
debugging symbols in all objects or the enabling of warnings during
compilation.
* --enable-unstable-shared
Possible values: yes, no
Default: no.
Forces the building of shared libraries in addition to static ones. The
build of shared libraries is currently disabled because their ABIs and
APIs are unstable and subject to change. This flag is provided for
development purposes only and will be removed once the libraries are
stable enough.
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

118
unit/atf-src/Makefile.am Normal file
View file

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

4938
unit/atf-src/Makefile.in Normal file

File diff suppressed because it is too large Load diff

423
unit/atf-src/NEWS Normal file
View file

@ -0,0 +1,423 @@
Major changes between releases Automated Testing Framework
===========================================================================
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
unit/atf-src/README Normal file
View file

@ -0,0 +1,40 @@
Introductory information Automated Testing Framework
===========================================================================
Introduction
************
The Automated Testing Framework (ATF) is a collection of libraries and
utilities designed to ease unattended application testing in the hands of
developers and end users of a specific piece of software.
As regards developers, ATF provides the necessary means to easily create
test suites composed of multiple test programs, which in turn are a
collection of test cases. It also attempts to simplify the debugging of
problems when these test cases detect an error by providing as much
information as possible about the failure.
As regards users, it simplifies the process of running the test suites and,
in special, encourages end users to run them often: they do not need to
have source trees around nor any other development tools installed to be
able to certify that a given piece of software works on their machine as
advertised.
Other documents
***************
* AUTHORS: List of authors and contributors for this project.
* COPYING: License information.
* INSTALL: Compilation and installation instructions. These is not the
standard document shipped with many packages, so be sure to read it for
things that are specific to ATF's build.
* NEWS: List of major changes between formal, published releases.
===========================================================================
vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2

1001
unit/atf-src/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,92 @@
#! /bin/sh
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007, 2008, 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.
#
#
# 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

View file

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

View file

@ -0,0 +1,82 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007, 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.
#
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

View file

@ -0,0 +1,90 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007, 2008, 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.
#
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

View file

@ -0,0 +1,78 @@
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007, 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.
#
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

View file

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

187
unit/atf-src/admin/check-style.sh Executable file
View file

@ -0,0 +1,187 @@
#! /bin/sh
#
# Automated Testing Framework (atf)
#
# Copyright (c) 2007, 2008, 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.
#
#
# 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 "*.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 "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

143
unit/atf-src/admin/compile Executable file
View file

@ -0,0 +1,143 @@
#! /bin/sh
# Wrapper for compilers which do not understand `-c -o'.
scriptversion=2009-10-06.20; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 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>.
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 $?
;;
esac
ofile=
cfile=
eat=
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:

1502
unit/atf-src/admin/config.guess vendored Executable file

File diff suppressed because it is too large Load diff

1708
unit/atf-src/admin/config.sub vendored Executable file

File diff suppressed because it is too large Load diff

630
unit/atf-src/admin/depcomp Executable file
View file

@ -0,0 +1,630 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2009-04-28.21; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 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 outputing 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
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.
## 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"
;;
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"
;;
#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"
cat < "$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:

291
unit/atf-src/admin/install-sh Executable file
View file

@ -0,0 +1,291 @@
#!/bin/sh
#
# $NetBSD: install-sh.in,v 1.4 2007/07/12 18:32:50 jlam Exp $
# This script now also installs multiple files, but might choke on installing
# multiple files with spaces in the file names.
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# 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.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
awkprog="${AWKPROG-awk}"
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
instcmd="$mvprog"
pathcompchmodcmd="$chmodprog 755"
chmodcmd="$chmodprog 755"
chowncmd=""
chgrpcmd=""
stripcmd=""
stripflags=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
msrc=""
dst=""
dir_arg=""
suffix=""
suffixfmt=""
while [ x"$1" != x ]; do
case $1 in
-b) suffix=".old"
shift
continue;;
-B) suffixfmt="$2"
shift
shift
continue;;
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-S) stripcmd="$stripprog"
stripflags="-S $2 $stripflags"
shift
shift
continue;;
*) if [ x"$msrc" = x ]
then
msrc="$dst"
else
msrc="$msrc $dst"
fi
src="$dst"
dst="$1"
shift
continue;;
esac
done
if [ x"$dir_arg" = x ]
then
dstisfile=""
if [ ! -d "$dst" ]
then
if [ x"$msrc" = x"$src" ]
then
dstisfile=true
else
echo "install: destination is not a directory"
exit 1
fi
fi
else
msrc="$msrc $dst"
fi
if [ x"$msrc" = x ]
then
echo "install: no destination specified"
exit 1
fi
for srcarg in $msrc; do
if [ x"$dir_arg" != x ]; then
dstarg="$srcarg"
else
dstarg="$dst"
# Waiting for this to be detected by the "$instcmd $srcarg $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f "$srcarg" ]
then
doinst="$instcmd"
elif [ -d "$srcarg" ]
then
echo "install: $srcarg: not a regular file"
exit 1
elif [ "$srcarg" = "/dev/null" ]
then
doinst="$cpprog"
else
echo "install: $srcarg does not exist"
exit 1
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d "$dstarg" ]
then
dstarg="$dstarg"/`basename "$srcarg"`
fi
fi
## this sed command emulates the dirname command
dstdir=`echo "$dstarg" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$doit $mkdirprog "${pathcomp}"
if [ x"$chowncmd" != x ]; then $doit $chowncmd "${pathcomp}"; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "${pathcomp}"; else true ; fi &&
if [ x"$pathcompchmodcmd" != x ]; then $doit $pathcompchmodcmd "${pathcomp}"; else true ; fi
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
if [ -d "$dstarg" ]; then
true
else
$doit $mkdirprog "$dstarg" &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dstarg"; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dstarg"; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dstarg"; else true ; fi
fi
else
if [ x"$dstisfile" = x ]
then
file=$srcarg
else
file=$dst
fi
dstfile=`basename "$file"`
dstfinal="$dstdir/$dstfile"
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Make a backup file name in the proper directory.
case x$suffixfmt in
*%*) suffix=`echo x |
$awkprog -v bname="$dstfinal" -v fmt="$suffixfmt" '
{ cnt = 0;
do {
sfx = sprintf(fmt, cnt++);
name = bname sfx;
} while (system("test -f " name) == 0);
print sfx; }' -`;;
x) ;;
*) suffix="$suffixfmt";;
esac
dstbackup="$dstfinal$suffix"
# Move or copy the file name to the temp name
$doit $doinst $srcarg "$dsttmp" &&
trap "rm -f ${dsttmp}" 0 &&
# 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 $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripflags "$dsttmp"; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else true;fi &&
# Now rename the file to the real destination.
if [ x"$suffix" != x ] && [ -f "$dstfinal" ]
then
$doit $mvcmd "$dstfinal" "$dstbackup"
else
$doit $rmcmd -f "$dstfinal"
fi &&
$doit $mvcmd "$dsttmp" "$dstfinal"
fi
done &&
exit 0

8406
unit/atf-src/admin/ltmain.sh Executable file

File diff suppressed because it is too large Load diff

376
unit/atf-src/admin/missing Executable file
View file

@ -0,0 +1,376 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2009-04-28.21; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009 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
tar try tar, gnutar, gtar, then tar without non-portable flags
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.
;;
tar*)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
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
;;
tar*)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case $firstarg in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case $firstarg in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
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
unit/atf-src/atf-c++.hpp Normal file
View file

@ -0,0 +1,35 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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_HPP_)
#define _ATF_CXX_HPP_
#include <atf-c++/macros.hpp>
#endif // !defined(_ATF_CXX_HPP_)

View file

@ -0,0 +1,16 @@
.deps
.dirstamp
.libs
atf-c++.pc
atf_c++_test
build.lo
build_test
check.lo
check_test
config.lo
config_test
macros_test
pkg_config_test
tests.lo
tests_test
utils_test

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,158 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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>
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));
}

View file

@ -0,0 +1,133 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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_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_)

View file

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

View file

@ -0,0 +1,123 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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 <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

View file

@ -0,0 +1,75 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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_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_)

View file

@ -0,0 +1,231 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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 "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);
}

View file

@ -0,0 +1,24 @@
.deps
.dirstamp
.libs
application.lo
application_test
env.lo
env_test
exceptions.lo
exceptions_test
expand.lo
expand_test
fs.lo
fs_test
libtest_helpers.la
parser.lo
parser_test
process.lo
process_test
sanity_test
test_helpers.lo
text.lo
text_test
ui.lo
ui_test

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,93 @@
//
// 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_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);
}

View file

@ -0,0 +1,73 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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 "../../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);
}

View file

@ -0,0 +1,84 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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_ENV_HPP_)
#define _ATF_CXX_ENV_HPP_
#include <string>
namespace atf {
namespace env {
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
//!
//! \brief Returns the value of an environment variable.
//!
//! Returns the value of the specified environment variable. The variable
//! must be defined.
//!
std::string get(const std::string&);
//!
//! \brief Checks if the environment has a variable.
//!
//! Checks if the environment has a given variable.
//!
bool has(const std::string&);
//!
//! \brief Sets an environment variable to a given value.
//!
//! Sets the specified environment variable to the given value. Note that
//! variables set to the empty string are different to undefined ones.
//!
//! Be aware that this alters the program's global status, which in general
//! is a bad thing to do due to the side-effects it may have. There are
//! some legitimate usages for this function, though.
//!
void set(const std::string&, const std::string&);
//!
//! \brief Unsets an environment variable.
//!
//! Unsets the specified environment variable Note that undefined
//! variables are different to those defined but set to an empty value.
//!
//! Be aware that this alters the program's global status, which in general
//! is a bad thing to do due to the side-effects it may have. There are
//! some legitimate usages for this function, though.
//!
void unset(const std::string&);
} // namespace env
} // namespace atf
#endif // !defined(_ATF_CXX_ENV_HPP_)

View file

@ -0,0 +1,91 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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 "env.hpp"
// ------------------------------------------------------------------------
// Test cases for the free functions.
// ------------------------------------------------------------------------
ATF_TEST_CASE(has_get);
ATF_TEST_CASE_HEAD(has_get)
{
set_md_var("descr", "Tests the has and get functions");
}
ATF_TEST_CASE_BODY(has_get)
{
ATF_REQUIRE(atf::env::has("PATH"));
ATF_REQUIRE(!atf::env::get("PATH").empty());
ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
}
ATF_TEST_CASE(set);
ATF_TEST_CASE_HEAD(set)
{
set_md_var("descr", "Tests the set function");
}
ATF_TEST_CASE_BODY(set)
{
ATF_REQUIRE(atf::env::has("PATH"));
const std::string& oldval = atf::env::get("PATH");
atf::env::set("PATH", "foo-bar");
ATF_REQUIRE(atf::env::get("PATH") != oldval);
ATF_REQUIRE_EQ(atf::env::get("PATH"), "foo-bar");
ATF_REQUIRE(!atf::env::has("_UNDEFINED_VARIABLE_"));
atf::env::set("_UNDEFINED_VARIABLE_", "foo2-bar2");
ATF_REQUIRE_EQ(atf::env::get("_UNDEFINED_VARIABLE_"), "foo2-bar2");
}
ATF_TEST_CASE(unset);
ATF_TEST_CASE_HEAD(unset)
{
set_md_var("descr", "Tests the unset function");
}
ATF_TEST_CASE_BODY(unset)
{
ATF_REQUIRE(atf::env::has("PATH"));
atf::env::unset("PATH");
ATF_REQUIRE(!atf::env::has("PATH"));
}
// ------------------------------------------------------------------------
// Main.
// ------------------------------------------------------------------------
ATF_INIT_TEST_CASES(tcs)
{
// Add the test cases for the free functions.
ATF_ADD_TEST_CASE(tcs, has_get);
ATF_ADD_TEST_CASE(tcs, set);
ATF_ADD_TEST_CASE(tcs, unset);
}

View file

@ -0,0 +1,156 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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(HAVE_CONFIG_H)
#include "bconfig.h"
#endif
#include <cstdarg>
#include <cstdio>
#include <cstring>
extern "C" {
#include "../../atf-c/error.h"
};
#include "exceptions.hpp"
#include "sanity.hpp"
// ------------------------------------------------------------------------
// The "system_error" type.
// ------------------------------------------------------------------------
atf::system_error::system_error(const std::string& who,
const std::string& message,
int sys_err) :
std::runtime_error(who + ": " + message),
m_sys_err(sys_err)
{
}
atf::system_error::~system_error(void)
throw()
{
}
int
atf::system_error::code(void)
const
throw()
{
return m_sys_err;
}
const char*
atf::system_error::what(void)
const
throw()
{
try {
if (m_message.length() == 0) {
m_message = std::string(std::runtime_error::what()) + ": ";
m_message += ::strerror(m_sys_err);
}
return m_message.c_str();
} catch (...) {
return "Unable to format system_error message";
}
}
// ------------------------------------------------------------------------
// Free functions.
// ------------------------------------------------------------------------
static
void
throw_libc_error(atf_error_t err)
{
PRE(atf_error_is(err, "libc"));
const int ecode = atf_libc_error_code(err);
const std::string msg = atf_libc_error_msg(err);
atf_error_free(err);
throw atf::system_error("XXX", msg, ecode);
}
static
void
throw_no_memory_error(atf_error_t err)
{
PRE(atf_error_is(err, "no_memory"));
atf_error_free(err);
throw std::bad_alloc();
}
static
void
throw_unknown_error(atf_error_t err)
{
PRE(atf_is_error(err));
static char buf[4096];
atf_error_format(err, buf, sizeof(buf));
atf_error_free(err);
throw std::runtime_error(buf);
}
void
atf::throw_atf_error(atf_error_t err)
{
static struct handler {
const char* m_name;
void (*m_func)(atf_error_t);
} handlers[] = {
{ "libc", throw_libc_error },
{ "no_memory", throw_no_memory_error },
{ NULL, throw_unknown_error },
};
PRE(atf_is_error(err));
handler* h = handlers;
while (h->m_name != NULL) {
if (atf_error_is(err, h->m_name)) {
h->m_func(err);
UNREACHABLE;
} else
h++;
}
// XXX: I'm not sure that raising an "unknown" error is a wise thing
// to do here. The C++ binding is supposed to have feature parity
// with the C one, so all possible errors raised by the C library
// should have their counterpart in the C++ library. Still, removing
// this will require some code auditing that I can't afford at the
// moment.
INV(h->m_name == NULL && h->m_func != NULL);
h->m_func(err);
UNREACHABLE;
}

View file

@ -0,0 +1,98 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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_EXCEPTIONS_HPP_)
#define _ATF_CXX_EXCEPTIONS_HPP_
#include <stdexcept>
extern "C" {
struct atf_error;
}
namespace atf {
template< class T >
class not_found_error :
public std::runtime_error
{
T m_value;
public:
not_found_error(const std::string& message, const T& value) throw();
virtual ~not_found_error(void) throw();
const T& get_value(void) const throw();
};
template< class T >
inline
not_found_error< T >::not_found_error(const std::string& message,
const T& value)
throw() :
std::runtime_error(message),
m_value(value)
{
}
template< class T >
inline
not_found_error< T >::~not_found_error(void)
throw()
{
}
template< class T >
inline
const T&
not_found_error< T >::get_value(void)
const
throw()
{
return m_value;
}
class system_error : public std::runtime_error {
int m_sys_err;
mutable std::string m_message;
public:
system_error(const std::string&, const std::string&, int);
~system_error(void) throw();
int code(void) const throw();
const char* what(void) const throw();
};
void throw_atf_error(struct atf_error *);
} // namespace atf
#endif // !defined(_ATF_CXX_EXCEPTIONS_HPP_)

View file

@ -0,0 +1,147 @@
//
// 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 "../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);
}

View file

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

View file

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

View file

@ -0,0 +1,272 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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 "../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);
}

View file

@ -0,0 +1,517 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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(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);
}

View file

@ -0,0 +1,391 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 2008, 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_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_)

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,355 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008, 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 <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();
}

View file

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

View file

@ -0,0 +1,357 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2008, 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 <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);
}

View file

@ -0,0 +1,37 @@
//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007, 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_SANITY_HPP_)
#define _ATF_CXX_SANITY_HPP_
extern "C" {
#include "../../atf-c/detail/sanity.h"
}
#endif // !defined(_ATF_CXX_SANITY_HPP_)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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