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
#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
#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
}
......
#ifndef TUT_CONFIG_H_GUARD
#define TUT_CONFIG_H_GUARD
#define TUT_USE_RTTI 1
#endif
#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();
}
};
......
#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_ + "`");
}
}