[geos-commits] [SCM] geos branch svn-3.6 updated. 17e0d841b5f433037c7f8a00855ea7a97a3bac1f
git at osgeo.org
git at osgeo.org
Thu Apr 6 01:49:30 PDT 2017
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "geos".
The branch, svn-3.6 has been updated
via 17e0d841b5f433037c7f8a00855ea7a97a3bac1f (commit)
from 39c807df6febb7de514614f49fc3dd4c136bb851 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 17e0d841b5f433037c7f8a00855ea7a97a3bac1f
Author: Mateusz Loskot <mateusz at loskot.net>
Date: Thu Apr 6 10:39:27 2017 +0200
Update TUT to latest release 2016-12-19.
Source: https://github.com/mrzechonek/tut-framework/releases/tag/2016-12-19
Fixes #639
Fixes #804
diff --git a/tests/unit/tut/tut.hpp b/tests/unit/tut/tut.hpp
index 617aa22..4679ab8 100644
--- a/tests/unit/tut/tut.hpp
+++ b/tests/unit/tut/tut.hpp
@@ -1,6 +1,9 @@
#ifndef TUT_H_GUARD
#define TUT_H_GUARD
+#include <tut/tut_config.hpp>
+#undef public
+#undef private
#include <iostream>
#include <map>
#include <vector>
@@ -9,11 +12,6 @@
#include <sstream>
#include <iterator>
#include <algorithm>
-#include <typeinfo>
-
-#if defined(linux)
-#define TUT_USE_POSIX
-#endif
#include "tut_exception.hpp"
#include "tut_result.hpp"
@@ -35,6 +33,9 @@
namespace tut
{
+template <class, int>
+class test_group;
+
/**
* Test object. Contains data test run upon and default test method
* implementation. Inherited from Data to allow tests to
@@ -43,12 +44,29 @@ namespace tut
template <class Data>
class test_object : public Data, public test_object_posix
{
+ template<class D, int M>
+ friend class test_group;
+
+ void set_test_group(const char *group)
+ {
+ current_test_group_ = group;
+ }
+
+ void set_test_id(int current_test_id)
+ {
+ current_test_id_ = current_test_id;
+ }
+
public:
/**
* Default constructor
*/
test_object()
+ : called_method_was_a_dummy_test_(false),
+ current_test_id_(0),
+ current_test_name_(),
+ current_test_group_()
{
}
@@ -62,9 +80,9 @@ public:
return current_test_name_;
}
- void set_test_id(int current_test_id)
+ const std::string& get_test_group() const
{
- current_test_id_ = current_test_id;
+ return current_test_group_;
}
int get_test_id() const
@@ -86,16 +104,17 @@ public:
* Used to detect usused test numbers and avoid unnecessary
* test object creation which may be time-consuming depending
* on operations described in Data::Data() and Data::~Data().
- * TODO: replace with throwing special exception from default test.
*/
bool called_method_was_a_dummy_test_;
+ virtual ~test_object()
+ {
+ }
+
private:
int current_test_id_;
std::string current_test_name_;
-
- test_object(test_object const&); // = delete
- test_object& operator=(test_object const&); // = delete
+ std::string current_test_group_;
};
@@ -129,6 +148,9 @@ struct tests_registerer<Test, Group, 0>
template <class Data, int MaxTestsInGroup = 50>
class test_group : public group_base, public test_group_posix
{
+ test_group(const test_group&);
+ void operator=(const test_group&);
+
const char* name_;
typedef void (test_object<Data>::*testmethod)();
@@ -142,13 +164,15 @@ class test_group : public group_base, public test_group_posix
tests tests_;
tests_iterator current_test_;
- enum seh_result
- {
- SEH_OK,
- SEH_CTOR,
- SEH_TEST,
- SEH_DUMMY
- };
+ enum seh_result
+ {
+ SEH_OK,
+#if defined(TUT_USE_SEH)
+ SEH_CTOR,
+ SEH_TEST,
+#endif
+ SEH_DUMMY
+ };
/**
* Exception-in-destructor-safe smart-pointer class.
@@ -204,11 +228,16 @@ class test_group : public group_base, public test_group_posix
{
try
{
+#if defined(TUT_USE_SEH)
if (delete_obj() == false)
{
throw warning("destructor of test object raised"
" an SEH exception");
}
+#else
+ bool d = delete_obj();
+ assert(d && "delete failed with SEH disabled: runtime bug?");
+#endif
}
catch (const std::exception& ex)
{
@@ -271,7 +300,9 @@ public:
* Creates and registers test group with specified name.
*/
test_group(const char* name)
- : name_(name)
+ : name_(name),
+ tests_(),
+ current_test_()
{
// register itself
runner.get().register_group(name_,this);
@@ -284,7 +315,9 @@ public:
* This constructor is used in self-test run only.
*/
test_group(const char* name, test_runner& another_runner)
- : name_(name)
+ : name_(name),
+ tests_(),
+ current_test_()
{
// register itself
another_runner.register_group(name_, this);
@@ -370,22 +403,23 @@ public:
try
{
switch (run_test_seh_(ti->second, obj, current_test_name, ti->first))
- {
- case SEH_CTOR:
- throw bad_ctor("seh");
- break;
-
- case SEH_TEST:
- throw seh("seh");
- break;
-
- case SEH_DUMMY:
- tr.result = test_result::dummy;
- break;
-
- case SEH_OK:
- // ok
- break;
+ {
+#if defined(TUT_USE_SEH)
+ case SEH_CTOR:
+ throw bad_ctor("seh");
+ break;
+
+ case SEH_TEST:
+ throw seh("seh");
+ break;
+#endif
+ case SEH_DUMMY:
+ tr.result = test_result::dummy;
+ break;
+
+ case SEH_OK:
+ // ok
+ break;
}
}
catch (const rethrown& ex)
@@ -396,13 +430,13 @@ public:
catch (const tut_error& ex)
{
tr.result = ex.result();
- tr.exception_typeid = typeid(ex).name();
+ tr.exception_typeid = ex.type();
tr.message = ex.what();
}
catch (const std::exception& ex)
{
tr.result = test_result::ex;
- tr.exception_typeid = typeid(ex).name();
+ tr.exception_typeid = type_name(ex);
tr.message = ex.what();
}
catch (...)
@@ -436,12 +470,12 @@ public:
__try
{
#endif
- if (obj.get() == 0)
- {
- reset_holder_(obj);
- }
+ if (obj.get() == 0)
+ {
+ reset_holder_(obj);
+ }
- obj->called_method_was_a_dummy_test_ = false;
+ obj->called_method_was_a_dummy_test_ = false;
#if defined(TUT_USE_SEH)
@@ -449,6 +483,7 @@ public:
{
#endif
obj.get()->set_test_id(current_test_id);
+ obj.get()->set_test_group(name_);
(obj.get()->*tm)();
#if defined(TUT_USE_SEH)
}
@@ -459,20 +494,20 @@ public:
}
#endif
- if (obj->called_method_was_a_dummy_test_)
- {
- // do not call obj.release(); reuse object
- return SEH_DUMMY;
- }
+ if (obj->called_method_was_a_dummy_test_)
+ {
+ // do not call obj.release(); reuse object
+ return SEH_DUMMY;
+ }
- current_test_name = obj->get_test_name();
- obj.permit_throw();
- obj.release();
+ current_test_name = obj->get_test_name();
+ obj.permit_throw();
+ obj.release();
#if defined(TUT_USE_SEH)
}
__except(handle_seh_(::GetExceptionCode()))
{
- return SEH_CTOR;
+ return SEH_CTOR;
}
#endif
return SEH_OK;
@@ -534,5 +569,5 @@ inline int handle_seh_(DWORD excode)
#endif
}
-#endif
+#endif // TUT_H_GUARD
diff --git a/tests/unit/tut/tut_assert.hpp b/tests/unit/tut/tut_assert.hpp
index 7c4b38a..eb8b2db 100644
--- a/tests/unit/tut/tut_assert.hpp
+++ b/tests/unit/tut/tut_assert.hpp
@@ -1,29 +1,34 @@
#ifndef TUT_ASSERT_H_GUARD
#define TUT_ASSERT_H_GUARD
+#include <tut/tut_config.hpp>
-#include "tut_exception.hpp"
#include <limits>
#include <iomanip>
+#include <iterator>
+#include <cassert>
+#include <cmath>
#if defined(TUT_USE_POSIX)
#include <errno.h>
#include <cstring>
#endif
+#include "tut_exception.hpp"
+
namespace tut
{
namespace detail
{
template<typename M>
- std::ostream &msg_prefix(std::ostream &str, const M &msg)
+ std::ostringstream &msg_prefix(std::ostringstream &str, const M &msg)
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << msg;
if(!ss.str().empty())
{
- str << ss.rdbuf() << ": ";
+ str << msg << ": ";
}
return str;
@@ -83,7 +88,7 @@ void ensure_not(const M& msg, bool cond)
* Tests two objects for being equal.
* Throws if false.
*
- * NB: both T and Q must have operator << defined somewhere, or
+ * NB: both LHS and RHS must have operator << defined somewhere, or
* client code will not compile at all!
*/
template <typename M, typename LHS, typename RHS>
@@ -91,42 +96,128 @@ void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
{
if (expected != actual)
{
- std::stringstream ss;
+ std::ostringstream ss;
detail::msg_prefix(ss,msg)
- << "expected '"
+ << "expected `"
<< expected
- << "' actual '"
+ << "` actual `"
<< actual
- << '\'';
+ << "`";
throw failure(ss.str());
}
}
-template <typename LHS, typename RHS>
-void ensure_equals(const LHS& actual, const RHS& expected)
+/**
+ * Tests two pointers for being equal.
+ * Throws if false.
+ *
+ * NB: both T and Q must have operator << defined somewhere, or
+ * client code will not compile at all!
+ */
+template <typename M, typename LHS, typename RHS>
+void ensure_equals(const M& msg, const LHS * const actual, const RHS * const expected)
{
- ensure_equals("Values are not equal", actual, expected);
+ if (expected != actual)
+ {
+ std::ostringstream ss;
+ detail::msg_prefix(ss,msg)
+ << "expected `"
+ << (void*)expected
+ << "` actual `"
+ << (void*)actual
+ << "`";
+ throw failure(ss.str());
+ }
}
template<typename M>
-void ensure_equals(const M& msg, const double& actual, const double& expected,
- const double& epsilon = std::numeric_limits<double>::epsilon())
+void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon)
{
const double diff = actual - expected;
- if ( !((diff <= epsilon) && (diff >= -epsilon )) )
+ if ( (actual != expected) && !((diff <= epsilon) && (diff >= -epsilon )) )
{
- std::stringstream ss;
+ std::ostringstream ss;
detail::msg_prefix(ss,msg)
<< std::scientific
<< std::showpoint
<< std::setprecision(16)
- << "expected " << expected
- << " actual " << actual
- << " with precision " << epsilon;
+ << "expected `" << expected
+ << "` actual `" << actual
+ << "` with precision `" << epsilon << "`";
throw failure(ss.str());
}
}
+
+template<typename M>
+void ensure_equals(const M& msg, const double& actual, const double& expected)
+{
+ ensure_equals(msg, actual, expected, std::numeric_limits<double>::epsilon());
+}
+
+template <typename LHS, typename RHS>
+void ensure_equals(const LHS& actual, const RHS& expected)
+{
+ ensure_equals("Values are not equal", actual, expected);
+}
+
+
+template<typename LhsIterator, typename RhsIterator>
+void ensure_equals(const std::string &msg,
+ const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
+ const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
+{
+ typename std::iterator_traits<LhsIterator>::difference_type lhs_size = std::distance(lhs_begin, lhs_end);
+ typename std::iterator_traits<RhsIterator>::difference_type rhs_size = std::distance(rhs_begin, rhs_end);
+
+ if(lhs_size < rhs_size)
+ {
+ ensure_equals(msg + ": range is too short", lhs_size, rhs_size);
+ }
+
+ if(lhs_size > rhs_size)
+ {
+ ensure_equals(msg + ": range is too long", lhs_size, rhs_size);
+ }
+
+ assert(lhs_size == rhs_size);
+
+ LhsIterator lhs_i = lhs_begin;
+ RhsIterator rhs_i = rhs_begin;
+ while( (lhs_i != lhs_end) && (rhs_i != rhs_end) )
+ {
+ if(*lhs_i != *rhs_i)
+ {
+ std::ostringstream ss;
+ detail::msg_prefix(ss,msg)
+ << "expected `" << *rhs_i
+ << "` actual `" << *lhs_i
+ << "` at offset " << std::distance(lhs_begin, lhs_i);
+ throw failure(ss.str());
+ }
+
+ lhs_i++;
+ rhs_i++;
+ }
+
+ assert(lhs_i == lhs_end);
+ assert(rhs_i == rhs_end);
+}
+
+template<typename LhsIterator, typename RhsIterator>
+void ensure_equals(const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
+ const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
+{
+ ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
+}
+
+template<typename LhsType, typename RhsType>
+void ensure_equals(const LhsType *lhs_begin, const LhsType *lhs_end,
+ const RhsType *rhs_begin, const RhsType *rhs_end)
+{
+ ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
+}
+
/**
* Tests two objects for being at most in given distance one from another.
* Borders are excluded.
@@ -143,15 +234,15 @@ void ensure_distance(const M& msg, const T& actual, const T& expected, const T&
{
if (expected-distance >= actual || expected+distance <= actual)
{
- std::stringstream ss;
+ std::ostringstream ss;
detail::msg_prefix(ss,msg)
- << " expected ("
+ << " expected `"
<< expected-distance
- << " - "
+ << "` - `"
<< expected+distance
- << ") actual '"
+ << "` actual `"
<< actual
- << '\'';
+ << "`";
throw failure(ss.str());
}
}
@@ -169,7 +260,7 @@ void ensure_errno(const M& msg, bool cond)
{
#if defined(TUT_USE_POSIX)
char e[512];
- std::stringstream ss;
+ std::ostringstream ss;
detail::msg_prefix(ss,msg)
<< strerror_r(errno, e, sizeof(e));
throw failure(ss.str());
@@ -193,6 +284,20 @@ void fail(const M& msg)
throw failure(msg);
}
+/**
+ * Mark test case as known failure and skip execution.
+ */
+static inline void skip(const char* msg = "")
+{
+ throw skipped(msg);
+}
+
+template<typename M>
+void skip(const M& msg)
+{
+ throw skipped(msg);
+}
+
} // end of namespace
}
diff --git a/tests/unit/tut/tut_config.hpp b/tests/unit/tut/tut_config.hpp
new file mode 100644
index 0000000..d698c1c
--- /dev/null
+++ b/tests/unit/tut/tut_config.hpp
@@ -0,0 +1,6 @@
+#ifndef TUT_CONFIG_H_GUARD
+#define TUT_CONFIG_H_GUARD
+
+#define TUT_USE_RTTI 1
+
+#endif
diff --git a/tests/unit/tut/tut_console_reporter.hpp b/tests/unit/tut/tut_console_reporter.hpp
index cd317ce..614e1f2 100644
--- a/tests/unit/tut/tut_console_reporter.hpp
+++ b/tests/unit/tut/tut_console_reporter.hpp
@@ -1,9 +1,14 @@
#ifndef TUT_CONSOLE_REPORTER
#define TUT_CONSOLE_REPORTER
-
-#include <tut.hpp>
+#include <tut/tut.hpp>
#include <cassert>
+#if defined(TUT_USE_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+
/**
* Template Unit Tests Framework for C++.
* http://tut.dozen.ru
@@ -17,29 +22,32 @@ std::ostream& operator<<(std::ostream& os, const tut::test_result& tr)
{
switch(tr.result)
{
- case tut::test_result::ok:
- os << '.';
- break;
- case tut::test_result::fail:
- os << '[' << tr.test << "=F]";
- break;
- case tut::test_result::ex_ctor:
- os << '[' << tr.test << "=C]";
- break;
- case tut::test_result::ex:
- os << '[' << tr.test << "=X]";
- break;
- case tut::test_result::warn:
- os << '[' << tr.test << "=W]";
- break;
- case tut::test_result::term:
- os << '[' << tr.test << "=T]";
- break;
- case tut::test_result::rethrown:
- os << '[' << tr.test << "=P]";
- break;
- case tut::test_result::dummy:
- assert(!"Should never be called");
+ case tut::test_result::ok:
+ os << '.';
+ break;
+ case tut::test_result::fail:
+ os << '[' << tr.test << "=F]";
+ break;
+ case tut::test_result::ex_ctor:
+ os << '[' << tr.test << "=C]";
+ break;
+ case tut::test_result::ex:
+ os << '[' << tr.test << "=X]";
+ break;
+ case tut::test_result::warn:
+ os << '[' << tr.test << "=W]";
+ break;
+ case tut::test_result::term:
+ os << '[' << tr.test << "=T]";
+ break;
+ case tut::test_result::rethrown:
+ os << '[' << tr.test << "=P]";
+ break;
+ case tut::test_result::skipped:
+ os << '[' << tr.test << "=S]";
+ break;
+ case tut::test_result::dummy:
+ throw tut::tut_error("console reporter called for dummy test result");
}
return os;
@@ -60,6 +68,8 @@ class console_reporter : public tut::callback
not_passed_list not_passed;
std::ostream& os;
+ console_reporter(const console_reporter &);
+ console_reporter &operator=(const console_reporter &);
public:
int ok_count;
@@ -67,15 +77,33 @@ public:
int failures_count;
int terminations_count;
int warnings_count;
+ int skipped_count;
console_reporter()
- : os(std::cout)
+ : current_group(),
+ not_passed(),
+ os(std::cout),
+ ok_count(0),
+ exceptions_count(0),
+ failures_count(0),
+ terminations_count(0),
+ warnings_count(0),
+ skipped_count(0)
{
init();
}
console_reporter(std::ostream& out)
- : os(out)
+ : current_group(),
+ not_passed(),
+ os(out),
+ ok_count(0),
+ exceptions_count(0),
+ failures_count(0),
+ terminations_count(0),
+ warnings_count(0),
+ skipped_count(0)
+
{
init();
}
@@ -114,11 +142,15 @@ public:
case test_result::term:
terminations_count++;
break;
+ case test_result::skipped:
+ skipped_count++;
+ break;
case tut::test_result::dummy:
- assert(!"Should never be called");
+ assert( (tr.result != tut::test_result::dummy) && "Should never be called");
} // switch
- if (tr.result != tut::test_result::ok)
+ if ( (tr.result != tut::test_result::ok) &&
+ (tr.result != tut::test_result::skipped) )
{
not_passed.push_back(tr);
}
@@ -181,12 +213,12 @@ public:
{
if (tr.result == test_result::fail)
{
- os << " failed assertion: \"" << tr.message << "\""
+ os << " failed assertion: `" << tr.message << "`"
<< std::endl;
}
else
{
- os << " message: \"" << tr.message << "\""
+ os << " message: `" << tr.message << "`"
<< std::endl;
}
}
@@ -214,11 +246,17 @@ public:
{
os << " warnings:" << warnings_count;
}
+
os << " ok:" << ok_count;
+
+ if(skipped_count > 0)
+ {
+ os << " skipped:" << skipped_count;
+ }
os << std::endl;
}
- bool all_ok() const
+ virtual bool all_ok() const
{
return not_passed.empty();
}
@@ -232,6 +270,7 @@ private:
failures_count = 0;
terminations_count = 0;
warnings_count = 0;
+ skipped_count = 0;
not_passed.clear();
}
};
diff --git a/tests/unit/tut/tut_cppunit_reporter.hpp b/tests/unit/tut/tut_cppunit_reporter.hpp
new file mode 100644
index 0000000..25d3adb
--- /dev/null
+++ b/tests/unit/tut/tut_cppunit_reporter.hpp
@@ -0,0 +1,218 @@
+
+#ifndef TUT_CPPUNIT_REPORTER
+#define TUT_CPPUNIT_REPORTER
+
+#include <tut/tut.hpp>
+#include <string>
+#include <fstream>
+#include <vector>
+#include <stdexcept>
+#include <memory>
+
+namespace tut
+{
+
+/**
+ * CppUnit TUT reporter
+ */
+class cppunit_reporter : public tut::callback
+{
+ std::vector<tut::test_result> failed_tests_;
+ std::vector<tut::test_result> passed_tests_;
+ const std::string filename_;
+ TUT_UNIQUE_PTR<std::ostream> stream_;
+
+
+ cppunit_reporter(const cppunit_reporter &);
+ cppunit_reporter &operator=(const cppunit_reporter &);
+
+public:
+ explicit cppunit_reporter(const std::string &filename = "testResult.xml")
+ : failed_tests_(),
+ passed_tests_(),
+ filename_(filename),
+ stream_(new std::ofstream(filename_.c_str()))
+ {
+ if (!stream_->good()) {
+ throw tut_error("Cannot open output file `" + filename_ + "`");
+ }
+ }
+
+ explicit cppunit_reporter(std::ostream &stream)
+ : failed_tests_(),
+ passed_tests_(),
+ filename_(),
+ stream_(&stream)
+ {
+ }
+
+ ~cppunit_reporter()
+ {
+ if(filename_.empty())
+ {
+ stream_.release();
+ }
+ }
+
+ void run_started()
+ {
+ failed_tests_.clear();
+ passed_tests_.clear();
+ }
+
+ void test_completed(const tut::test_result& tr)
+ {
+ assert(tr.result != test_result::dummy );
+ if ( (tr.result == test_result::ok) ||
+ (tr.result == test_result::skipped) )
+ {
+ passed_tests_.push_back(tr);
+ }
+ else
+ {
+ failed_tests_.push_back(tr);
+ }
+ }
+
+ void run_completed()
+ {
+ int errors = 0;
+ int failures = 0;
+ std::string failure_type;
+ std::string failure_msg;
+
+ *stream_ << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>" << std::endl
+ << "<TestRun>" << std::endl;
+
+ if (failed_tests_.size() > 0)
+ {
+ *stream_ << " <FailedTests>" << std::endl;
+
+ for (unsigned int i=0; i<failed_tests_.size(); i++)
+ {
+ switch (failed_tests_[i].result)
+ {
+ case test_result::fail:
+ failure_type = "Assertion";
+ failure_msg = "";
+ failures++;
+ break;
+ case test_result::ex:
+ failure_type = "Assertion";
+ failure_msg = "Thrown exception: " + failed_tests_[i].exception_typeid + '\n';
+ failures++;
+ break;
+ case test_result::warn:
+ failure_type = "Assertion";
+ failure_msg = "Destructor failed\n";
+ failures++;
+ break;
+ case test_result::term:
+ failure_type = "Error";
+ failure_msg = "Test application terminated abnormally\n";
+ errors++;
+ break;
+ case test_result::ex_ctor:
+ failure_type = "Error";
+ failure_msg = "Constructor has thrown an exception: " + failed_tests_[i].exception_typeid + '\n';
+ errors++;
+ break;
+ case test_result::rethrown:
+ failure_type = "Assertion";
+ failure_msg = "Child failed\n";
+ failures++;
+ break;
+ default: // ok, skipped, dummy
+ failure_type = "Error";
+ failure_msg = "Unknown test status, this should have never happened. "
+ "You may just have found a bug in TUT, please report it immediately.\n";
+ errors++;
+ break;
+ }
+
+ *stream_ << " <FailedTest id=\"" << failed_tests_[i].test << "\">" << std::endl
+ << " <Name>" << encode(failed_tests_[i].group) + "::" + encode(failed_tests_[i].name) << "</Name>" << std::endl
+ << " <FailureType>" << failure_type << "</FailureType>" << std::endl
+ << " <Location>" << std::endl
+ << " <File>Unknown</File>" << std::endl
+ << " <Line>Unknown</Line>" << std::endl
+ << " </Location>" << std::endl
+ << " <Message>" << encode(failure_msg + failed_tests_[i].message) << "</Message>" << std::endl
+ << " </FailedTest>" << std::endl;
+ }
+
+ *stream_ << " </FailedTests>" << std::endl;
+ }
+
+ /* *********************** passed tests ***************************** */
+ if (passed_tests_.size() > 0) {
+ *stream_ << " <SuccessfulTests>" << std::endl;
+
+ for (unsigned int i=0; i<passed_tests_.size(); i++)
+ {
+ *stream_ << " <Test id=\"" << passed_tests_[i].test << "\">" << std::endl
+ << " <Name>" << encode(passed_tests_[i].group) + "::" + encode(passed_tests_[i].name) << "</Name>" << std::endl
+ << " </Test>" << std::endl;
+ }
+
+ *stream_ << " </SuccessfulTests>" << std::endl;
+ }
+
+ /* *********************** statistics ***************************** */
+ *stream_ << " <Statistics>" << std::endl
+ << " <Tests>" << (failed_tests_.size() + passed_tests_.size()) << "</Tests>" << std::endl
+ << " <FailuresTotal>" << failed_tests_.size() << "</FailuresTotal>" << std::endl
+ << " <Errors>" << errors << "</Errors>" << std::endl
+ << " <Failures>" << failures << "</Failures>" << std::endl
+ << " </Statistics>" << std::endl;
+
+ /* *********************** footer ***************************** */
+ *stream_ << "</TestRun>" << std::endl;
+ }
+
+ virtual bool all_ok() const
+ {
+ return failed_tests_.empty();
+ }
+
+ /**
+ * \brief Encodes text to XML
+ * XML-reserved characters (e.g. "<") are encoded according to specification
+ * @param text text to be encoded
+ * @return encoded string
+ */
+ static std::string encode(const std::string & text)
+ {
+ std::string out;
+
+ for (unsigned int i=0; i<text.length(); ++i) {
+ char c = text[i];
+ switch (c) {
+ case '<':
+ out += "<";
+ break;
+ case '>':
+ out += ">";
+ break;
+ case '&':
+ out += "&";
+ break;
+ case '\'':
+ out += "'";
+ break;
+ case '"':
+ out += """;
+ break;
+ default:
+ out += c;
+ }
+ }
+
+ return out;
+ }
+};
+
+}
+
+#endif
+
diff --git a/tests/unit/tut/tut_exception.hpp b/tests/unit/tut/tut_exception.hpp
index 2858ac7..1ebea34 100644
--- a/tests/unit/tut/tut_exception.hpp
+++ b/tests/unit/tut/tut_exception.hpp
@@ -12,7 +12,7 @@ namespace tut
*/
struct tut_error : public std::exception
{
- tut_error(const std::string& msg)
+ explicit tut_error(const std::string& msg)
: err_msg(msg)
{
}
@@ -22,6 +22,11 @@ struct tut_error : public std::exception
return test_result::ex;
}
+ virtual std::string type() const
+ {
+ return "tut::tut_error";
+ }
+
const char* what() const throw()
{
return err_msg.c_str();
@@ -32,8 +37,9 @@ struct tut_error : public std::exception
}
private:
- tut_error& operator=(const tut_error&);
- std::string err_msg;
+ void operator=(const tut_error &);
+
+ const std::string err_msg;
};
/**
@@ -41,23 +47,48 @@ private:
*/
struct no_such_group : public tut_error
{
- no_such_group(const std::string& grp)
+ explicit no_such_group(const std::string& grp)
: tut_error(grp)
{
}
+ virtual std::string type() const
+ {
+ return "tut::no_such_group";
+ }
+
~no_such_group() throw()
{
}
};
/**
+ * Test not found exception.
+ */
+struct no_such_test : public tut_error
+{
+ explicit no_such_test(const std::string& grp)
+ : tut_error(grp)
+ {
+ }
+
+ virtual std::string type() const
+ {
+ return "tut::no_such_test";
+ }
+
+ ~no_such_test() throw()
+ {
+ }
+};
+
+/**
* Internal exception to be throwed when
* test constructor has failed.
*/
struct bad_ctor : public tut_error
{
- bad_ctor(const std::string& msg)
+ explicit bad_ctor(const std::string& msg)
: tut_error(msg)
{
}
@@ -67,6 +98,11 @@ struct bad_ctor : public tut_error
return test_result::ex_ctor;
}
+ virtual std::string type() const
+ {
+ return "tut::bad_ctor";
+ }
+
~bad_ctor() throw()
{
}
@@ -77,7 +113,7 @@ struct bad_ctor : public tut_error
*/
struct failure : public tut_error
{
- failure(const std::string& msg)
+ explicit failure(const std::string& msg)
: tut_error(msg)
{
}
@@ -87,6 +123,11 @@ struct failure : public tut_error
return test_result::fail;
}
+ virtual std::string type() const
+ {
+ return "tut::failure";
+ }
+
~failure() throw()
{
}
@@ -97,7 +138,7 @@ struct failure : public tut_error
*/
struct warning : public tut_error
{
- warning(const std::string& msg)
+ explicit warning(const std::string& msg)
: tut_error(msg)
{
}
@@ -107,6 +148,11 @@ struct warning : public tut_error
return test_result::warn;
}
+ virtual std::string type() const
+ {
+ return "tut::warning";
+ }
+
~warning() throw()
{
}
@@ -117,7 +163,7 @@ struct warning : public tut_error
*/
struct seh : public tut_error
{
- seh(const std::string& msg)
+ explicit seh(const std::string& msg)
: tut_error(msg)
{
}
@@ -127,6 +173,11 @@ struct seh : public tut_error
return test_result::term;
}
+ virtual std::string type() const
+ {
+ return "tut::seh";
+ }
+
~seh() throw()
{
}
@@ -147,6 +198,11 @@ struct rethrown : public failure
return test_result::rethrown;
}
+ virtual std::string type() const
+ {
+ return "tut::rethrown";
+ }
+
~rethrown() throw()
{
}
@@ -154,6 +210,28 @@ struct rethrown : public failure
const test_result tr;
};
+struct skipped : public tut_error
+{
+ explicit skipped(const std::string& msg)
+ : tut_error(msg)
+ {
+ }
+
+ virtual test_result::result_type result() const
+ {
+ return test_result::skipped;
+ }
+
+ virtual std::string type() const
+ {
+ return "tut::skipped";
+ }
+
+ ~skipped() throw()
+ {
+ }
+};
+
}
#endif
diff --git a/tests/unit/tut/tut_fpt.hpp b/tests/unit/tut/tut_fpt.hpp
new file mode 100644
index 0000000..393cf1a
--- /dev/null
+++ b/tests/unit/tut/tut_fpt.hpp
@@ -0,0 +1,181 @@
+/**
+ * @brief Additional ensures for scientific/engineering applications.
+ * @author Joerg <yogi2005 at users.sourceforge.net>
+ * @date 07/04/2008
+ */
+#ifndef TUT_Float_H_GUARD
+#define TUT_Float_H_GUARD
+
+#include <limits>
+#include <iostream>
+
+namespace tut
+{
+ namespace detail
+ {
+ template<bool Predicate, typename Then, typename Else>
+ struct If
+ {
+ typedef Else type;
+ };
+
+ template<typename Then, typename Else>
+ struct If<true,Then,Else>
+ {
+ typedef Then type;
+ };
+
+ template<typename T>
+ struct fpt_traits
+ {
+ struct StdNumericLimitsNotAvailable {};
+ static const StdNumericLimitsNotAvailable static_check[ std::numeric_limits<T>::is_specialized ];
+
+ static const T zero;
+
+ typedef typename If<std::numeric_limits<T>::is_integer,
+ double,
+ T>::type Result;
+
+ static T abs(const T &arg)
+ {
+ if(arg < zero)
+ return zero - arg;
+ else
+ return arg;
+ }
+
+ static T sig(const T &arg)
+ {
+ if(arg < zero)
+ return -1;
+ else
+ return 1;
+ }
+
+ static inline Result div(const Result &number, const T &divisor)
+ {
+ static_cast<void>(static_check);
+
+ if(number == zero && divisor == zero)
+ return std::numeric_limits<Result>::quiet_NaN();
+
+ if(number == zero)
+ return zero;
+
+ if(divisor == zero)
+ return sig(number) * std::numeric_limits<Result>::infinity();
+
+ assert(zero < number);
+ assert(zero < divisor);
+
+ // Avoid underflow
+ if(static_cast<T>(1) < abs(divisor))
+ {
+ // number / divisor < min <=> number < min * divisor
+ if( abs(number) < abs(divisor) * std::numeric_limits<T>::min())
+ {
+ return sig(divisor) * sig(number) * std::numeric_limits<T>::min();
+ }
+ }
+
+ // Avoid overflow
+ if( abs(divisor) < static_cast<T>(1))
+ {
+ // number / divisor > max <=> number > max * divisor
+ if( abs(divisor) * std::numeric_limits<T>::max() < abs(number))
+ {
+ return sig(divisor) * sig(number) * std::numeric_limits<T>::max();
+ }
+ }
+
+ return number / divisor;
+ }
+ };
+
+ template<typename T>
+ const typename fpt_traits<T>::StdNumericLimitsNotAvailable
+ fpt_traits<T>::static_check[ std::numeric_limits<T>::is_specialized ] = { {} };
+
+ template<typename T>
+ const T fpt_traits<T>::zero = static_cast<T>(0);
+
+ template<typename T, typename U>
+ bool check_tolerance(T actual, T expected, U fraction)
+ {
+ typename fpt_traits<T>::Result diff = fpt_traits<T>::div( fpt_traits<T>::abs( expected - actual ),
+ fpt_traits<T>::abs( expected ) );
+
+ return (diff == fraction) || (diff < fraction);
+ }
+
+ } // namespace detail
+
+ template<typename T, typename U>
+ void ensure_close(const char* msg, const T& actual, const T& expected, const U& tolerance )
+ {
+ typedef detail::fpt_traits<U> Traits;
+
+ typename Traits::Result fraction = Traits::div( Traits::abs(static_cast<typename Traits::Result>(tolerance)),
+ static_cast<typename Traits::Result>(100) );
+ if( !detail::check_tolerance(actual, expected, fraction) )
+ {
+ std::ostringstream ss;
+ ss << ( msg ? msg : "" )
+ << ( msg ? ": " : "" )
+ << "expected `"
+ << expected
+ << "` and actual `"
+ << actual
+ << "` differ more than "
+ << tolerance
+ << "%";
+ throw failure( ss.str().c_str() );
+ }
+ }
+
+ template<typename T, typename Tolerance>
+ void ensure_close(const T& actual, const T& expected, const Tolerance& tolerance )
+ {
+ ensure_close( 0, actual, expected, tolerance );
+ }
+
+ template<typename T, typename U>
+ void ensure_close_fraction(const char* msg, const T& actual, const T& expected, const U& fraction)
+ {
+ typedef char StdNumericLimitsNotAvailable;
+ const StdNumericLimitsNotAvailable static_check[ std::numeric_limits<U>::is_specialized ] = { 0 };
+ static_cast<void>(static_check);
+
+ if( !detail::check_tolerance(actual, expected, fraction) )
+ {
+ std::ostringstream ss;
+ ss << ( msg ? msg : "" )
+ << ( msg ? ": " : "" )
+ << "expected `"
+ << expected
+ << "` and actual `"
+ << actual
+ << "` differ more than fraction `"
+ << fraction
+ << "`";
+ throw failure( ss.str().c_str() );
+ }
+ }
+
+ template<typename T>
+ void ensure_close_fraction( const char* msg, const T& actual, const T& expected, const int& tolerance )
+ {
+ ensure_close(msg, actual, expected, double(tolerance));
+ }
+
+ template< typename T, typename Tolerance>
+ void ensure_close_fraction(const T& actual, const T& expected, const Tolerance& fraction)
+ {
+ ensure_close_fraction( 0, actual, expected, fraction );
+ }
+
+} // namespace tut
+
+#endif
+
diff --git a/tests/unit/tut/tut_macros.hpp b/tests/unit/tut/tut_macros.hpp
new file mode 100644
index 0000000..fa106fb
--- /dev/null
+++ b/tests/unit/tut/tut_macros.hpp
@@ -0,0 +1,71 @@
+#ifndef TUT_MACROS_HPP
+#define TUT_MACROS_HPP
+
+#include <tut/tut.hpp>
+
+#ifdef ensure_THROW
+#error ensure_THROW macro is already defined
+#endif
+
+/** Helper macros to ensure that a call throws exception.
+ * \code
+ * #include <tut_macros.h>
+ * ensure_THROW( this_function_should_throw_bad_alloc(), std::bad_alloc );
+ * \endcode
+ */
+#define ensure_THROW(x, e) \
+do \
+{ \
+ try \
+ { \
+ try \
+ { \
+ x; \
+ } \
+ catch (const e&) \
+ { \
+ break; \
+ } \
+ } \
+ catch (const std::exception& ex) \
+ { \
+ fail(std::string(#x " has thrown unexpected exception ") + \
+ tut::type_name(ex) + ": " + ex.what()); \
+ } \
+ catch (...) \
+ { \
+ fail(#x " has thrown unexpected unknown exception"); \
+ } \
+ fail(#x " has not thrown expected exception " #e); \
+} while (false)
+
+#ifdef ensure_NO_THROW
+#error ensure_NO_THROW macro is already defined
+#endif
+
+/** Helper macro to ensure a call does not throw any exceptions.
+ * \code
+ * #include <tut_macros.h>
+ * ensure_NO_THROW( this_function_should_never_throw() );
+ * \endcode
+ */
+#define ensure_NO_THROW( x ) \
+try \
+{ \
+ x; \
+} \
+catch(const std::exception &ex) \
+{ \
+ fail( std::string(#x " has thrown unexpected exception ")+tut::type_name(ex)+": "+ex.what()); \
+} \
+catch(...) \
+{ \
+ fail(#x " has thrown unexpected unknown exception"); \
+}
+
+#ifdef __COUNTER__
+#define TUT_TESTCASE(object) template<> template<> void object::test<__COUNTER__>()
+#endif
+
+#endif
+
diff --git a/tests/unit/tut/tut_main.hpp b/tests/unit/tut/tut_main.hpp
new file mode 100644
index 0000000..c6955bb
--- /dev/null
+++ b/tests/unit/tut/tut_main.hpp
@@ -0,0 +1,111 @@
+#ifndef TUT_MAIN_H
+#define TUT_MAIN_H
+
+#include <tut/tut.hpp>
+#include <tut/tut_console_reporter.hpp>
+#include <tut/tut_cppunit_reporter.hpp>
+#include <iostream>
+#include <cstring>
+
+namespace tut
+{
+
+/** Helper function to make test binaries simpler.
+ *
+ * Example of basic usage follows.
+ *
+ * @code
+ * namespace tut { test_runner_singleton runner; }
+ *
+ * int main(int argc, char **argv)
+ * {
+ * if( tut_main(argc, argv) )
+ * return 0;
+ * else
+ * return -1;
+ * }
+ * @endcode
+ *
+ * It is also possible to do some generic initialization before
+ * running any tests and cleanup before exiting application.
+ * Note that tut_main can throw tut::no_such_group or tut::no_such_test.
+ *
+ * @code
+ * namespace tut { test_runner_singleton runner; }
+ *
+ * int main(int argc, char **argv)
+ * {
+ * tut::xml_reporter reporter;
+ * tut::runner.get().insert_callback(&reporter);
+ *
+ * MyInit();
+ * try
+ * {
+ * tut_main(argc, argv);
+ * }
+ * catch(const tut::tut_error &ex)
+ * {
+ * std::cerr << "TUT error: " << ex.what() << std::endl;
+ * }
+ * MyCleanup();
+ * }
+ * @endcode
+ */
+inline bool tut_main(int argc, const char * const * const argv, std::ostream &os = std::cerr)
+{
+ std::stringstream usage;
+ usage << "Usage: " << argv[0] << " [group] [testcase]" << std::endl;
+ groupnames gr = runner.get().list_groups();
+ usage << "Available test groups:" << std::endl;
+ for(groupnames::const_iterator i = gr.begin(); i != gr.end(); ++i)
+ {
+ usage << " " << *i << std::endl;
+ }
+
+ if(argc>1)
+ {
+ if(std::string(argv[1]) == "-h" ||
+ std::string(argv[1]) == "--help" ||
+ std::string(argv[1]) == "/?" ||
+ argc > 3)
+ {
+ os << usage.rdbuf();
+ return false;
+ }
+ }
+
+ // Check command line options.
+ switch(argc)
+ {
+ case 1:
+ runner.get().run_tests();
+ break;
+
+ case 2:
+ runner.get().run_tests(argv[1]);
+ break;
+
+ case 3:
+ {
+ char *end;
+ int t = strtol(argv[2], &end, 10);
+ if(end != argv[2] + strlen(argv[2]))
+ {
+ throw no_such_test("`" + std::string(argv[2]) + "` should be a number");
+ }
+
+ test_result tr;
+ if(!runner.get().run_test(argv[1], t, tr) || tr.result == test_result::dummy)
+ {
+ throw no_such_test("No testcase `" + std::string(argv[2]) + "` in group `" + argv[1] + "`");
+ }
+ }
+ break;
+ }
+
+ return true;
+} // tut_main()
+
+}
+
+#endif
diff --git a/tests/unit/tut/tut_posix.hpp b/tests/unit/tut/tut_posix.hpp
index 89a7130..003bc34 100644
--- a/tests/unit/tut/tut_posix.hpp
+++ b/tests/unit/tut/tut_posix.hpp
@@ -1,5 +1,12 @@
#ifndef TUT_FORK_H_GUARD
#define TUT_FORK_H_GUARD
+#include <tut/tut_config.hpp>
+
+#if __cplusplus >= 201103L
+#define TUT_UNIQUE_PTR std::unique_ptr
+#else
+#define TUT_UNIQUE_PTR std::auto_ptr
+#endif
#if defined(TUT_USE_POSIX)
#include <errno.h>
@@ -44,7 +51,7 @@ private:
if(tr.result != test_result::ok)
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << int(tr.result) << "\n"
<< tr.group << "\n"
<< tr.test << "\n"
@@ -57,6 +64,10 @@ private:
ensure_errno("write() failed", w == size);
}
}
+
+ virtual ~test_group_posix()
+ {
+ }
};
template<typename T>
@@ -64,24 +75,36 @@ struct tut_posix
{
pid_t fork()
{
+#ifdef TUT_USE_RTTI
test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
ensure("trying to call 'tut_fork' in ctor of test object", self != NULL);
+#else
+ test_object<T> *self = static_cast< tut::test_object<T>* >(this);
+#endif
return self->fork_();
}
pid_t waitpid(pid_t pid, int *status, int flags = 0)
{
+#ifdef TUT_USE_RTTI
test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
ensure("trying to call 'tut_waitpid' in ctor of test object", self != NULL);
+#else
+ test_object<T> *self = static_cast< tut::test_object<T>* >(this);
+#endif
return self->waitpid_(pid, status, flags);
}
void ensure_child_exit(pid_t pid, int exit_status = 0)
{
+#ifdef TUT_USE_RTTI
test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
ensure("trying to call 'ensure_child_exit' in ctor of test object", self != NULL);
+#else
+ test_object<T> *self = static_cast< tut::test_object<T>* >(this);
+#endif
int status;
self->waitpid_(pid, &status);
@@ -92,8 +115,12 @@ struct tut_posix
void ensure_child_signal(pid_t pid, int signal = SIGTERM)
{
+#ifdef TUT_USE_RTTI
test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
ensure("trying to call 'ensure_child_signal' in ctor of test object", self != NULL);
+#else
+ test_object<T> *self = static_cast< tut::test_object<T>* >(this);
+#endif
int status;
self->waitpid_(pid, &status);
@@ -103,10 +130,12 @@ struct tut_posix
std::set<pid_t> get_pids() const
{
- using namespace std;
-
+#ifdef TUT_USE_RTTI
const test_object<T> *self = dynamic_cast< const tut::test_object<T>* >(this);
ensure("trying to call 'get_pids' in ctor of test object", self != NULL);
+#else
+ const test_object<T> *self = static_cast< const tut::test_object<T>* >(this);
+#endif
return self->get_pids_();
}
@@ -126,7 +155,8 @@ public:
* Default constructor
*/
test_object_posix()
- : pipe_(-1)
+ : pids_(),
+ pipe_(-1)
{
}
@@ -142,7 +172,7 @@ public:
if(!pids_.empty())
{
- std::stringstream ss;
+ std::ostringstream ss;
// in parent, reap children
for(std::map<pid_t, int>::iterator i = pids_.begin(); i != pids_.end(); ++i)
@@ -158,7 +188,11 @@ public:
if(!ss.str().empty())
{
+#if __cplusplus >= 201103L
+ std::cerr << ss.rdbuf() << std::endl;
+#else
fail(ss.str().c_str());
+#endif
}
}
}
@@ -226,7 +260,7 @@ private:
else
{
// cannot kill, we are in trouble
- std::stringstream ss;
+ std::ostringstream ss;
char e[1024];
ss << "child " << pid << " could not be killed with SIGTERM, " << strerror_r(errno, e, sizeof(e)) << std::endl;
fail(ss.str());
@@ -257,7 +291,7 @@ private:
}
else
{
- std::stringstream ss;
+ std::ostringstream ss;
char e[1024];
ss << "child " << pid << " could not be killed with SIGKILL, " << strerror_r(errno, e, sizeof(e)) << std::endl;
fail(ss.str());
@@ -269,7 +303,7 @@ private:
ensure_equals("child process exists after SIGKILL", ::kill(pid, 0), -1);
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child " << pid << " had to be killed with SIGKILL";
fail(ss.str());
}
@@ -361,7 +395,7 @@ private:
{
if(WIFSIGNALED(status))
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child killed by signal " << WTERMSIG(status)
<< ": expected exit with code " << exit_status;
@@ -372,7 +406,7 @@ private:
{
if(WEXITSTATUS(status) != exit_status)
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child exited, expected '"
<< exit_status
<< "' actual '"
@@ -385,7 +419,7 @@ private:
if(WIFSTOPPED(status))
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child stopped by signal " << WTERMSIG(status)
<< ": expected exit with code " << exit_status;
throw failure(ss.str().c_str());
@@ -398,7 +432,7 @@ private:
{
if(WTERMSIG(status) != signal)
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child killed by signal, expected '"
<< signal
<< "' actual '"
@@ -410,7 +444,7 @@ private:
if(WIFEXITED(status))
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child exited with code " << WEXITSTATUS(status)
<< ": expected signal " << signal;
@@ -419,7 +453,7 @@ private:
if(WIFSTOPPED(status))
{
- std::stringstream ss;
+ std::ostringstream ss;
ss << "child stopped by signal " << WTERMSIG(status)
<< ": expected kill by signal " << signal;
@@ -453,6 +487,9 @@ namespace tut
struct test_object_posix
{
+ virtual ~test_object_posix()
+ {
+ }
};
struct test_group_posix
@@ -461,6 +498,10 @@ struct test_group_posix
void send_result_(const T*, const test_result &)
{
}
+
+ virtual ~test_group_posix()
+ {
+ }
};
} // namespace tut
diff --git a/tests/unit/tut/tut_reporter.hpp b/tests/unit/tut/tut_reporter.hpp
index 1da9690..56731d8 100644
--- a/tests/unit/tut/tut_reporter.hpp
+++ b/tests/unit/tut/tut_reporter.hpp
@@ -1,7 +1,7 @@
#ifndef TUT_REPORTER
#define TUT_REPORTER
-#include <tut_console_reporter.hpp>
+#include <tut/tut_console_reporter.hpp>
namespace tut
{
diff --git a/tests/unit/tut/tut_restartable.hpp b/tests/unit/tut/tut_restartable.hpp
index eb6eb00..9f92923 100644
--- a/tests/unit/tut/tut_restartable.hpp
+++ b/tests/unit/tut/tut_restartable.hpp
@@ -186,7 +186,7 @@ bool deserialize(std::istream& is, tut::test_result& tr)
}
return true;
}
-};
+}
/**
* Restartable test runner wrapper.
@@ -207,11 +207,12 @@ public:
*/
restartable_wrapper(const std::string& dir = ".")
: runner_(runner.get()),
- dir_(dir)
+ callbacks_(),
+ dir_(dir),
+ log_( dir + '/' + "log.tut" ),
+ jrn_( dir + '/' + "journal.tut" )
{
// dozen: it works, but it would be better to use system path separator
- jrn_ = dir_ + '/' + "journal.tut";
- log_ = dir_ + '/' + "log.tut";
}
/**
diff --git a/tests/unit/tut/tut_result.hpp b/tests/unit/tut/tut_result.hpp
index 5731802..28a5671 100644
--- a/tests/unit/tut/tut_result.hpp
+++ b/tests/unit/tut/tut_result.hpp
@@ -1,11 +1,47 @@
#ifndef TUT_RESULT_H_GUARD
#define TUT_RESULT_H_GUARD
+#include <tut/tut_config.hpp>
#include <string>
+#if defined(TUT_USE_RTTI)
+#if (defined(_MSC_VER) && !defined(_CPPRTTI)) || (defined(__GNUC__) && !defined(__GXX_RTTI))
+#undef TUT_USE_RTTI
+#endif
+#endif
+
+#if defined(TUT_USE_RTTI)
+#include <typeinfo>
+#endif
+
+#if defined(TUT_USE_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
namespace tut
{
+#if defined(TUT_USE_RTTI)
+template<typename T>
+inline std::string type_name(const T& t)
+{
+ return typeid(t).name();
+}
+#else
+template<typename T>
+inline std::string type_name(const T& t)
+{
+ return "Unknown type, RTTI disabled";
+}
+
+inline std::string type_name(const std::exception&)
+{
+ return "Unknown std::exception, RTTI disabled";
+}
+#endif
+
+
#if defined(TUT_USE_POSIX)
struct test_result_posix
{
@@ -14,11 +50,18 @@ struct test_result_posix
{
}
+ virtual ~test_result_posix()
+ {
+ }
+
pid_t pid;
};
#else
struct test_result_posix
{
+ virtual ~test_result_posix()
+ {
+ }
};
#endif
@@ -46,22 +89,19 @@ struct test_result : public test_result_posix
std::string name;
/**
- * ok - test finished successfully
- * fail - test failed with ensure() or fail() methods
- * ex - test throwed an exceptions
- * warn - test finished successfully, but test destructor throwed
- * term - test forced test application to terminate abnormally
+ * result of a test
*/
enum result_type
{
- ok,
- fail,
- ex,
- warn,
- term,
- ex_ctor,
- rethrown,
- dummy
+ ok, ///< test finished successfully
+ fail, ///< test failed with ensure() or fail() methods
+ ex, ///< test throwed an exceptions
+ warn, ///< test finished successfully, but test destructor throwed
+ term, ///< test forced test application to terminate abnormally
+ ex_ctor, ///<
+ rethrown, ///<
+ skipped, ///<
+ dummy ///<
};
result_type result;
@@ -76,8 +116,12 @@ struct test_result : public test_result_posix
* Default constructor.
*/
test_result()
- : test(0),
- result(ok)
+ : group(),
+ test(0),
+ name(),
+ result(ok),
+ message(),
+ exception_typeid()
{
}
@@ -89,7 +133,9 @@ struct test_result : public test_result_posix
: group(grp),
test(pos),
name(test_name),
- result(res)
+ result(res),
+ message(),
+ exception_typeid()
{
}
@@ -104,7 +150,7 @@ struct test_result : public test_result_posix
name(test_name),
result(res),
message(ex.what()),
- exception_typeid(typeid(ex).name())
+ exception_typeid(type_name(ex))
{
}
@@ -122,6 +168,10 @@ struct test_result : public test_result_posix
exception_typeid(ex_typeid)
{
}
+
+ virtual ~test_result()
+ {
+ }
};
}
diff --git a/tests/unit/tut/tut_runner.hpp b/tests/unit/tut/tut_runner.hpp
index 33ffe42..3803046 100644
--- a/tests/unit/tut/tut_runner.hpp
+++ b/tests/unit/tut/tut_runner.hpp
@@ -62,24 +62,27 @@ struct callback
* Called when a group started
* @param name Name of the group
*/
- virtual void group_started(const std::string& /*name*/)
+ virtual void group_started(const std::string& name)
{
+ (void)name;
}
/**
* Called when a test finished.
* @param tr Test results.
*/
- virtual void test_completed(const test_result& /*tr*/)
+ virtual void test_completed(const test_result& tr)
{
+ (void)tr;
}
/**
* Called when a group is completed
* @param name Name of the group
*/
- virtual void group_completed(const std::string& /*name*/)
+ virtual void group_completed(const std::string& name)
{
+ (void)name;
}
/**
@@ -88,6 +91,11 @@ struct callback
virtual void run_completed()
{
}
+
+ virtual bool all_ok() const
+ {
+ return true;
+ }
private:
callback(const callback &);
void operator=(const callback&);
@@ -111,11 +119,15 @@ public:
* Constructor
*/
test_runner()
+ : groups_(),
+ callbacks_()
{
}
/**
* Stores another group for getting by name.
+ * @param name new group object
+ * @param gr new callback object
*/
void register_group(const std::string& name, group_base* gr)
{
@@ -127,15 +139,16 @@ public:
if (groups_.find(name) != groups_.end())
{
std::string msg("attempt to add already existent group " + name);
- // this exception terminates application so we use cerr also
- // TODO: should this message appear in stream?
- std::cerr << msg << std::endl;
throw tut_error(msg);
}
groups_.insert( std::make_pair(name, gr) );
}
+ /**
+ * Stores one callback object.
+ * @param cb new callback object
+ */
void set_callback(callback *cb)
{
clear_callbacks();
@@ -143,7 +156,8 @@ public:
}
/**
- * Stores callback object.
+ * Add callback object.
+ * @param cb new callback object
*/
void insert_callback(callback* cb)
{
@@ -153,11 +167,18 @@ public:
}
}
+ /**
+ * Remove callback object.
+ * @param cb callback to remove
+ */
void erase_callback(callback* cb)
{
callbacks_.erase(cb);
}
+ /**
+ * Remove all callback objects.
+ */
void clear_callbacks()
{
callbacks_.clear();
@@ -165,12 +186,17 @@ public:
/**
* Returns callback list.
+ * @return callback list
*/
const callbacks &get_callbacks() const
{
return callbacks_;
}
+ /**
+ * Set callback list.
+ * @param cb new callback list
+ */
void set_callbacks(const callbacks &cb)
{
callbacks_ = cb;
@@ -178,23 +204,20 @@ public:
/**
* Returns list of known test groups.
+ * @return groups list
*/
const groupnames list_groups() const
{
groupnames ret;
- const_iterator i = groups_.begin();
- const_iterator e = groups_.end();
- while (i != e)
+ for(const_iterator i = groups_.begin(); i != groups_.end(); ++i)
{
ret.push_back(i->first);
- ++i;
}
return ret;
}
/**
* Runs all tests in all groups.
- * @param callback Callback object if exists; null otherwise
*/
void run_tests() const
{
@@ -216,6 +239,7 @@ public:
/**
* Runs all tests in specified group.
+ * @param group_name group to test
*/
void run_tests(const std::string& group_name) const
{
@@ -236,6 +260,10 @@ public:
/**
* Runs one test in specified group.
+ * @param group_name group to test
+ * @param n run case in test
+ * @param tr result of this case
+ * @return true if test is ok, otherwise false
*/
bool run_test(const std::string& group_name, int n, test_result &tr) const
{
@@ -356,4 +384,5 @@ extern test_runner_singleton runner;
}
-#endif
+#endif // TUT_RUNNER_H_GUARD
+
diff --git a/tests/unit/tut/tut_xml_reporter.hpp b/tests/unit/tut/tut_xml_reporter.hpp
new file mode 100644
index 0000000..1a8dd11
--- /dev/null
+++ b/tests/unit/tut/tut_xml_reporter.hpp
@@ -0,0 +1,310 @@
+#ifndef TUT_XML_REPORTER
+#define TUT_XML_REPORTER
+#include <tut/tut_config.hpp>
+#include <tut/tut.hpp>
+#include <tut/tut_cppunit_reporter.hpp>
+#include <cassert>
+#include <string>
+#include <fstream>
+#include <vector>
+#include <stdexcept>
+
+#if defined(TUT_USE_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace tut
+{
+
+/**
+ * \brief JUnit XML TUT reporter
+ * @author Lukasz Maszczynski, NSN
+ * @date 11/07/2008
+ */
+class xml_reporter : public tut::callback
+{
+ typedef std::vector<tut::test_result> TestResults;
+ typedef std::map<std::string, TestResults> TestGroups;
+
+ TestGroups all_tests_; /// holds all test results
+ const std::string filename_; /// filename base
+ TUT_UNIQUE_PTR<std::ostream> stream_;
+
+ /**
+ * \brief Builds "testcase" XML entity with given parameters
+ * Builds \<testcase\> entity according to given parameters. \<testcase\>-s are part of \<testsuite\>.
+ * @param tr test result to be used as source data
+ * @param failure_type type of failure to be reported ("Assertion" or "Error", empty if test passed)
+ * @param failure_msg failure message to be reported (empty, if test passed)
+ * @return string with \<testcase\> entity
+ */
+ std::string xml_build_testcase(const tut::test_result & tr, const std::string & failure_type,
+ const std::string & failure_msg, int pid = 0)
+ {
+ using std::endl;
+ using std::string;
+
+ std::ostringstream out;
+
+ if ( (tr.result == test_result::ok) ||
+ (tr.result == test_result::skipped) )
+ {
+ out << " <testcase classname=\"" << cppunit_reporter::encode(tr.group) << "\" name=\"" << cppunit_reporter::encode(tr.name) << "\"/>";
+ }
+ else
+ {
+ string err_msg = cppunit_reporter::encode(failure_msg + tr.message);
+
+ string tag; // determines tag name: "failure" or "error"
+ if ( tr.result == test_result::fail || tr.result == test_result::warn ||
+ tr.result == test_result::ex || tr.result == test_result::ex_ctor || tr.result == test_result::rethrown )
+ {
+ tag = "failure";
+ }
+ else
+ {
+ tag = "error";
+ }
+
+ out << " <testcase classname=\"" << cppunit_reporter::encode(tr.group) << "\" name=\"" << cppunit_reporter::encode(tr.name) << "\">" << endl;
+ out << " <" << tag << " message=\"" << err_msg << "\"" << " type=\"" << failure_type << "\"";
+#if defined(TUT_USE_POSIX)
+ if(pid != getpid())
+ {
+ out << " child=\"" << pid << "\"";
+ }
+#else
+ (void)pid;
+#endif
+ out << ">" << err_msg << "</" << tag << ">" << endl;
+ out << " </testcase>";
+ }
+
+ return out.str();
+ }
+
+ /**
+ * \brief Builds "testsuite" XML entity
+ * Builds \<testsuite\> XML entity according to given parameters.
+ * @param errors number of errors to be reported
+ * @param failures number of failures to be reported
+ * @param total total number of tests to be reported
+ * @param name test suite name
+ * @param testcases cppunit_reporter::encoded XML string containing testcases
+ * @return string with \<testsuite\> entity
+ */
+ std::string xml_build_testsuite(int errors, int failures, int total,
+ const std::string & name, const std::string & testcases)
+ {
+ std::ostringstream out;
+
+ out << " <testsuite errors=\"" << errors << "\" failures=\"" << failures << "\" tests=\"" << total << "\" name=\"" << cppunit_reporter::encode(name) << "\">" << std::endl;
+ out << testcases;
+ out << " </testsuite>";
+
+ return out.str();
+ }
+
+public:
+ int ok_count; /// number of passed tests
+ int exceptions_count; /// number of tests that threw exceptions
+ int failures_count; /// number of tests that failed
+ int terminations_count; /// number of tests that would terminate
+ int warnings_count; /// number of tests where destructors threw an exception
+
+ /**
+ * \brief Default constructor
+ * @param filename base filename
+ */
+ xml_reporter(const std::string & filename)
+ : all_tests_(),
+ filename_(filename),
+ stream_(new std::ofstream(filename_.c_str())),
+ ok_count(0),
+ exceptions_count(0),
+ failures_count(0),
+ terminations_count(0),
+ warnings_count(0)
+ {
+ if (!stream_->good()) {
+ throw tut_error("Cannot open output file `" + filename_ + "`");
+ }
+ }
+
+ xml_reporter(std::ostream & stream)
+ : all_tests_(),
+ filename_(),
+ stream_(&stream),
+ ok_count(0),
+ exceptions_count(0),
+ failures_count(0),
+ terminations_count(0),
+ warnings_count(0)
+ {
+ }
+
+ ~xml_reporter()
+ {
+ if(filename_.empty())
+ {
+ stream_.release();
+ }
+ }
+
+ /**
+ * \brief Callback function
+ * This function is called before the first test is executed. It initializes counters.
+ */
+ virtual void run_started()
+ {
+ ok_count = 0;
+ exceptions_count = 0;
+ failures_count = 0;
+ terminations_count = 0;
+ warnings_count = 0;
+ all_tests_.clear();
+ }
+
+ /**
+ * \brief Callback function
+ * This function is called when test completes. Counters are updated here, and test results stored.
+ */
+ virtual void test_completed(const tut::test_result& tr)
+ {
+ // update global statistics
+ switch (tr.result) {
+ case test_result::ok:
+ case test_result::skipped:
+ ok_count++;
+ break;
+ case test_result::fail:
+ case test_result::rethrown:
+ failures_count++;
+ break;
+ case test_result::ex:
+ case test_result::ex_ctor:
+ exceptions_count++;
+ break;
+ case test_result::warn:
+ warnings_count++;
+ break;
+ case test_result::term:
+ terminations_count++;
+ break;
+ case tut::test_result::dummy:
+ assert(!"Should never be called");
+ } // switch
+
+ // add test result to results table
+ all_tests_[tr.group].push_back(tr);
+ }
+
+ /**
+ * \brief Callback function
+ * This function is called when all tests are completed. It generates XML output
+ * to file(s). File name base can be set with constructor.
+ */
+ virtual void run_completed()
+ {
+ /* *********************** header ***************************** */
+ *stream_ << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" << std::endl;
+ *stream_ << "<testsuites>" << std::endl;
+
+ // iterate over all test groups
+ for (TestGroups::const_iterator tgi = all_tests_.begin(); tgi != all_tests_.end(); ++tgi)
+ {
+ /* per-group statistics */
+ int passed = 0; // passed in single group
+ int exceptions = 0; // exceptions in single group
+ int failures = 0; // failures in single group
+ int terminations = 0; // terminations in single group
+ int warnings = 0; // warnings in single group
+ int errors = 0; // errors in single group
+
+
+ // output is written to string stream buffer, because JUnit format <testsuite> tag
+ // contains statistics, which aren't known yet
+ std::ostringstream out;
+
+ // iterate over all test cases in the current test group
+ const TestResults &results = tgi->second;
+ for (TestResults::const_iterator tri = results.begin(); tri != results.end(); ++tri)
+ {
+ std::string failure_type; // string describing the failure type
+ std::string failure_msg; // a string with failure message
+
+ switch (tri->result)
+ {
+ case test_result::ok:
+ case test_result::skipped:
+ passed++;
+ break;
+ case test_result::fail:
+ failure_type = "Assertion";
+ failure_msg = "";
+ failures++;
+ break;
+ case test_result::ex:
+ failure_type = "Assertion";
+ failure_msg = "Thrown exception: " + tri->exception_typeid + '\n';
+ exceptions++;
+ break;
+ case test_result::warn:
+ failure_type = "Assertion";
+ failure_msg = "Destructor failed.\n";
+ warnings++;
+ break;
+ case test_result::term:
+ failure_type = "Error";
+ failure_msg = "Test application terminated abnormally.\n";
+ terminations++;
+ break;
+ case test_result::ex_ctor:
+ failure_type = "Assertion";
+ failure_msg = "Constructor has thrown an exception: " + tri->exception_typeid + ".\n";
+ exceptions++;
+ break;
+ case test_result::rethrown:
+ failure_type = "Assertion";
+ failure_msg = "Child failed.\n";
+ failures++;
+ break;
+ default:
+ failure_type = "Error";
+ failure_msg = "Unknown test status, this should have never happened. "
+ "You may just have found a bug in TUT, please report it immediately.\n";
+ errors++;
+ break;
+ } // switch
+
+#if defined(TUT_USE_POSIX)
+ out << xml_build_testcase(*tri, failure_type, failure_msg, tri->pid) << std::endl;
+#else
+ out << xml_build_testcase(*tri, failure_type, failure_msg) << std::endl;
+#endif
+ } // iterate over all test cases
+
+ // calculate per-group statistics
+ int stat_errors = terminations + errors;
+ int stat_failures = failures + warnings + exceptions;
+ int stat_all = stat_errors + stat_failures + passed;
+
+ *stream_ << xml_build_testsuite(stat_errors, stat_failures, stat_all, (*tgi).first/* name */, out.str()/* testcases */) << std::endl;
+ } // iterate over all test groups
+
+ *stream_ << "</testsuites>" << std::endl;
+ }
+
+ /**
+ * \brief Returns true, if all tests passed
+ */
+ virtual bool all_ok() const
+ {
+ return ( (terminations_count + failures_count + warnings_count + exceptions_count) == 0);
+ };
+};
+
+}
+
+#endif
-----------------------------------------------------------------------
Summary of changes:
tests/unit/tut/tut.hpp | 141 ++++++++------
tests/unit/tut/tut_assert.hpp | 155 +++++++++++++---
tests/unit/tut/tut_config.hpp | 6 +
tests/unit/tut/tut_console_reporter.hpp | 103 ++++++----
tests/unit/tut/tut_cppunit_reporter.hpp | 218 ++++++++++++++++++++++
tests/unit/tut/tut_exception.hpp | 94 +++++++++-
tests/unit/tut/tut_fpt.hpp | 181 ++++++++++++++++++
tests/unit/tut/tut_macros.hpp | 71 +++++++
tests/unit/tut/tut_main.hpp | 111 +++++++++++
tests/unit/tut/tut_posix.hpp | 69 +++++--
tests/unit/tut/tut_reporter.hpp | 2 +-
tests/unit/tut/tut_restartable.hpp | 9 +-
tests/unit/tut/tut_result.hpp | 84 +++++++--
tests/unit/tut/tut_runner.hpp | 55 ++++--
tests/unit/tut/tut_xml_reporter.hpp | 310 +++++++++++++++++++++++++++++++
15 files changed, 1442 insertions(+), 167 deletions(-)
create mode 100644 tests/unit/tut/tut_config.hpp
create mode 100644 tests/unit/tut/tut_cppunit_reporter.hpp
create mode 100644 tests/unit/tut/tut_fpt.hpp
create mode 100644 tests/unit/tut/tut_macros.hpp
create mode 100644 tests/unit/tut/tut_main.hpp
create mode 100644 tests/unit/tut/tut_xml_reporter.hpp
hooks/post-receive
--
geos
More information about the geos-commits
mailing list