[geos-commits] [SCM] geos branch svn-trunk updated. ee134e7af15898a2cc6631d046851b50523cf437

git at osgeo.org git at osgeo.org
Thu Apr 6 01:42:13 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-trunk has been updated
       via  ee134e7af15898a2cc6631d046851b50523cf437 (commit)
      from  4091c89da51c4ee35882f995157e13bd5e4d7981 (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 ee134e7af15898a2cc6631d046851b50523cf437
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