]> git.stg.codes - stg.git/blobdiff - tests/tut/tut_assert.hpp
Merge remote-tracking branch 'origin/master' into ticket
[stg.git] / tests / tut / tut_assert.hpp
index 7ee44bc234bee062fecd01cb89e511ef454668ad..c1959012ade5a6f78756f78b618ef56015f93ab5 100644 (file)
@@ -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.
+ */
+void skip(const char* msg = "")
+{
+    throw skipped(msg);
+}
+
+template<typename M>
+void skip(const M& msg)
+{
+    throw skipped(msg);
+}
+
 } // end of namespace
 
 }