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)();
...@@ -142,13 +164,15 @@ class test_group : public group_base, public test_group_posix ...@@ -142,13 +164,15 @@ class test_group : public group_base, public test_group_posix
tests tests_; tests tests_;
tests_iterator current_test_; tests_iterator current_test_;
enum seh_result enum seh_result
{ {
SEH_OK, SEH_OK,
SEH_CTOR, #if defined(TUT_USE_SEH)
SEH_TEST, SEH_CTOR,
SEH_DUMMY SEH_TEST,
}; #endif
SEH_DUMMY
};
/** /**
* Exception-in-destructor-safe smart-pointer class. * Exception-in-destructor-safe smart-pointer class.
...@@ -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);
...@@ -370,22 +403,23 @@ public: ...@@ -370,22 +403,23 @@ public:
try try
{ {
switch (run_test_seh_(ti->second, obj, current_test_name, ti->first)) switch (run_test_seh_(ti->second, obj, current_test_name, ti->first))
{ {
case SEH_CTOR: #if defined(TUT_USE_SEH)
throw bad_ctor("seh"); case SEH_CTOR:
break; throw bad_ctor("seh");
break;
case SEH_TEST:
throw seh("seh"); case SEH_TEST:
break; throw seh("seh");
break;
case SEH_DUMMY: #endif
tr.result = test_result::dummy; case SEH_DUMMY:
break; tr.result = test_result::dummy;
break;
case SEH_OK:
// ok case SEH_OK:
break; // ok
break;
} }
} }
catch (const rethrown& ex) catch (const rethrown& ex)
...@@ -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 (...)
...@@ -436,12 +470,12 @@ public: ...@@ -436,12 +470,12 @@ public:
__try __try
{ {
#endif #endif
if (obj.get() == 0) if (obj.get() == 0)
{ {
reset_holder_(obj); reset_holder_(obj);
} }
obj->called_method_was_a_dummy_test_ = false; obj->called_method_was_a_dummy_test_ = false;
#if defined(TUT_USE_SEH) #if defined(TUT_USE_SEH)
...@@ -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)
} }
...@@ -459,20 +494,20 @@ public: ...@@ -459,20 +494,20 @@ public:
} }
#endif #endif
if (obj->called_method_was_a_dummy_test_) if (obj->called_method_was_a_dummy_test_)
{ {
// do not call obj.release(); reuse object // do not call obj.release(); reuse object
return SEH_DUMMY; return SEH_DUMMY;
} }
current_test_name = obj->get_test_name(); current_test_name = obj->get_test_name();
obj.permit_throw(); obj.permit_throw();
obj.release(); obj.release();
#if defined(TUT_USE_SEH) #if defined(TUT_USE_SEH)
} }
__except(handle_seh_(::GetExceptionCode())) __except(handle_seh_(::GetExceptionCode()))
{ {
return SEH_CTOR; return SEH_CTOR;
} }
#endif #endif
return SEH_OK; return SEH_OK;
...@@ -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
...@@ -17,29 +22,32 @@ std::ostream& operator<<(std::ostream& os, const tut::test_result& tr) ...@@ -17,29 +22,32 @@ std::ostream& operator<<(std::ostream& os, const tut::test_result& tr)
{ {
switch(tr.result) switch(tr.result)
{ {
case tut::test_result::ok: case tut::test_result::ok:
os << '.'; os << '.';
break; break;
case tut::test_result::fail: case tut::test_result::fail:
os << '[' << tr.test << "=F]"; os << '[' << tr.test << "=F]";
break; break;
case tut::test_result::ex_ctor: case tut::test_result::ex_ctor:
os << '[' << tr.test << "=C]"; os << '[' << tr.test << "=C]";
break; break;
case tut::test_result::ex: case tut::test_result::ex:
os << '[' << tr.test << "=X]"; os << '[' << tr.test << "=X]";
break; break;
case tut::test_result::warn: case tut::test_result::warn:
os << '[' << tr.test << "=W]"; os << '[' << tr.test << "=W]";
break; break;
case tut::test_result::term: case tut::test_result::term:
os << '[' << tr.test << "=T]"; os << '[' << tr.test << "=T]";
break; break;
case tut::test_result::rethrown: case tut::test_result::rethrown:
os << '[' << tr.test << "=P]"; os << '[' << tr.test << "=P]";
break; break;
case tut::test_result::dummy: case tut::test_result::skipped:
assert(!"Should never be called"); os << '[' << tr.test << "=S]";
break;