[Liblas-commits] r1340 - in trunk: . test/unit/tut

liblas-commits at liblas.org liblas-commits at liblas.org
Fri Aug 14 20:20:27 EDT 2009


Author: mloskot
Date: Fri Aug 14 20:20:26 2009
New Revision: 1340
URL: http://liblas.org/changeset/1340

Log:
Updated C++ TUT Framework to latest revision (147) of its SVN trunk.

Added:
   trunk/test/unit/tut/tut_console_reporter.hpp
Modified:
   trunk/   (props changed)
   trunk/test/unit/tut/tut.hpp
   trunk/test/unit/tut/tut_assert.hpp
   trunk/test/unit/tut/tut_exception.hpp
   trunk/test/unit/tut/tut_posix.hpp
   trunk/test/unit/tut/tut_reporter.hpp
   trunk/test/unit/tut/tut_restartable.hpp
   trunk/test/unit/tut/tut_result.hpp
   trunk/test/unit/tut/tut_runner.hpp

Modified: trunk/test/unit/tut/tut.hpp
==============================================================================
--- trunk/test/unit/tut/tut.hpp	(original)
+++ trunk/test/unit/tut/tut.hpp	Fri Aug 14 20:20:26 2009
@@ -11,6 +11,10 @@
 #include <algorithm>
 #include <typeinfo>
 
+#if defined(linux)
+#define TUT_USE_POSIX
+#endif
+
 #include "tut_exception.hpp"
 #include "tut_result.hpp"
 #include "tut_posix.hpp"
@@ -58,6 +62,16 @@
         return current_test_name_;
     }
 
+    void set_test_id(int current_test_id)
+    {
+        current_test_id_ = current_test_id;
+    }
+
+    int get_test_id() const
+    {
+        return current_test_id_;
+    }
+
     /**
      * Default do-nothing test.
      */
@@ -77,6 +91,7 @@
     bool called_method_was_a_dummy_test_;
 
 private:
+    int             current_test_id_;
     std::string     current_test_name_;
 };
 
@@ -124,6 +139,14 @@
     tests tests_;
     tests_iterator current_test_;
 
+	enum seh_result
+	{
+		SEH_OK,
+		SEH_CTOR,
+		SEH_TEST,
+		SEH_DUMMY
+	};
+
     /**
      * Exception-in-destructor-safe smart-pointer class.
      */
@@ -287,85 +310,81 @@
     /**
      * Runs next test.
      */
-    test_result run_next()
+    bool run_next(test_result &tr)
     {
         if (current_test_ == tests_.end())
         {
-            throw no_more_tests();
+            return false;
         }
 
         // find next user-specialized test
         safe_holder<object> obj;
         while (current_test_ != tests_.end())
         {
-            try
-            {
-                tests_iterator current_test = current_test_++;
-
-                test_result tr = run_test_(current_test, obj);
+            tests_iterator current_test = current_test_++;
 
-                return tr;
-            }
-            catch (const no_such_test&)
+            if(run_test_(current_test, obj, tr) && tr.result != test_result::dummy)
             {
-                continue;
+                return true;
             }
         }
 
-        throw no_more_tests();
+        return false;
     }
 
     /**
      * Runs one test by position.
      */
-    test_result run_test(int n)
+    bool run_test(int n, test_result &tr)
     {
-        // beyond tests is special case to discover upper limit
-        if (tests_.rbegin() == tests_.rend())
+        if (tests_.rbegin() == tests_.rend() ||
+            tests_.rbegin()->first < n)
         {
-            throw beyond_last_test();
-        }
-
-        if (tests_.rbegin()->first < n)
-        {
-            throw beyond_last_test();
+            return false;
         }
 
         // withing scope; check if given test exists
         tests_iterator ti = tests_.find(n);
         if (ti == tests_.end())
         {
-            throw no_such_test();
+            return false;
         }
 
         safe_holder<object> obj;
-        test_result tr = run_test_(ti, obj);
-
-        return tr;
+        return run_test_(ti, obj, tr);
     }
 
-
     /**
      * VC allows only one exception handling type per function,
      * so I have to split the method.
      */
-    test_result run_test_(const tests_iterator& ti, safe_holder<object>& obj)
+    bool run_test_(const tests_iterator& ti, safe_holder<object>& obj, test_result &tr)
     {
         std::string current_test_name;
 
-        test_result tr(name_, ti->first, current_test_name, test_result::ok);
+        tr = test_result(name_, ti->first, current_test_name, test_result::ok);
 
         try
         {
-            if (run_test_seh_(ti->second, obj, current_test_name) == false)
-            {
-                throw seh("seh");
+            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;
             }
         }
-        catch (const no_such_test&)
-        {
-            throw;
-        }
         catch (const rethrown& ex)
         {
             tr = ex.tr;
@@ -401,14 +420,14 @@
             tr.name = current_test_name;
         }
 
-        return tr;
+        return true;
     }
 
     /**
      * Runs one under SEH if platform supports it.
      */
-    bool run_test_seh_(testmethod tm, safe_holder<object>& obj,
-        std::string& current_test_name)
+    seh_result run_test_seh_(testmethod tm, safe_holder<object>& obj,
+                             std::string& current_test_name, int current_test_id)
     {
 #if defined(TUT_USE_SEH)
         __try
@@ -426,21 +445,21 @@
             __try
             {
 #endif
+                obj.get()->set_test_id(current_test_id);
                 (obj.get()->*tm)();
 #if defined(TUT_USE_SEH)
             }
             __except(handle_seh_(::GetExceptionCode()))
             {
-                // throw seh("SEH");
                 current_test_name = obj->get_test_name();
-                return false;
+                return SEH_TEST;
             }
 #endif
 
         if (obj->called_method_was_a_dummy_test_)
         {
             // do not call obj.release(); reuse object
-            throw no_such_test();
+            return SEH_DUMMY;
         }
 
         current_test_name = obj->get_test_name();
@@ -450,10 +469,10 @@
         }
         __except(handle_seh_(::GetExceptionCode()))
         {
-            return false;
+			return SEH_CTOR;
         }
 #endif
-        return true;
+        return SEH_OK;
     }
 
     void reset_holder_(safe_holder<object>& obj)

Modified: trunk/test/unit/tut/tut_assert.hpp
==============================================================================
--- trunk/test/unit/tut/tut_assert.hpp	(original)
+++ trunk/test/unit/tut/tut_assert.hpp	Fri Aug 14 20:20:26 2009
@@ -2,6 +2,8 @@
 #define TUT_ASSERT_H_GUARD
 
 #include "tut_exception.hpp"
+#include <limits>
+#include <iomanip>
 
 #if defined(TUT_USE_POSIX)
 #include <errno.h>
@@ -11,6 +13,24 @@
 namespace tut
 {
 
+    namespace detail
+    {
+        template<typename M>
+        std::ostream &msg_prefix(std::ostream &str, const M &msg)
+        {
+            std::stringstream ss;
+            ss << msg;
+
+            if(!ss.str().empty())
+            {
+                str << ss.rdbuf() << ": ";
+            }
+
+            return str;
+        }
+    }
+
+
 namespace
 {
 
@@ -40,8 +60,8 @@
  * Tests provided condition.
  * Throws if false.
  */
-template <typename T>
-void ensure(const T msg, bool cond)
+template <typename M>
+void ensure(const M& msg, bool cond)
 {
     if (!cond)
     {
@@ -53,8 +73,8 @@
  * Tests provided condition.
  * Throws if true.
  */
-template <typename T>
-void ensure_not(const T msg, bool cond)
+template <typename M>
+void ensure_not(const M& msg, bool cond)
 {
     ensure(msg, !cond);
 }
@@ -66,29 +86,47 @@
  * NB: both T and Q must have operator << defined somewhere, or
  * client code will not compile at all!
  */
-template <class T, class Q>
-void ensure_equals(const char* msg, const Q& actual, const T& expected)
+template <typename M, typename LHS, typename RHS>
+void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
 {
     if (expected != actual)
     {
         std::stringstream ss;
-        ss << (msg ? msg : "")
-            << (msg ? ":" : "")
-            << " expected '"
-            << expected
-            << "' actual '"
-            << actual
-            << '\'';
-        throw failure(ss.str().c_str());
+        detail::msg_prefix(ss,msg)
+           << "expected '"
+           << expected
+           << "' actual '"
+           << actual
+           << '\'';
+        throw failure(ss.str());
     }
 }
 
-template <class T, class Q>
-void ensure_equals(const Q& actual, const T& expected)
+template <typename LHS, typename RHS>
+void ensure_equals(const LHS& actual, const RHS& expected)
 {
-    ensure_equals<>(0, actual, expected);
+    ensure_equals("Values are not equal", actual, expected);
 }
 
+template<typename M>
+void ensure_equals(const M& msg, const double& actual, const double& expected,
+                   const double& epsilon = std::numeric_limits<double>::epsilon())
+{
+    const double diff = actual - expected;
+
+    if ( !((diff <= epsilon) && (diff >= -epsilon )) )
+    {
+        std::stringstream ss;
+        detail::msg_prefix(ss,msg)
+           << std::scientific
+           << std::showpoint
+           << std::setprecision(16)
+           << "expected " << expected
+           << " actual " << actual
+           << " with precision " << epsilon;
+        throw failure(ss.str());
+    }
+}
 /**
  * Tests two objects for being at most in given distance one from another.
  * Borders are excluded.
@@ -97,16 +135,16 @@
  * NB: T must have operator << defined somewhere, or
  * client code will not compile at all! Also, T shall have
  * operators + and -, and be comparable.
+ *
+ * TODO: domains are wrong, T - T might not yield T, but Q
  */
-template <class T>
-void ensure_distance(const char* msg, const T& actual, const T& expected,
-    const T& distance)
+template <typename M, class T>
+void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance)
 {
     if (expected-distance >= actual || expected+distance <= actual)
     {
         std::stringstream ss;
-        ss << (msg ? msg : "")
-            << (msg? ":" : "")
+        detail::msg_prefix(ss,msg)
             << " expected ("
             << expected-distance
             << " - "
@@ -114,27 +152,27 @@
             << ") actual '"
             << actual
             << '\'';
-        throw failure(ss.str().c_str());
+        throw failure(ss.str());
     }
 }
 
 template <class T>
 void ensure_distance(const T& actual, const T& expected, const T& distance)
 {
-    ensure_distance<>(0, actual, expected, distance);
+    ensure_distance<>("Distance is wrong", actual, expected, distance);
 }
 
-void ensure_errno(const char *msg, bool cond)
+template<typename M>
+void ensure_errno(const M& msg, bool cond)
 {
     if(!cond)
     {
 #if defined(TUT_USE_POSIX)
         char e[512];
         std::stringstream ss;
-        ss << (msg ? msg : "")
-            << (msg? ": " : "")
-            << strerror_r(errno, e, sizeof(e));
-        throw failure(ss.str().c_str());
+        detail::msg_prefix(ss,msg)
+           << strerror_r(errno, e, sizeof(e));
+        throw failure(ss.str());
 #else
         throw failure(msg);
 #endif
@@ -149,7 +187,8 @@
     throw failure(msg);
 }
 
-void fail(const std::string &msg)
+template<typename M>
+void fail(const M& msg)
 {
     throw failure(msg);
 }

Added: trunk/test/unit/tut/tut_console_reporter.hpp
==============================================================================
--- (empty file)
+++ trunk/test/unit/tut/tut_console_reporter.hpp	Fri Aug 14 20:20:26 2009
@@ -0,0 +1,241 @@
+#ifndef TUT_CONSOLE_REPORTER
+#define TUT_CONSOLE_REPORTER
+
+#include <tut/tut.hpp>
+#include <cassert>
+
+/**
+ * Template Unit Tests Framework for C++.
+ * http://tut.dozen.ru
+ *
+ * @author Vladimir Dyuzhev, Vladimir.Dyuzhev at gmail.com
+ */
+namespace
+{
+
+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");
+    }
+
+    return os;
+}
+
+} // end of namespace
+
+namespace tut
+{
+
+/**
+ * Default TUT callback handler.
+ */
+class console_reporter : public tut::callback
+{
+    std::string current_group;
+    typedef std::vector<tut::test_result> not_passed_list;
+    not_passed_list not_passed;
+    std::ostream& os;
+
+public:
+
+    int ok_count;
+    int exceptions_count;
+    int failures_count;
+    int terminations_count;
+    int warnings_count;
+
+    console_reporter()
+        : os(std::cout)
+    {
+        init();
+    }
+
+    console_reporter(std::ostream& out)
+        : os(out)
+    {
+        init();
+    }
+
+    void run_started()
+    {
+        init();
+    }
+
+    void test_completed(const tut::test_result& tr)
+    {
+        if (tr.group != current_group)
+        {
+            os << std::endl << tr.group << ": " << std::flush;
+            current_group = tr.group;
+        }
+
+        os << tr << std::flush;
+
+        // update global statistics
+        switch (tr.result) {
+            case test_result::ok:
+                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
+
+        if (tr.result != tut::test_result::ok)
+        {
+            not_passed.push_back(tr);
+        }
+    }
+
+    void run_completed()
+    {
+        os << std::endl;
+
+        if (not_passed.size() > 0)
+        {
+            not_passed_list::const_iterator i = not_passed.begin();
+            while (i != not_passed.end())
+            {
+                tut::test_result tr = *i;
+
+                os << std::endl;
+
+                os << "---> " << "group: " << tr.group
+                << ", test: test<" << tr.test << ">"
+                << (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string())
+                << std::endl;
+
+#if defined(TUT_USE_POSIX)
+                if(tr.pid != getpid())
+                {
+                    os << "     child pid: " << tr.pid << std::endl;
+                }
+#endif
+                os << "     problem: ";
+                switch(tr.result)
+                {
+                case test_result::rethrown:
+                    os << "assertion failed in child" << std::endl;
+                    break;
+                case test_result::fail:
+                    os << "assertion failed" << std::endl;
+                    break;
+                case test_result::ex:
+                case test_result::ex_ctor:
+                    os << "unexpected exception" << std::endl;
+                    if( tr.exception_typeid != "" )
+                    {
+                        os << "     exception typeid: "
+                        << tr.exception_typeid << std::endl;
+                    }
+                    break;
+                case test_result::term:
+                    os << "would be terminated" << std::endl;
+                    break;
+                case test_result::warn:
+                    os << "test passed, but cleanup code (destructor) raised"
+                        " an exception" << std::endl;
+                    break;
+                default:
+                    break;
+                }
+
+                if (!tr.message.empty())
+                {
+                    if (tr.result == test_result::fail)
+                    {
+                        os << "     failed assertion: \"" << tr.message << "\""
+                            << std::endl;
+                    }
+                    else
+                    {
+                        os << "     message: \"" << tr.message << "\""
+                            << std::endl;
+                    }
+                }
+
+                ++i;
+            }
+        }
+
+        os << std::endl;
+
+        os << "tests summary:";
+        if (terminations_count > 0)
+        {
+            os << " terminations:" << terminations_count;
+        }
+        if (exceptions_count > 0)
+        {
+            os << " exceptions:" << exceptions_count;
+        }
+        if (failures_count > 0)
+        {
+            os << " failures:" << failures_count;
+        }
+        if (warnings_count > 0)
+        {
+            os << " warnings:" << warnings_count;
+        }
+        os << " ok:" << ok_count;
+        os << std::endl;
+    }
+
+    bool all_ok() const
+    {
+        return not_passed.empty();
+    }
+
+private:
+
+    void init()
+    {
+        ok_count = 0;
+        exceptions_count = 0;
+        failures_count = 0;
+        terminations_count = 0;
+        warnings_count = 0;
+        not_passed.clear();
+    }
+};
+
+}
+
+#endif

Modified: trunk/test/unit/tut/tut_exception.hpp
==============================================================================
--- trunk/test/unit/tut/tut_exception.hpp	(original)
+++ trunk/test/unit/tut/tut_exception.hpp	Fri Aug 14 20:20:26 2009
@@ -37,38 +37,6 @@
 };
 
 /**
- * Exception to be throwed when attempted to execute
- * missed test by number.
- */
-struct no_such_test : public tut_error
-{
-    no_such_test()
-        : tut_error("no such test")
-    {
-    }
-
-    ~no_such_test() throw()
-    {
-    }
-};
-
-/**
- * No such test and passed test number is higher than
- * any test number in current group. Used in one-by-one
- * test running when upper bound is not known.
- */
-struct beyond_last_test : public no_such_test
-{
-    beyond_last_test()
-    {
-    }
-
-    ~beyond_last_test() throw()
-    {
-    }
-};
-
-/**
  * Group not found exception.
  */
 struct no_such_group : public tut_error
@@ -85,21 +53,6 @@
 
 /**
  * Internal exception to be throwed when
- * no more tests left in group or journal.
- */
-struct no_more_tests
-{
-    no_more_tests()
-    {
-    }
-
-    ~no_more_tests() throw()
-    {
-    }
-};
-
-/**
- * Internal exception to be throwed when
  * test constructor has failed.
  */
 struct bad_ctor : public tut_error

Modified: trunk/test/unit/tut/tut_posix.hpp
==============================================================================
--- trunk/test/unit/tut/tut_posix.hpp	(original)
+++ trunk/test/unit/tut/tut_posix.hpp	Fri Aug 14 20:20:26 2009
@@ -65,11 +65,19 @@
     pid_t fork()
     {
         test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
-        ensure("trying to call 'fork' in ctor of test object", self != NULL);
+        ensure("trying to call 'tut_fork' in ctor of test object", self != NULL);
 
         return self->fork_();
     }
 
+    pid_t waitpid(pid_t pid, int *status, int flags = 0)
+    {
+        test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
+        ensure("trying to call 'tut_waitpid' in ctor of test object", self != NULL);
+
+        return self->waitpid_(pid, status, flags);
+    }
+
     void ensure_child_exit(pid_t pid, int exit_status = 0)
     {
         test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
@@ -188,7 +196,7 @@
         else
         {
             // in child, shutdown reporter
-            tut::runner.get().set_callback(NULL);
+            tut::runner.get().clear_callbacks();
 
             // close reading side
             close(fds[0]);
@@ -248,13 +256,13 @@
                     return;
                 }
                 else
-            {
-                std::stringstream ss;
+                {
+                    std::stringstream ss;
                     char e[1024];
                     ss << "child " << pid << " could not be killed with SIGKILL, " << strerror_r(errno, e, sizeof(e)) << std::endl;
-                fail(ss.str());
+                    fail(ss.str());
+                }
             }
-        }
 
             ensure_equals("wait after SIGKILL", waitpid_(pid, &status), pid);
             ensure_child_signal_(status, SIGKILL);
@@ -290,8 +298,20 @@
         return tr;
     }
 
+    struct fdclose
+    {
+        fdclose(int fd): fd_(fd) { }
+        ~fdclose()
+        {
+            close(fd_);
+        }
+    private:
+        int fd_;
+    };
+
     pid_t waitpid_(pid_t pid, int *status, int flags = 0)
     {
+
         ensure("trying to wait for unknown pid", pids_.count(pid) > 0);
 
         pid_t p = ::waitpid(pid, status, flags);
@@ -309,6 +329,8 @@
         FD_ZERO(&fdset);
 
         int pipe = pids_[pid];
+        fdclose guard(pipe);
+
         FD_SET(pipe, &fdset);
 
         int result = select(pipe+1, &fdset, NULL, NULL, &tv);
@@ -417,7 +439,7 @@
 
         return pids;
     }
-    
+
     pid_map         pids_;
     int             pipe_;
 };

Modified: trunk/test/unit/tut/tut_reporter.hpp
==============================================================================
--- trunk/test/unit/tut/tut_reporter.hpp	(original)
+++ trunk/test/unit/tut/tut_reporter.hpp	Fri Aug 14 20:20:26 2009
@@ -1,243 +1,11 @@
 #ifndef TUT_REPORTER
 #define TUT_REPORTER
 
-#include <tut/tut.hpp>
-
-/**
- * Template Unit Tests Framework for C++.
- * http://tut.dozen.ru
- *
- * @author Vladimir Dyuzhev, Vladimir.Dyuzhev at gmail.com
- */
-namespace
-{
-
-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;
-    }
-
-    return os;
-}
-
-} // end of namespace
+#include <tut/tut_console_reporter.hpp>
 
 namespace tut
 {
-
-/**
- * Default TUT callback handler.
- */
-class reporter : public tut::callback
-{
-    std::string current_group;
-    typedef std::vector<tut::test_result> not_passed_list;
-    not_passed_list not_passed;
-    std::ostream& os;
-
-public:
-
-    int ok_count;
-    int exceptions_count;
-    int failures_count;
-    int terminations_count;
-    int warnings_count;
-
-    reporter()
-        : os(std::cout)
-    {
-        init();
-    }
-
-    reporter(std::ostream& out)
-        : os(out)
-    {
-        init();
-    }
-
-    void run_started()
-    {
-        init();
-    }
-
-    void test_completed(const tut::test_result& tr)
-    {
-        if (tr.group != current_group)
-        {
-            os << std::endl << tr.group << ": " << std::flush;
-            current_group = tr.group;
-        }
-
-        os << tr << std::flush;
-        if (tr.result == tut::test_result::ok)
-        {
-            ok_count++;
-        }
-        else if (tr.result == tut::test_result::ex)
-        {
-            exceptions_count++;
-        }
-        else if (tr.result == tut::test_result::ex_ctor)
-        {
-            exceptions_count++;
-        }
-        else if (tr.result == tut::test_result::fail)
-        {
-            failures_count++;
-        }
-        else if (tr.result == tut::test_result::rethrown)
-        {
-            failures_count++;
-        }
-        else if (tr.result == tut::test_result::warn)
-        {
-            warnings_count++;
-        }
-        else
-        {
-            terminations_count++;
-        }
-
-        if (tr.result != tut::test_result::ok)
-        {
-            not_passed.push_back(tr);
-        }
-    }
-
-    void run_completed()
-    {
-        os << std::endl;
-
-        if (not_passed.size() > 0)
-        {
-            not_passed_list::const_iterator i = not_passed.begin();
-            while (i != not_passed.end())
-            {
-                tut::test_result tr = *i;
-
-                os << std::endl;
-
-                os << "---> " << "group: " << tr.group
-                << ", test: test<" << tr.test << ">"
-                << (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string())
-                << std::endl;
-
-#if defined(TUT_USE_POSIX)
-                if(tr.pid != getpid())
-                {
-                    os << "     child pid: " << tr.pid << std::endl;
-                }
-#endif
-                os << "     problem: ";
-                switch(tr.result)
-                {
-                case test_result::rethrown:
-                    os << "assertion failed in child" << std::endl;
-                    break;
-                case test_result::fail:
-                    os << "assertion failed" << std::endl;
-                    break;
-                case test_result::ex:
-                case test_result::ex_ctor:
-                    os << "unexpected exception" << std::endl;
-                    if( tr.exception_typeid != "" )
-                    {
-                        os << "     exception typeid: "
-                        << tr.exception_typeid << std::endl;
-                    }
-                    break;
-                case test_result::term:
-                    os << "would be terminated" << std::endl;
-                    break;
-                case test_result::warn:
-                    os << "test passed, but cleanup code (destructor) raised"
-                        " an exception" << std::endl;
-                    break;
-                default:
-                    break;
-                }
-
-                if (!tr.message.empty())
-                {
-                    if (tr.result == test_result::fail)
-                    {
-                        os << "     failed assertion: \"" << tr.message << "\""
-                            << std::endl;
-                    }
-                    else
-                    {
-                        os << "     message: \"" << tr.message << "\""
-                            << std::endl;
-                    }
-                }
-
-                ++i;
-            }
-        }
-
-        os << std::endl;
-
-        os << "tests summary:";
-        if (terminations_count > 0)
-        {
-            os << " terminations:" << terminations_count;
-        }
-        if (exceptions_count > 0)
-        {
-            os << " exceptions:" << exceptions_count;
-        }
-        if (failures_count > 0)
-        {
-            os << " failures:" << failures_count;
-        }
-        if (warnings_count > 0)
-        {
-            os << " warnings:" << warnings_count;
-        }
-        os << " ok:" << ok_count;
-        os << std::endl;
-    }
-
-    bool all_ok() const
-    {
-        return not_passed.empty();
-    }
-
-private:
-
-    void init()
-    {
-        ok_count = 0;
-        exceptions_count = 0;
-        failures_count = 0;
-        terminations_count = 0;
-        warnings_count = 0;
-        not_passed.clear();
-    }
-};
-
+    typedef console_reporter reporter;
 }
 
 #endif

Modified: trunk/test/unit/tut/tut_restartable.hpp
==============================================================================
--- trunk/test/unit/tut/tut_restartable.hpp	(original)
+++ trunk/test/unit/tut/tut_restartable.hpp	Fri Aug 14 20:20:26 2009
@@ -7,11 +7,10 @@
 #include <stdexcept>
 
 /**
- * Template Unit Tests Framework for C++.
- * http://tut.dozen.ru
+ * Optional restartable wrapper for test_runner.
  *
- * Optional restartable wrapper for test_runner. Allows to restart test runs
- * finished due to abnormal test application termination (such as segmentation
+ * Allows to restart test runs finished due to abnormal
+ * test application termination (such as segmentation
  * fault or math error).
  *
  * @author Vladimir Dyuzhev, Vladimir.Dyuzhev at gmail.com
@@ -19,10 +18,10 @@
 
 namespace tut
 {
-    
+
 namespace util
 {
-    
+
 /**
  * Escapes non-alphabetical characters in string.
  */
@@ -124,12 +123,12 @@
 /**
  * deserialization for test_result
  */
-void deserialize(std::istream& is, tut::test_result& tr)
+bool deserialize(std::istream& is, tut::test_result& tr)
 {
     std::getline(is,tr.group);
     if (is.eof())
     {
-        throw tut::no_more_tests();
+        return false;
     }
     tr.group = unescape(tr.group);
 
@@ -170,6 +169,7 @@
     {
         throw std::logic_error("malformed test result");
     }
+    return true;
 }
 };
 
@@ -179,7 +179,7 @@
 class restartable_wrapper
 {
     test_runner& runner_;
-    callback* callback_;
+    callbacks callbacks_;
 
     std::string dir_;
     std::string log_; // log file: last test being executed
@@ -191,8 +191,7 @@
      * @param dir Directory where to search/put log and journal files
      */
     restartable_wrapper(const std::string& dir = ".")
-        : runner_(runner.get()), 
-          callback_(0), 
+        : runner_(runner.get()),
           dir_(dir)
     {
         // dozen: it works, but it would be better to use system path separator
@@ -213,15 +212,28 @@
      */
     void set_callback(callback* cb)
     {
-        callback_ = cb;
+        callbacks_.clear();
+        callbacks_.insert(cb);
     }
 
-    /**
-     * Returns callback object.
-     */
-    callback& get_callback() const
+    void insert_callback(callback* cb)
     {
-        return runner_.get_callback();
+        callbacks_.insert(cb);
+    }
+
+    void erase_callback(callback* cb)
+    {
+        callbacks_.erase(cb);
+    }
+
+    void set_callbacks(const callbacks& cb)
+    {
+        callbacks_ = cb;
+    }
+
+    const callbacks& get_callbacks() const
+    {
+        return runner_.get_callbacks();
     }
 
     /**
@@ -270,17 +282,17 @@
 
                 try
                 {
-                    tut::test_result tr = runner_.run_test(*gni,test);
+                    tut::test_result tr;
+                    if( !runner_.run_test(*gni,test, tr) )
+                    {
+                        break;
+                    }
                     register_test_(tr);
                 }
                 catch (const tut::beyond_last_test&)
                 {
                     break;
                 }
-                catch(const tut::no_such_test&)
-                {
-                    // it's ok
-                }
 
                 ++test;
             }
@@ -301,27 +313,22 @@
      */
     void invoke_callback_() const
     {
-        runner_.set_callback(callback_);
-        runner_.get_callback().run_started();
+        runner_.set_callbacks(callbacks_);
+        runner_.cb_run_started_();
 
         std::string current_group;
         std::ifstream ijournal(jrn_.c_str());
         while (ijournal.good())
         {
-            // read next test result
-            try
-            {
-                tut::test_result tr;
-                util::deserialize(ijournal,tr);
-                runner_.get_callback().test_completed(tr);
-            }
-            catch (const no_more_tests&)
+            tut::test_result tr;
+            if( !util::deserialize(ijournal,tr) )
             {
                 break;
             }
+            runner_.cb_test_completed_(tr);
         }
 
-        runner_.get_callback().run_completed();
+        runner_.cb_run_completed_();
     }
 
     /**

Modified: trunk/test/unit/tut/tut_result.hpp
==============================================================================
--- trunk/test/unit/tut/tut_result.hpp	(original)
+++ trunk/test/unit/tut/tut_result.hpp	Fri Aug 14 20:20:26 2009
@@ -60,7 +60,8 @@
         warn,
         term,
         ex_ctor,
-        rethrown
+        rethrown,
+        dummy
     };
 
     result_type result;

Modified: trunk/test/unit/tut/tut_runner.hpp
==============================================================================
--- trunk/test/unit/tut/tut_runner.hpp	(original)
+++ trunk/test/unit/tut/tut_runner.hpp	Fri Aug 14 20:20:26 2009
@@ -3,6 +3,7 @@
 
 #include <string>
 #include <vector>
+#include <set>
 #include "tut_exception.hpp"
 
 namespace tut
@@ -20,10 +21,10 @@
 
     // execute tests iteratively
     virtual void rewind() = 0;
-    virtual test_result run_next() = 0;
+    virtual bool run_next(test_result &) = 0;
 
     // execute one test
-    virtual test_result run_test(int n) = 0;
+    virtual bool run_test(int n, test_result &tr) = 0;
 };
 
 
@@ -37,6 +38,13 @@
 struct callback
 {
     /**
+     * Default constructor.
+     */
+    callback()
+    {
+    }
+
+    /**
      * Virtual destructor is a must for subclassed types.
      */
     virtual ~callback()
@@ -80,12 +88,16 @@
     virtual void run_completed()
     {
     }
+private:
+    callback(const callback &);
+    void operator=(const callback&);
 };
 
 /**
  * Typedef for runner::list_groups()
  */
 typedef std::vector<std::string> groupnames;
+typedef std::set<callback*> callbacks;
 
 /**
  * Test runner.
@@ -99,7 +111,6 @@
      * Constructor
      */
     test_runner()
-        : callback_(&default_callback_)
     {
     }
 
@@ -125,20 +136,44 @@
         groups_.insert( std::make_pair(name, gr) );
     }
 
+    void set_callback(callback *cb)
+    {
+        clear_callbacks();
+        insert_callback(cb);
+    }
+
     /**
      * Stores callback object.
      */
-    void set_callback(callback* cb)
+    void insert_callback(callback* cb)
+    {
+        if(cb != NULL)
+        {
+            callbacks_.insert(cb);
+        }
+    }
+
+    void erase_callback(callback* cb)
+    {
+        callbacks_.erase(cb);
+    }
+
+    void clear_callbacks()
     {
-        callback_ = cb == 0 ? &default_callback_ : cb;
+        callbacks_.clear();
     }
 
     /**
-     * Returns callback object.
+     * Returns callback list.
      */
-    callback& get_callback() const
+    const callbacks &get_callbacks() const
+    {
+        return callbacks_;
+    }
+
+    void set_callbacks(const callbacks &cb)
     {
-        return *callback_;
+        callbacks_ = cb;
     }
 
     /**
@@ -163,26 +198,20 @@
      */
     void run_tests() const
     {
-        callback_->run_started();
+        cb_run_started_();
 
         const_iterator i = groups_.begin();
         const_iterator e = groups_.end();
         while (i != e)
         {
-            callback_->group_started(i->first);
-            try
-            {
-                run_all_tests_in_group_(i);
-            }
-            catch (const no_more_tests&)
-            {
-                callback_->group_completed(i->first);
-            }
+            cb_group_started_(i->first);
+            run_all_tests_in_group_(i);
+            cb_group_completed_(i->first);
 
             ++i;
         }
 
-        callback_->run_completed();
+        cb_run_completed_();
     }
 
     /**
@@ -190,64 +219,48 @@
      */
     void run_tests(const std::string& group_name) const
     {
-        callback_->run_started();
+        cb_run_started_();
 
         const_iterator i = groups_.find(group_name);
         if (i == groups_.end())
         {
-            callback_->run_completed();
+            cb_run_completed_();
             throw no_such_group(group_name);
         }
 
-        callback_->group_started(group_name);
-        try
-        {
-            run_all_tests_in_group_(i);
-        }
-        catch (const no_more_tests&)
-        {
-            // ok
-        }
-
-        callback_->group_completed(group_name);
-        callback_->run_completed();
+        cb_group_started_(group_name);
+        run_all_tests_in_group_(i);
+        cb_group_completed_(group_name);
+        cb_run_completed_();
     }
 
     /**
      * Runs one test in specified group.
      */
-    test_result run_test(const std::string& group_name, int n) const
+    bool run_test(const std::string& group_name, int n, test_result &tr) const
     {
-        callback_->run_started();
+        cb_run_started_();
 
         const_iterator i = groups_.find(group_name);
         if (i == groups_.end())
         {
-            callback_->run_completed();
+            cb_run_completed_();
             throw no_such_group(group_name);
         }
 
-        callback_->group_started(group_name);
-        try
+        cb_group_started_(group_name);
+
+        bool t = i->second->run_test(n, tr);
+
+        if(t && tr.result != test_result::dummy)
         {
-            test_result tr = i->second->run_test(n);
-            callback_->test_completed(tr);
-            callback_->group_completed(group_name);
-            callback_->run_completed();
-            return tr;
-        }
-        catch (const beyond_last_test&)
-        {
-            callback_->group_completed(group_name);
-            callback_->run_completed();
-            throw;
-        }
-        catch (const no_such_test&)
-        {
-            callback_->group_completed(group_name);
-            callback_->run_completed();
-            throw;
+            cb_test_completed_(tr);
         }
+
+        cb_group_completed_(group_name);
+        cb_run_completed_();
+
+        return t;
     }
 
 protected:
@@ -257,23 +270,67 @@
     typedef groups::const_iterator const_iterator;
     groups groups_;
 
-    callback  default_callback_;
-    callback* callback_;
-
+    callbacks callbacks_;
 
 private:
+    friend class restartable_wrapper;
+
+    void cb_run_started_() const
+    {
+        for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
+        {
+            (*i)->run_started();
+        }
+    }
+
+    void cb_run_completed_() const
+    {
+        for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
+        {
+            (*i)->run_completed();
+        }
+    }
+
+    void cb_group_started_(const std::string &group_name) const
+    {
+        for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
+        {
+            (*i)->group_started(group_name);
+        }
+    }
+
+    void cb_group_completed_(const std::string &group_name) const
+    {
+        for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
+        {
+            (*i)->group_completed(group_name);
+        }
+    }
+
+    void cb_test_completed_(const test_result &tr) const
+    {
+        for(callbacks::const_iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
+        {
+            (*i)->test_completed(tr);
+        }
+    }
 
     void run_all_tests_in_group_(const_iterator i) const
     {
         i->second->rewind();
-        for ( ;; )
+
+        test_result tr;
+        while(i->second->run_next(tr))
         {
-            test_result tr = i->second->run_next();
-            callback_->test_completed(tr);
+            if(tr.result != test_result::dummy)
+            {
+                cb_test_completed_(tr);
+            }
 
             if (tr.result == test_result::ex_ctor)
             {
-                throw no_more_tests();
+                // test object ctor failed, skip whole group
+                break;
             }
         }
     }


More information about the Liblas-commits mailing list