summaryrefslogtreecommitdiff
path: root/cpp/src/tests
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2007-05-30 16:13:58 +0000
committerAlan Conway <aconway@apache.org>2007-05-30 16:13:58 +0000
commit1d63a898503d20e3221be43fc222f0091971a0ce (patch)
tree78d8673b9ed8820e431b6a6f353ba0143adeb800 /cpp/src/tests
parentf2b034ea3f4fa70e512fafdf18fd42c370194329 (diff)
downloadqpid-python-1d63a898503d20e3221be43fc222f0091971a0ce.tar.gz
Logging infrastructure: See qpidd --long-help for details.
* src/qpid/log/*: Logging infrastructure, QPID_LOG macro. * src/*: changed output to cout/cerr to logging. * src/qpidd.cpp: logging options. * src/tests/Makefile.am: fixed issues with valgrind * src/tests/kill|start_broker: use broker daemon options. * src/tests/run_test: run tests in valgrind. Disabled till leaks in client_test are fixed. * src/test/unit/logging.cpp: Logging unit test using boost test framework. Eventually we should move all unit tests to boost & drop CppUnit. * src/test/unit/test_tools.h: useful extensions to boost framework: Regular expression check, ostream << for vectors. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@542855 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/tests')
-rw-r--r--cpp/src/tests/.valgrind.supp-default (renamed from cpp/src/tests/.valgrind.supp)0
-rw-r--r--cpp/src/tests/AccumulatedAckTest.cpp1
-rw-r--r--cpp/src/tests/Makefile.am35
-rwxr-xr-xcpp/src/tests/kill_broker3
-rwxr-xr-xcpp/src/tests/run_test60
-rwxr-xr-xcpp/src/tests/start_broker17
-rw-r--r--cpp/src/tests/unit/logging.cpp373
-rw-r--r--cpp/src/tests/unit/test_tools.h53
8 files changed, 518 insertions, 24 deletions
diff --git a/cpp/src/tests/.valgrind.supp b/cpp/src/tests/.valgrind.supp-default
index 8b13789179..8b13789179 100644
--- a/cpp/src/tests/.valgrind.supp
+++ b/cpp/src/tests/.valgrind.supp-default
diff --git a/cpp/src/tests/AccumulatedAckTest.cpp b/cpp/src/tests/AccumulatedAckTest.cpp
index aa90de5b42..edd4b0d807 100644
--- a/cpp/src/tests/AccumulatedAckTest.cpp
+++ b/cpp/src/tests/AccumulatedAckTest.cpp
@@ -1,3 +1,4 @@
+
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am
index 198c9ce7ef..699a2f073c 100644
--- a/cpp/src/tests/Makefile.am
+++ b/cpp/src/tests/Makefile.am
@@ -1,6 +1,17 @@
AM_CXXFLAGS = $(WARNING_CFLAGS) $(CPPUNIT_CXXFLAGS) $(APR_CXXFLAGS)
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../gen -I$(top_builddir)/src/gen
+
+# Unit test programs
+UNIT_TESTS=
+
+UNIT_TESTS+=logging
+logging_SOURCES=unit/logging.cpp unit/test_tools.h
+logging_LDADD=-lboost_unit_test_framework -lboost_regex $(lib_common)
+
+# NB: CppUnit test libraries below will be migrated to boost test programs.
+# UNIT_TESTS+= ...
+
# Unit tests
broker_unit_tests = \
AccumulatedAckTest \
@@ -52,19 +63,24 @@ testprogs = \
topic_listener \
topic_publisher
-noinst_PROGRAMS = $(testprogs)
+check_PROGRAMS = $(UNIT_TESTS) $(testprogs)
+# FIXME aconway 2007-05-30: TESTS_ENVIRONMENT should have ./run_test
+# as below to run valgrind on all test programs.
+# Disabled temporarily till leaks in client_test are fixed.
+#
+#TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) ./run_test
TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir)
-CLIENT_TESTS = client_test quick_topictest
-TESTS = run-unit-tests start_broker $(CLIENT_TESTS) python_tests kill_broker daemon_test
+SYSTEM_TESTS = client_test quick_topictest
+TESTS = $(UNIT_TESTS) run-unit-tests start_broker $(SYSTEM_TESTS) python_tests kill_broker daemon_test
EXTRA_DIST = \
test_env \
run-unit-tests start_broker python_tests kill_broker daemon_test \
quick_topictest \
topictest \
- .valgrind.supp \
+ .valgrind.supp-default \
.valgrindrc-default \
InProcessBroker.h \
MockChannel.h \
@@ -103,20 +119,21 @@ gen.mk: Makefile.am
> $@-t
mv $@-t $@
-check: .valgrindrc ../qpidd
+check: .valgrindrc .valgrind.supp
check-unit:
- $(MAKE) check TESTS=run-unit-tests
+ $(MAKE) check TESTS=$(UNIT_TESTS) run-unit-tests
# Create a copy so that can be modified without risk of committing the changes.
.valgrindrc: .valgrindrc-default
- cp $(srcdir)/.valgrindrc-default .valgrindrc
+ cp $^ $@
+.valgrind.supp: .valgrind.supp-default
+ cp $^ $@
# Tell GNU make not to build targets in this directory in parallel.
# This is necessary because with two or more identical and simultaneous
# ltmain invocations, one may corrupt the temporaries of the other.
.NOTPARALLEL:
-CLEANFILES=valgrind.out qpidd.log
-DISTCLEANFILES=.valgrindrc
+CLEANFILES=valgrind.out qpidd.log .valgrindrc .valgrind.supp
MAINTAINERCLEANFILES=gen.mk
diff --git a/cpp/src/tests/kill_broker b/cpp/src/tests/kill_broker
index b71ca22ffd..e6331d6876 100755
--- a/cpp/src/tests/kill_broker
+++ b/cpp/src/tests/kill_broker
@@ -1,3 +1,2 @@
#!/bin/sh
-PID=qpidd.pid
-if [ -f $PID ] ; then kill -9 `cat $PID` ; rm -f $PID ; fi
+../qpidd --quit
diff --git a/cpp/src/tests/run_test b/cpp/src/tests/run_test
new file mode 100755
index 0000000000..ef608e55ca
--- /dev/null
+++ b/cpp/src/tests/run_test
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Run a test executable. Output nothing if test passes,
+# show the output if it fails. Leave output in <test>.log for
+# examination.
+#
+# If $VALGRIND if is set run under valgrind. If there are
+# valgrind erros show valgrind output, also leave it in
+# <test>.valgrind for examination.
+#
+
+vg_failed() {
+ cat $VG_LOG 1>&2
+ echo $1 1>&2
+ exit 1
+}
+
+vg_check()
+{
+ test -f $VG_LOG || vg_failed Valgrind log file $VG_LOG missing.
+ # Ensure there is an ERROR SUMMARY line.
+ grep -E '^==[0-9]+== ERROR SUMMARY:' $VG_LOG > /dev/null || \
+ vg_failed "No valgrind ERROR SUMMARY line in $$vg_failed."
+ # Ensure that the number of errors is 0.
+ grep -E '^==[0-9]+== ERROR SUMMARY: [^0] ' $VG_LOG > /dev/null && \
+ vg_failed "Valgrind reported errors in $vg_out; see above."
+ # Check for leaks.
+ grep -E '^==[0-9]+== +.* lost: [^0]' $VG_LOG && \
+ vg_failed "Found memory leaks (see log file, $VG_LOG); see above."
+ true
+}
+
+# Export variables from makefile.
+export VALGRIND srcdir
+
+VG_LOG="$1.vglog"
+TEST_LOG="$1.log"
+rm -f $VG_LOG $TEST_LOG
+
+if grep -l "^# Generated by .*libtool" "$1" >/dev/null 2>&1; then
+ # This is a libtool "executable". Valgrind it if VALGRIND specified.
+ test -n "$VALGRIND" && VALGRIND="$VALGRIND --log-file-exactly=$VG_LOG --"
+ # Hide output unless there's an error.
+ libtool --mode=execute $VALGRIND "$@" >$TEST_LOG 2>&1 || {
+ ERROR=$?
+ cat $TEST_LOG
+ }
+ test -n "$VALGRIND" && vg_check
+else
+ # This is a non-libtool shell script, just execute it.
+ "$@"
+fi
+
+if test -z "$ERROR"; then
+ # Clean up logs if there was no error.
+ rm -f $VG_LOG $TEST_LOG
+ exit 0
+else
+ exit $ERROR
+fi
diff --git a/cpp/src/tests/start_broker b/cpp/src/tests/start_broker
index dfbaee6bcc..515a3a2b5e 100755
--- a/cpp/src/tests/start_broker
+++ b/cpp/src/tests/start_broker
@@ -1,14 +1,5 @@
#!/bin/sh
-set -e
-
-LOG=`pwd`/qpidd.log
-PID=`pwd`/qpidd.pid
-
-rm -rf $LOG $PID
-
-# Start the daemon, recording its PID.
-../qpidd > $LOG 2>&1 & echo $! > $PID
-
-# FIXME aconway 2007-01-18: qpidd should not return till it is accepting
-# connections, remove arbitrary sleep.
-sleep 30
+fail() { echo FAIL: $0:$* 1>&2; exit 1; }
+qpidd=../qpidd
+PID=`$qpidd --check --ppid` && fail $qpidd already running $PID
+$qpidd --log.output qpidd.log --daemon || fail $qpidd startup: `cat qpidd.log`
diff --git a/cpp/src/tests/unit/logging.cpp b/cpp/src/tests/unit/logging.cpp
new file mode 100644
index 0000000000..3dbe68ad2b
--- /dev/null
+++ b/cpp/src/tests/unit/logging.cpp
@@ -0,0 +1,373 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test_tools.h"
+#include "qpid/log/Logger.h"
+#include "qpid/log/Options.h"
+#include "qpid/memory.h"
+#include "qpid/CommonOptions.h"
+#include <boost/test/floating_point_comparison.hpp>
+#include <boost/format.hpp>
+#include <exception>
+#include <time.h>
+#include <fstream>
+
+
+using namespace std;
+using namespace boost;
+using namespace qpid::log;
+
+BOOST_AUTO_TEST_CASE(testStatementInit) {
+ Statement s=QPID_LOG_STATEMENT_INIT(debug); int line=__LINE__;
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK_EQUAL(string(__FILE__), s.file);
+ BOOST_CHECK_EQUAL(line, s.line);
+ BOOST_CHECK_EQUAL(string("void testStatementInit()"), s.function);
+ BOOST_CHECK_EQUAL(debug, s.level);
+}
+
+
+BOOST_AUTO_TEST_CASE(testSelector_enable) {
+ Selector s;
+ // Simple enable
+ s.enable(debug,"foo");
+ BOOST_CHECK(s.isEnabled(debug,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"foo"));
+ BOOST_CHECK(!s.isEnabled(error,"bar"));
+
+ // Substring match
+ BOOST_CHECK(s.isEnabled(debug, "bazfoobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bazbar"));
+
+ // Different levels for different substrings.
+ s.enable(info, "bar");
+ BOOST_CHECK(s.isEnabled(debug, "foobar"));
+ BOOST_CHECK(s.isEnabled(info, "foobar"));
+ BOOST_CHECK(!s.isEnabled(debug, "bar"));
+ BOOST_CHECK(!s.isEnabled(info, "foo"));
+
+ // Enable-strings
+ s.enable("notice:blob");
+ BOOST_CHECK(s.isEnabled(notice, "blob"));
+ s.enable("error+:oops");
+ BOOST_CHECK(s.isEnabled(error, "oops"));
+ BOOST_CHECK(s.isEnabled(critical, "oops"));
+}
+
+Logger& clearLogger() {
+ Logger::instance().clear();
+ return Logger::instance();
+}
+
+BOOST_AUTO_TEST_CASE(testStatementEnabled) {
+ // Verify that the logger enables and disables log statements.
+ Logger& l=clearLogger();
+ l.select(Selector(debug));
+ Statement s=QPID_LOG_STATEMENT_INIT(debug);
+ BOOST_CHECK(!s.enabled);
+ Statement::Initializer init(s);
+ BOOST_CHECK(s.enabled);
+
+ Statement s2=QPID_LOG_STATEMENT_INIT(warning);
+ Statement::Initializer init2(s2);
+ BOOST_CHECK(!s2.enabled);
+
+ l.select(Selector(warning));
+ BOOST_CHECK(!s.enabled);
+ BOOST_CHECK(s2.enabled);
+}
+
+struct TestOutput : public Logger::Output {
+ vector<string> msg;
+ vector<Statement> stmt;
+
+ TestOutput() {
+ Logger::instance().output(qpid::make_auto_ptr<Logger::Output>(this));
+ }
+ void log(const Statement& s, const string& m) {
+ msg.push_back(m);
+ stmt.push_back(s);
+ }
+ string last() { return msg.back(); }
+};
+
+using boost::assign::list_of;
+
+BOOST_AUTO_TEST_CASE(testLoggerOutput) {
+ Logger& l=clearLogger();
+ l.select(Selector(debug));
+ Statement s=QPID_LOG_STATEMENT_INIT(debug);
+ TestOutput* out=new TestOutput();
+
+ // Verify message is output.
+ l.log(s, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ // Verify multiple outputs
+ TestOutput* out2=new TestOutput();
+ l.log(Statement(), "baz");
+ expect.push_back("baz\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ expect.erase(expect.begin());
+ BOOST_CHECK_EQUAL(expect, out2->msg);
+}
+
+BOOST_AUTO_TEST_CASE(testMacro) {
+ Logger& l = clearLogger();
+ l.select(Selector(info));
+ TestOutput* out=new TestOutput();
+ QPID_LOG(info, "foo");
+ vector<string> expect=list_of("foo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+ BOOST_CHECK_EQUAL(__FILE__, out->stmt.front().file);
+ BOOST_CHECK_EQUAL("void testMacro()", out->stmt.front().function);
+
+ // Not enabled:
+ QPID_LOG(debug, "bar");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+
+ QPID_LOG(info, 42 << " bingo");
+ expect.push_back("42 bingo\n");
+ BOOST_CHECK_EQUAL(expect, out->msg);
+}
+
+BOOST_AUTO_TEST_CASE(testLoggerFormat) {
+ Logger& l=clearLogger();
+ l.select(Selector(critical));
+ TestOutput* out=new TestOutput();
+
+ // Time format is YYY-Month-dd hh:mm:ss
+ l.format(Logger::TIME);
+ QPID_LOG(critical, "foo");
+ string re("\\d\\d\\d\\d-[A-Z][a-z]+-\\d\\d \\d\\d:\\d\\d:\\d\\d foo\n");
+ BOOST_CHECK_REGEX(re, out->last());
+
+ l.format(Logger::FILE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL(out->last(), string(__FILE__)+": foo\n");
+
+ l.format(Logger::FILE|Logger::LINE);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_REGEX(string(__FILE__)+":\\d+: foo\n", out->last());
+
+ l.format(Logger::FUNCTION);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL("void testLoggerFormat(): foo\n", out->last());
+
+ l.format(Logger::LEVEL);
+ QPID_LOG(critical, "foo");
+ BOOST_CHECK_EQUAL("critical foo\n", out->last());
+
+ l.format(~0); // Everything
+ QPID_LOG(critical, "foo");
+ re=".* critical \\[[0-9a-f]*] "+string(__FILE__)+":\\d+:void testLoggerFormat\\(\\): foo\n";
+ BOOST_CHECK_REGEX(re, out->last());
+}
+
+BOOST_AUTO_TEST_CASE(testOstreamOutput) {
+ Logger& l=clearLogger();
+ l.select(Selector(error));
+ ostringstream os;
+ l.output(os);
+ QPID_LOG(error, "foo");
+ QPID_LOG(error, "bar");
+ QPID_LOG(error, "baz");
+ BOOST_CHECK_EQUAL("foo\nbar\nbaz\n", os.str());
+ l.clear();
+}
+
+#if 0 // This test requires manual intervention. Normally disabled.
+BOOST_AUTO_TEST_CASE(testSyslogOutput) {
+ Logger& l = clearLogger();
+ l.select(Selector(info));
+ l.syslog("qpid_test");
+ QPID_LOG(info, "Testing QPID");
+ BOOST_ERROR("Manually verify that /var/log/messages contains a recent line 'Testing QPID'");
+}
+#endif // 0
+
+int count() {
+ static int n = 0;
+ return n++;
+}
+
+int loggedCount() {
+ static int n = 0;
+ QPID_LOG(debug, "counting: " << n);
+ return n++;
+}
+
+
+using namespace qpid::sys;
+
+// Measure CPU time.
+clock_t timeLoop(int times, int (*fp)()) {
+ clock_t start=clock();
+ while (times-- > 0)
+ (*fp)();
+ return clock() - start;
+}
+
+// Overhead test disabled because it consumes a ton of CPU and takes
+// forever under valgrind. Not friendly for regular test runs.
+//
+#if 0
+BOOST_AUTO_TEST_CASE(testOverhead) {
+ // Ensure that the ratio of CPU time for an incrementing loop
+ // with and without disabled log statements is in acceptable limits.
+ //
+ int times=100000000;
+ clock_t noLog=timeLoop(times, count);
+ clock_t withLog=timeLoop(times, loggedCount);
+ double ratio=double(withLog)/double(noLog);
+
+ // NB: in initial tests the ratio was consistently below 1.5,
+ // 2.5 is reasonable and should avoid spurios failures
+ // due to machine load.
+ //
+ BOOST_CHECK_SMALL(ratio, 2.5);
+}
+#endif // 0
+
+Statement statement(
+ Level level, const char* file="", int line=0, const char* fn=0)
+{
+ Statement s={0, file, line, fn, level};
+ return s;
+}
+
+
+struct TestOptions : public Options {
+ TestOptions(int argc, char** argv) {
+ qpid::po::options_description desc;
+ addTo(desc);
+ qpid::parseOptions(desc, argc, argv);
+ }
+};
+
+#define ARGC(argv) (sizeof(argv)/sizeof(char*))
+
+BOOST_AUTO_TEST_CASE(testOptionsParse) {
+ char* argv[]={
+ 0,
+ "--log.enable", "error+:foo",
+ "--log.enable", "debug:bar",
+ "--log.enable", "info",
+ "--log.output", "x",
+ "--log.output", "y",
+ "--log.level", "yes",
+ "--log.source", "1",
+ "--log.thread", "true",
+ "--log.function", "YES"
+ };
+ TestOptions opts(ARGC(argv), argv);
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ expect=list_of("x")("y");
+ BOOST_CHECK_EQUAL(expect, opts.outputs);
+ BOOST_CHECK(opts.level);
+ BOOST_CHECK(opts.source);
+ BOOST_CHECK(opts.function);
+ BOOST_CHECK(opts.thread);
+}
+
+BOOST_AUTO_TEST_CASE(testOptionsDefault) {
+ Options opts;
+ vector<string> expect=list_of("stderr");
+ BOOST_CHECK_EQUAL(expect, opts.outputs);
+ expect=list_of("error+");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK(opts.time && opts.level);
+ BOOST_CHECK(!(opts.source || opts.function || opts.thread));
+}
+
+BOOST_AUTO_TEST_CASE(testSelectorFromOptions) {
+ char* argv[]={
+ 0,
+ "--log.enable", "error+:foo",
+ "--log.enable", "debug:bar",
+ "--log.enable", "info"
+ };
+ TestOptions opts(ARGC(argv), argv);
+ vector<string> expect=list_of("error+:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.selectors);
+ Selector s(opts);
+ BOOST_CHECK(!s.isEnabled(warning, "x"));
+ BOOST_CHECK(!s.isEnabled(debug, "x"));
+ BOOST_CHECK(s.isEnabled(debug, "bar"));
+ BOOST_CHECK(s.isEnabled(error, "foo"));
+ BOOST_CHECK(s.isEnabled(critical, "foo"));
+}
+
+BOOST_AUTO_TEST_CASE(testOptionsFormat) {
+ Logger& l = clearLogger();
+ Options opts;
+ BOOST_CHECK_EQUAL(Logger::TIME|Logger::LEVEL, l.format(opts));
+ char* argv[]={
+ 0,
+ "--log.time", "no",
+ "--log.level", "no",
+ "--log.source", "1",
+ "--log.thread", "1"
+ };
+ qpid::po::options_description desc;
+ opts.addTo(desc);
+ qpid::parseOptions(desc, ARGC(argv), argv);
+ BOOST_CHECK_EQUAL(
+ Logger::FILE|Logger::LINE|Logger::THREAD, l.format(opts));
+ opts = Options(); // Clear.
+ char* argv2[]={
+ 0,
+ "--log.level", "no",
+ "--log.thread", "true",
+ "--log.function", "YES",
+ "--log.time", "YES"
+ };
+ qpid::po::options_description desc2;
+ opts.addTo(desc2);
+ qpid::parseOptions(desc2, ARGC(argv2), argv2);
+ BOOST_CHECK_EQUAL(
+ Logger::THREAD|Logger::FUNCTION|Logger::TIME,
+ l.format(opts));
+}
+
+
+BOOST_AUTO_TEST_CASE(testLoggerConfigure) {
+ Logger& l = clearLogger();
+ Options opts;
+ char* argv[]={
+ 0,
+ "--log.time", "no",
+ "--log.source", "yes",
+ "--log.output", "logging.tmp",
+ "--log.enable", "critical"
+ };
+ qpid::po::options_description desc;
+ opts.addTo(desc);
+ qpid::parseOptions(desc, ARGC(argv), argv);
+ l.configure(opts, "test");
+ QPID_LOG(critical, "foo"); int srcline=__LINE__;
+ ifstream log("logging.tmp");
+ string line;
+ getline(log, line);
+ string expect=(format("critical %s:%d: foo")%__FILE__%srcline).str();
+ BOOST_CHECK_EQUAL(expect, line);
+ log.close();
+ unlink("logging.tmp");
+}
diff --git a/cpp/src/tests/unit/test_tools.h b/cpp/src/tests/unit/test_tools.h
new file mode 100644
index 0000000000..a941cf40eb
--- /dev/null
+++ b/cpp/src/tests/unit/test_tools.h
@@ -0,0 +1,53 @@
+#ifndef TEST_TOOLS_H
+#define TEST_TOOLS_H
+
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define BOOST_AUTO_TEST_MAIN // Must come before #include<boost/test/*>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/regex.hpp>
+#include <vector>
+
+/** Stream operator so BOOST_CHECK_EQUALS works on vectors. */
+namespace std {
+template <class T>
+ostream& operator <<(ostream& o, const vector<T>& v) {
+ o << " {";
+ typename vector<T>::const_iterator i = v.begin();
+ if (i != v.end())
+ o << *i++;
+ while (i != v.end())
+ o << ", " << *i++;
+ return o << "}";
+}
+} // namespace std
+
+/** NB: order of parameters is regex first, in line with
+ * CHECK(expected, actual) convention.
+ */
+inline bool regexPredicate(const std::string& re, const std::string& text) {
+ return boost::regex_match(text, boost::regex(re));
+}
+
+/** Check for regular expression match. You must #include <boost/regex.hpp> */
+#define BOOST_CHECK_REGEX(re, text) \
+ BOOST_CHECK_PREDICATE(regexPredicate, (re)(text))
+
+#endif /*!TEST_TOOLS_H*/