Commit 17e0d841 authored by Mateusz Łoskot's avatar Mateusz Łoskot

Update TUT to latest release 2016-12-19.

Source: https://github.com/mrzechonek/tut-framework/releases/tag/2016-12-19

Fixes #639
Fixes #804
parent 39c807df
Pipeline #7476646 failed with stage
in 37 minutes
#ifndef TUT_H_GUARD #ifndef TUT_H_GUARD
#define TUT_H_GUARD #define TUT_H_GUARD
#include <tut/tut_config.hpp>
#undef public
#undef private
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
...@@ -9,11 +12,6 @@ ...@@ -9,11 +12,6 @@
#include <sstream> #include <sstream>
#include <iterator> #include <iterator>
#include <algorithm> #include <algorithm>
#include <typeinfo>
#if defined(linux)
#define TUT_USE_POSIX
#endif
#include "tut_exception.hpp" #include "tut_exception.hpp"
#include "tut_result.hpp" #include "tut_result.hpp"
...@@ -35,6 +33,9 @@ ...@@ -35,6 +33,9 @@
namespace tut namespace tut
{ {
template <class, int>
class test_group;
/** /**
* Test object. Contains data test run upon and default test method * Test object. Contains data test run upon and default test method
* implementation. Inherited from Data to allow tests to * implementation. Inherited from Data to allow tests to
...@@ -43,12 +44,29 @@ namespace tut ...@@ -43,12 +44,29 @@ namespace tut
template <class Data> template <class Data>
class test_object : public Data, public test_object_posix 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: public:
/** /**
* Default constructor * Default constructor
*/ */
test_object() test_object()
: called_method_was_a_dummy_test_(false),
current_test_id_(0),
current_test_name_(),
current_test_group_()
{ {
} }
...@@ -62,9 +80,9 @@ public: ...@@ -62,9 +80,9 @@ public:
return current_test_name_; 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 int get_test_id() const
...@@ -86,16 +104,17 @@ public: ...@@ -86,16 +104,17 @@ public:
* Used to detect usused test numbers and avoid unnecessary * Used to detect usused test numbers and avoid unnecessary
* test object creation which may be time-consuming depending * test object creation which may be time-consuming depending
* on operations described in Data::Data() and Data::~Data(). * 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_; bool called_method_was_a_dummy_test_;
virtual ~test_object()
{
}
private: private:
int current_test_id_; int current_test_id_;
std::string current_test_name_; std::string current_test_name_;
std::string current_test_group_;
test_object(test_object const&); // = delete
test_object& operator=(test_object const&); // = delete
}; };
...@@ -129,6 +148,9 @@ struct tests_registerer<Test, Group, 0> ...@@ -129,6 +148,9 @@ struct tests_registerer<Test, Group, 0>
template <class Data, int MaxTestsInGroup = 50> template <class Data, int MaxTestsInGroup = 50>
class test_group : public group_base, public test_group_posix class test_group : public group_base, public test_group_posix
{ {
test_group(const test_group&);
void operator=(const test_group&);
const char* name_; const char* name_;
typedef void (test_object<Data>::*testmethod)(); typedef void (test_object<Data>::*testmethod)();
...@@ -145,8 +167,10 @@ class test_group : public group_base, public test_group_posix ...@@ -145,8 +167,10 @@ class test_group : public group_base, public test_group_posix
enum seh_result enum seh_result
{ {
SEH_OK, SEH_OK,
#if defined(TUT_USE_SEH)
SEH_CTOR, SEH_CTOR,
SEH_TEST, SEH_TEST,
#endif
SEH_DUMMY SEH_DUMMY
}; };
...@@ -204,11 +228,16 @@ class test_group : public group_base, public test_group_posix ...@@ -204,11 +228,16 @@ class test_group : public group_base, public test_group_posix
{ {
try try
{ {
#if defined(TUT_USE_SEH)
if (delete_obj() == false) if (delete_obj() == false)
{ {
throw warning("destructor of test object raised" throw warning("destructor of test object raised"
" an SEH exception"); " an SEH exception");
} }
#else
bool d = delete_obj();
assert(d && "delete failed with SEH disabled: runtime bug?");
#endif
} }
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
...@@ -271,7 +300,9 @@ public: ...@@ -271,7 +300,9 @@ public:
* Creates and registers test group with specified name. * Creates and registers test group with specified name.
*/ */
test_group(const char* name) test_group(const char* name)
: name_(name) : name_(name),
tests_(),
current_test_()
{ {
// register itself // register itself
runner.get().register_group(name_,this); runner.get().register_group(name_,this);
...@@ -284,7 +315,9 @@ public: ...@@ -284,7 +315,9 @@ public:
* This constructor is used in self-test run only. * This constructor is used in self-test run only.
*/ */
test_group(const char* name, test_runner& another_runner) test_group(const char* name, test_runner& another_runner)
: name_(name) : name_(name),
tests_(),
current_test_()
{ {
// register itself // register itself
another_runner.register_group(name_, this); another_runner.register_group(name_, this);
...@@ -371,6 +404,7 @@ public: ...@@ -371,6 +404,7 @@ public:
{ {
switch (run_test_seh_(ti->second, obj, current_test_name, ti->first)) switch (run_test_seh_(ti->second, obj, current_test_name, ti->first))
{ {
#if defined(TUT_USE_SEH)
case SEH_CTOR: case SEH_CTOR:
throw bad_ctor("seh"); throw bad_ctor("seh");
break; break;
...@@ -378,7 +412,7 @@ public: ...@@ -378,7 +412,7 @@ public:
case SEH_TEST: case SEH_TEST:
throw seh("seh"); throw seh("seh");
break; break;
#endif
case SEH_DUMMY: case SEH_DUMMY:
tr.result = test_result::dummy; tr.result = test_result::dummy;
break; break;
...@@ -396,13 +430,13 @@ public: ...@@ -396,13 +430,13 @@ public:
catch (const tut_error& ex) catch (const tut_error& ex)
{ {
tr.result = ex.result(); tr.result = ex.result();
tr.exception_typeid = typeid(ex).name(); tr.exception_typeid = ex.type();
tr.message = ex.what(); tr.message = ex.what();
} }
catch (const std::exception& ex) catch (const std::exception& ex)
{ {
tr.result = test_result::ex; tr.result = test_result::ex;
tr.exception_typeid = typeid(ex).name(); tr.exception_typeid = type_name(ex);
tr.message = ex.what(); tr.message = ex.what();
} }
catch (...) catch (...)
...@@ -449,6 +483,7 @@ public: ...@@ -449,6 +483,7 @@ public:
{ {
#endif #endif
obj.get()->set_test_id(current_test_id); obj.get()->set_test_id(current_test_id);
obj.get()->set_test_group(name_);
(obj.get()->*tm)(); (obj.get()->*tm)();
#if defined(TUT_USE_SEH) #if defined(TUT_USE_SEH)
} }
...@@ -534,5 +569,5 @@ inline int handle_seh_(DWORD excode) ...@@ -534,5 +569,5 @@ inline int handle_seh_(DWORD excode)
#endif #endif
} }
#endif #endif // TUT_H_GUARD
#ifndef TUT_ASSERT_H_GUARD #ifndef TUT_ASSERT_H_GUARD
#define TUT_ASSERT_H_GUARD #define TUT_ASSERT_H_GUARD
#include <tut/tut_config.hpp>
#include "tut_exception.hpp"
#include <limits> #include <limits>
#include <iomanip> #include <iomanip>
#include <iterator>
#include <cassert>
#include <cmath>
#if defined(TUT_USE_POSIX) #if defined(TUT_USE_POSIX)
#include <errno.h> #include <errno.h>
#include <cstring> #include <cstring>
#endif #endif
#include "tut_exception.hpp"
namespace tut namespace tut
{ {
namespace detail namespace detail
{ {
template<typename M> 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; ss << msg;
if(!ss.str().empty()) if(!ss.str().empty())
{ {
str << ss.rdbuf() << ": "; str << msg << ": ";
} }
return str; return str;
...@@ -83,7 +88,7 @@ void ensure_not(const M& msg, bool cond) ...@@ -83,7 +88,7 @@ void ensure_not(const M& msg, bool cond)
* Tests two objects for being equal. * Tests two objects for being equal.
* Throws if false. * 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! * client code will not compile at all!
*/ */
template <typename M, typename LHS, typename RHS> template <typename M, typename LHS, typename RHS>
...@@ -91,42 +96,128 @@ void ensure_equals(const M& msg, const LHS& actual, const RHS& expected) ...@@ -91,42 +96,128 @@ void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
{ {
if (expected != actual) if (expected != actual)
{ {
std::stringstream ss; std::ostringstream ss;
detail::msg_prefix(ss,msg) detail::msg_prefix(ss,msg)
<< "expected '" << "expected `"
<< expected << expected
<< "' actual '" << "` actual `"
<< actual << actual
<< '\''; << "`";
throw failure(ss.str()); 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> template<typename M>
void ensure_equals(const M& msg, const double& actual, const double& expected, void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon)
const double& epsilon = std::numeric_limits<double>::epsilon())
{ {
const double diff = actual - expected; 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) detail::msg_prefix(ss,msg)
<< std::scientific << std::scientific
<< std::showpoint << std::showpoint
<< std::setprecision(16) << std::setprecision(16)
<< "expected " << expected << "expected `" << expected
<< " actual " << actual << "` actual `" << actual
<< " with precision " << epsilon; << "` with precision `" << epsilon << "`";
throw failure(ss.str()); 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. * Tests two objects for being at most in given distance one from another.
* Borders are excluded. * Borders are excluded.
...@@ -143,15 +234,15 @@ void ensure_distance(const M& msg, const T& actual, const T& expected, const T& ...@@ -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) if (expected-distance >= actual || expected+distance <= actual)
{ {
std::stringstream ss; std::ostringstream ss;
detail::msg_prefix(ss,msg) detail::msg_prefix(ss,msg)
<< " expected (" << " expected `"
<< expected-distance << expected-distance
<< " - " << "` - `"
<< expected+distance << expected+distance
<< ") actual '" << "` actual `"
<< actual << actual
<< '\''; << "`";
throw failure(ss.str()); throw failure(ss.str());
} }
} }
...@@ -169,7 +260,7 @@ void ensure_errno(const M& msg, bool cond) ...@@ -169,7 +260,7 @@ void ensure_errno(const M& msg, bool cond)
{ {
#if defined(TUT_USE_POSIX) #if defined(TUT_USE_POSIX)
char e[512]; char e[512];
std::stringstream ss; std::ostringstream ss;
detail::msg_prefix(ss,msg) detail::msg_prefix(ss,msg)
<< strerror_r(errno, e, sizeof(e)); << strerror_r(errno, e, sizeof(e));
throw failure(ss.str()); throw failure(ss.str());
...@@ -193,6 +284,20 @@ void fail(const M& msg) ...@@ -193,6 +284,20 @@ void fail(const M& msg)
throw failure(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 } // end of namespace
} }
......
#ifndef TUT_CONFIG_H_GUARD
#define TUT_CONFIG_H_GUARD
#define TUT_USE_RTTI 1
#endif
#ifndef TUT_CONSOLE_REPORTER #ifndef TUT_CONSOLE_REPORTER
#define TUT_CONSOLE_REPORTER #define TUT_CONSOLE_REPORTER
#include <tut/tut.hpp>
#include <tut.hpp>
#include <cassert> #include <cassert>
#if defined(TUT_USE_POSIX)
#include <sys/types.h>
#include <unistd.h>
#endif
/** /**
* Template Unit Tests Framework for C++. * Template Unit Tests Framework for C++.
* http://tut.dozen.ru * http://tut.dozen.ru
...@@ -38,8 +43,11 @@ std::ostream& operator<<(std::ostream& os, const tut::test_result& tr) ...@@ -38,8 +43,11 @@ std::ostream& operator<<(std::ostream& os, const tut::test_result& tr)
case tut::test_result::rethrown: case tut::test_result::rethrown:
os << '[' << tr.test << "=P]"; os << '[' << tr.test << "=P]";
break; break;
case tut::test_result::skipped:
os << '[' << tr.test << "=S]";
break;
case tut::test_result::dummy: case tut::test_result::dummy:
assert(!"Should never be called"); throw tut::tut_error("console reporter called for dummy test result");
} }
return os; return os;
...@@ -60,6 +68,8 @@ class console_reporter : public tut::callback ...@@ -60,6 +68,8 @@ class console_reporter : public tut::callback
not_passed_list not_passed; not_passed_list not_passed;
std::ostream& os; std::ostream& os;
console_reporter(const console_reporter &);
console_reporter &operator=(const console_reporter &);
public: public:
int ok_count; int ok_count;
...@@ -67,15 +77,33 @@ public: ...@@ -67,15 +77,33 @@ public:
int failures_count; int failures_count;
int terminations_count; int terminations_count;
int warnings_count; int warnings_count;
int skipped_count;
console_reporter() 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(); init();
} }
console_reporter(std::ostream& out) 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(); init();
} }
...@@ -114,11 +142,15 @@ public: ...@@ -114,11 +142,15 @@ public:
case test_result::term: case test_result::term:
terminations_count++; terminations_count++;
break; break;
case test_result::skipped:
skipped_count++;
break;
case tut::test_result::dummy: case tut::test_result::dummy:
assert(!"Should never be called"); assert( (tr.result != tut::test_result::dummy) && "Should never be called");
} // switch } // 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); not_passed.push_back(tr);
} }
...@@ -181,12 +213,12 @@ public: ...@@ -181,12 +213,12 @@ public:
{ {
if (tr.result == test_result::fail) if (tr.result == test_result::fail)
{ {
os << " failed assertion: \"" << tr.message << "\"" os << " failed assertion: `" << tr.message << "`"
<< std::endl; << std::endl;
} }
else else
{ {
os << " message: \"" << tr.message << "\"" os << " message: `" << tr.message << "`"
<< std::endl; << std::endl;
} }
} }
...@@ -214,11 +246,17 @@ public: ...@@ -214,11 +246,17 @@ public:
{ {
os << " warnings:" << warnings_count; os << " warnings:" << warnings_count;
}