add Chapter14

This commit is contained in:
Amar Mahmutbegovic
2024-11-19 21:29:22 +01:00
parent 49b062908b
commit b378383cf5
1393 changed files with 1058616 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
#include "AssertException.h"
#ifndef UNITTEST_NO_EXCEPTIONS
namespace UnitTest {
AssertException::AssertException()
{}
AssertException::~AssertException() throw()
{}
}
#endif

View File

@@ -0,0 +1,23 @@
#ifndef UNITTEST_ASSERTEXCEPTION_H
#define UNITTEST_ASSERTEXCEPTION_H
#include "Config.h"
#ifndef UNITTEST_NO_EXCEPTIONS
#include "HelperMacros.h"
#include <exception>
namespace UnitTest {
class UNITTEST_LINKAGE AssertException : public std::exception
{
public:
AssertException();
virtual ~AssertException() throw();
};
}
#endif
#endif

View File

@@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.5.0)
project(UnitTestpp LANGUAGES CXX)
add_library(UnitTestpp
AssertException.cpp
Checks.cpp
CompositeTestReporter.cpp
CurrentTest.cpp
DeferredTestReporter.cpp
DeferredTestResult.cpp
MemoryOutStream.cpp
ReportAssert.cpp
RequiredCheckException.cpp
RequiredCheckTestReporter.cpp
Test.cpp
TestDetails.cpp
TestList.cpp
TestReporter.cpp
TestReporterStdout.cpp
TestResults.cpp
TestRunner.cpp
ThrowingTestReporter.cpp
TimeConstraint.cpp
XmlTestReporter.cpp
)
target_include_directories(UnitTestpp SYSTEM INTERFACE ..)
if (WIN32)
target_sources(UnitTestpp PRIVATE Win32/TimeHelpers.cpp)
else ()
target_sources(UnitTestpp PRIVATE
Posix/SignalTranslator.cpp
Posix/TimeHelpers.cpp
)
endif ()
if ((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
target_compile_options(UnitTestpp PRIVATE -fexceptions)
endif ()
if (UNIX AND NOT APPLE)
# atomic is need on Linux with Clang
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(UnitTestpp PRIVATE atomic Threads::Threads)
elseif (NOT UNIX AND APPLE)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(UnitTestpp PRIVATE Threads::Threads)
endif ()

View File

@@ -0,0 +1,410 @@
#ifndef UNITTEST_CHECKMACROS_H
#define UNITTEST_CHECKMACROS_H
#include "HelperMacros.h"
#include "ExceptionMacros.h"
#include "Checks.h"
#include "AssertException.h"
#include "RequiredCheckException.h"
#include "MemoryOutStream.h"
#include "TestDetails.h"
#include "CurrentTest.h"
#include "ReportAssertImpl.h"
#define UNITTEST_CHECK(value) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
if (!UnitTest::Check(value)) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK(" #value ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK(" #value ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_FALSE(value) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
if (!UnitTest::CheckFalse(value)) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK(" #value ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK(" #value ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_EQUAL(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_EQUAL(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_EQUAL_HEX(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckEqualHex(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_EQUAL(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_NOT_EQUAL(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckNotEqual(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_EQUAL(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_FALSE_EQUAL_HEX(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckNotEqualHex(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_EQUAL(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_CLOSE(expected, actual, tolerance) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_CLOSE(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_CLOSE(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_FLOAT_SAME(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, 0, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_FLOAT_SAME(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_FLOAT_SAME(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_FLOAT_DIFFERENT(expected, actual) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckNotClose(*UnitTest::CurrentTest::Results(), expected, actual, 0, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_FLOAT_DIFFERENT(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_FLOAT_DIFFERENT(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_ARRAY_EQUAL(expected, actual, count) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), expected, actual, count, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_ARRAY_EQUAL(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_ARRAY_EQUAL(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UNITTEST_IMPL_TRY \
({ \
UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \
}) \
UNITTEST_IMPL_RETHROW (UnitTest::RequiredCheckException) \
UNITTEST_IMPL_CATCH (std::exception, exc, \
{ \
UnitTest::MemoryOutStream UnitTest_message; \
UnitTest_message << "Unhandled exception (" << exc.what() << ") in CHECK_ARRAY2D_CLOSE(" #expected ", " #actual ")"; \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
UnitTest_message.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
"Unhandled exception in CHECK_ARRAY2D_CLOSE(" #expected ", " #actual ")"); \
}) \
UNITTEST_MULTILINE_MACRO_END
#ifndef UNITTEST_DISABLE_SHORT_MACROS
#ifdef CHECK
#error CHECK already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK instead
#else
#define CHECK(value) UNITTEST_CHECK((value))
#endif
#ifdef CHECK_TRUE
#error CHECK_TRUE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_TRUE instead
#else
#define CHECK_TRUE(value) UNITTEST_CHECK((value))
#endif
#ifdef CHECK_FALSE
#error CHECK_FALSE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_FALSE instead
#else
#define CHECK_FALSE(value) UNITTEST_CHECK_FALSE((value))
#endif
#ifdef CHECK_EQUAL
#error CHECK_EQUAL already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_EQUAL instead
#else
#define CHECK_EQUAL(expected, actual) UNITTEST_CHECK_EQUAL((expected), (actual))
#endif
#ifdef CHECK_EQUAL_HEX
#error CHECK_EQUAL_HEX already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_EQUAL_HEX instead
#else
#define CHECK_EQUAL_HEX(expected, actual) UNITTEST_CHECK_EQUAL_HEX((expected), (actual))
#endif
#ifdef CHECK_NOT_EQUAL
#error CHECK_NOT_EQUAL already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_NOT_EQUAL instead
#else
#define CHECK_NOT_EQUAL(expected, actual) UNITTEST_CHECK_NOT_EQUAL((expected), (actual))
#endif
#ifdef CHECK_NOT_EQUAL_HEX
#error CHECK_NOT_EQUAL_HEX already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_NOT_EQUAL_HEX instead
#else
#define CHECK_NOT_EQUAL_HEX(expected, actual) UNITTEST_CHECK_NOT_EQUAL_HEX((expected), (actual))
#endif
#ifdef CHECK_CLOSE
#error CHECK_CLOSE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_CLOSE instead
#else
#define CHECK_CLOSE(expected, actual, tolerance) UNITTEST_CHECK_CLOSE((expected), (actual), (tolerance))
#endif
#ifdef CHECK_FLOAT_SAME
#error CHECK_FLOAT_SAME already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_FLOAT_SAME instead
#else
#define CHECK_FLOAT_SAME(expected, actual) UNITTEST_CHECK_FLOAT_SAME((expected), (actual))
#endif
#ifdef CHECK_FLOAT_DIFFERENT
#error CHECK_FLOAT_DIFFERENT already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_FLOAT_DIFFERENT instead
#else
#define CHECK_FLOAT_DIFFERENT(expected, actual) UNITTEST_CHECK_FLOAT_DIFFERENT((expected), (actual))
#endif
#ifdef CHECK_ARRAY_EQUAL
#error CHECK_ARRAY_EQUAL already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_ARRAY_EQUAL instead
#else
#define CHECK_ARRAY_EQUAL(expected, actual, count) UNITTEST_CHECK_ARRAY_EQUAL((expected), (actual), (count))
#endif
#ifdef CHECK_ARRAY_CLOSE
#error CHECK_ARRAY_CLOSE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_ARRAY_CLOSE instead
#else
#define CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) UNITTEST_CHECK_ARRAY_CLOSE((expected), (actual), (count), (tolerance))
#endif
#ifdef CHECK_ARRAY2D_CLOSE
#error CHECK_ARRAY2D_CLOSE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_ARRAY2D_CLOSE instead
#else
#define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) UNITTEST_CHECK_ARRAY2D_CLOSE((expected), (actual), (rows), (columns), (tolerance))
#endif
#endif
// CHECK_THROW and CHECK_ASSERT only exist when UNITTEST_NO_EXCEPTIONS isn't defined (see config.h)
#ifndef UNITTEST_NO_EXCEPTIONS
#define UNITTEST_CHECK_THROW(expression, ExpectedExceptionType) \
UNITTEST_MULTILINE_MACRO_BEGIN \
bool caught_ = false; \
try { expression; } \
catch (ExpectedExceptionType const&) { caught_ = true; } \
catch (...) {} \
if (!caught_) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_NO_THROW(expression) \
UNITTEST_MULTILINE_MACRO_BEGIN \
bool caught_ = false; \
try { expression; } \
catch (...) { caught_ = true; } \
if (caught_) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), "Unexpected exception thrown"); \
UNITTEST_MULTILINE_MACRO_END
#define UNITTEST_CHECK_ASSERT(expression) \
UNITTEST_MULTILINE_MACRO_BEGIN \
UnitTest::Detail::ExpectAssert(true); \
CHECK_THROW(expression, UnitTest::AssertException); \
UnitTest::Detail::ExpectAssert(false); \
UNITTEST_MULTILINE_MACRO_END
#endif
#ifndef UNITTEST_DISABLE_SHORT_MACROS
#ifdef CHECK_THROW
#error CHECK_THROW already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_THROW instead
#else
#define CHECK_THROW UNITTEST_CHECK_THROW
#endif
#ifdef CHECK_NO_THROW
#error CHECK_NO_THROW already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_NO_THROW instead
#else
#define CHECK_NO_THROW UNITTEST_CHECK_NO_THROW
#endif
#ifdef CHECK_ASSERT
#error CHECK_ASSERT already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_CHECK_ASSERT instead
#else
#define CHECK_ASSERT UNITTEST_CHECK_ASSERT
#endif
#endif
#define CHECK_MESSAGE(m1) std::cerr << (m1) << "\n";
#define CHECK_MESSAGE1(m1) std::cerr << (m1) << "\n";
#define CHECK_MESSAGE2(m1, m2) std::cerr << (m1) << (m2) << "\n";
#define CHECK_MESSAGE3(m1, m2, m3) std::cerr << (m1) << (m2) << (m3) << "\n";
#define CHECK_MESSAGE4(m1, m2, m3, m4) std::cerr << (m1) << (m2) << (m3) << (m4) << "\n";
#define CHECK_MESSAGE_IF(b, m1) { if (b) std::cerr << (m1) << "\n"; }
#define CHECK_MESSAGE1_IF(m1) { if (b) std::cerr << (m1) << "\n"; }
#define CHECK_MESSAGE2_IF(m1, m2) { if (b) std::cerr << (m1) << (m2) << "\n"; }
#define CHECK_MESSAGE3_IF(m1, m2, m3) { if (b) std::cerr << (m1) << (m2) << (m3) << "\n"; }
#define CHECK_MESSAGE4_IF(m1, m2, m3, m4) { if (b) std::cerr << (m1) << (m2) << (m3) << (m4) << "\n"; }
#endif

View File

@@ -0,0 +1,50 @@
#include "Checks.h"
#include <cstring>
namespace UnitTest {
namespace {
void CheckStringsEqual(TestResults& results, char const* expected, char const* actual,
TestDetails const& details)
{
using namespace std;
if ((expected && actual) ? strcmp(expected, actual) : (expected || actual))
{
UnitTest::MemoryOutStream stream;
stream << "Expected " << (expected ? expected : "<NULLPTR>") << " but was " << (actual ? actual : "<NULLPTR>");
results.OnTestFailure(details, stream.GetText());
}
}
}
void CheckEqual(TestResults& results, char const* expected, char const* actual,
TestDetails const& details)
{
CheckStringsEqual(results, expected, actual, details);
}
void CheckEqual(TestResults& results, char* expected, char* actual,
TestDetails const& details)
{
CheckStringsEqual(results, expected, actual, details);
}
void CheckEqual(TestResults& results, char* expected, char const* actual,
TestDetails const& details)
{
CheckStringsEqual(results, expected, actual, details);
}
void CheckEqual(TestResults& results, char const* expected, char* actual,
TestDetails const& details)
{
CheckStringsEqual(results, expected, actual, details);
}
}

View File

@@ -0,0 +1,389 @@
#ifndef UNITTEST_CHECKS_H
#define UNITTEST_CHECKS_H
#if defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
#if defined(__clang__) || defined(__llvm__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wfloat-equal"
#endif
#include "Config.h"
#include "TestResults.h"
#include "MemoryOutStream.h"
#include<iomanip>
namespace UnitTest
{
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, std::string>::type
DisplayValue(const T& c)
{
std::ostringstream oss;
oss << c;
return oss.str();
}
template <>
inline std::string DisplayValue(const char& c)
{
typedef std::char_traits<char>::int_type type;
std::ostringstream oss;
oss << type(c) << " ('" << c << "')";
return oss.str();
}
#if (__cplusplus >= 202002L)
template <>
inline std::string DisplayValue(const char8_t& c)
{
typedef std::char_traits<char8_t>::int_type type;
std::ostringstream oss;
oss << type(c);
return oss.str();
}
#endif
template <>
inline std::string DisplayValue(const wchar_t& c)
{
typedef std::char_traits<wchar_t>::int_type type;
std::ostringstream oss;
oss << type(c);
return oss.str();
}
#if (__cplusplus >= 201103L)
template <>
inline std::string DisplayValue(const char16_t& c)
{
typedef std::char_traits<char16_t>::int_type type;
std::ostringstream oss;
oss << type(c);
return oss.str();
}
template <>
inline std::string DisplayValue(const char32_t& c)
{
typedef std::char_traits<char32_t>::int_type type;
std::ostringstream oss;
oss << type(c);
return oss.str();
}
#endif
template <typename T>
std::string DisplayValue(const T* c)
{
std::ostringstream oss;
oss << c;
return oss.str();
}
template <>
inline std::string DisplayValue(const char* c)
{
std::ostringstream oss;
oss << c;
return oss.str();
}
#if (__cplusplus >= 202002L)
template <>
inline std::string DisplayValue(const char8_t* c)
{
std::ostringstream oss;
oss << static_cast<const void*>(c);
return oss.str();
}
#endif
template <>
inline std::string DisplayValue(const wchar_t* c)
{
std::ostringstream oss;
oss << static_cast<const void*>(c);
return oss.str();
}
#if (__cplusplus >= 201103L)
template <>
inline std::string DisplayValue(const char16_t* c)
{
std::ostringstream oss;
oss << static_cast<const void*>(c);
return oss.str();
}
template <>
inline std::string DisplayValue(const char32_t* c)
{
std::ostringstream oss;
oss << static_cast<const void*>(c);
return oss.str();
}
#endif
template< typename Value >
bool Check(Value const& value)
{
return !!value; // doing double negative to avoid silly VS warnings
}
template< typename Value >
bool CheckFalse(Value const& value)
{
return !value;
}
#if __cplusplus >= 201103L
template< typename Expected, typename Actual >
void CheckEqual(TestResults& results, Expected&& expected, Actual&& actual, TestDetails const& details)
{
if (!(expected == actual))
{
UnitTest::MemoryOutStream stream;
stream << "Expected "
<< DisplayValue(expected) << " but was " << DisplayValue(actual);
results.OnTestFailure(details, stream.GetText());
}
}
#else
template< typename Expected, typename Actual >
void CheckEqual(TestResults& results, Expected const& expected, Actual const& actual, TestDetails const& details)
{
if (!(expected == actual))
{
UnitTest::MemoryOutStream stream;
stream << "Expected "
<< DisplayValue(expected) << " but was " << DisplayValue(actual);
results.OnTestFailure(details, stream.GetText());
}
}
#endif
template< typename Expected, typename Actual >
void CheckEqualHex(TestResults& results, Expected const& expected, Actual const& actual, TestDetails const& details)
{
if (!(expected == actual))
{
UnitTest::MemoryOutStream stream;
stream << std::hex << std::uppercase << std::setfill('0')
<< "Expected 0x" << std::setw(2 * sizeof(Expected)) << (expected & ~(typename std::make_unsigned<Expected>::type(0)))
<< " but was 0x" << std::setw(2 * sizeof(Actual)) << (actual & ~(typename std::make_unsigned<Actual>::type(0)));
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual >
void CheckNotEqual(TestResults& results, Expected const& expected, Actual const& actual, TestDetails const& details)
{
if (expected == actual)
{
UnitTest::MemoryOutStream stream;
stream << "Expected not equal, but both values are" << actual;
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual >
void CheckNotEqualHex(TestResults& results, Expected const& expected, Actual const& actual, TestDetails const& details)
{
if (expected == actual)
{
UnitTest::MemoryOutStream stream;
stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2 * sizeof(Actual))
<< "Expected not equal, but both values are " << (actual & ~(typename std::make_unsigned<Actual>::type(0)));
results.OnTestFailure(details, stream.GetText());
}
}
UNITTEST_LINKAGE void CheckEqual(TestResults& results, char const* expected, char const* actual, TestDetails const& details);
UNITTEST_LINKAGE void CheckEqual(TestResults& results, char* expected, char* actual, TestDetails const& details);
UNITTEST_LINKAGE void CheckEqual(TestResults& results, char* expected, char const* actual, TestDetails const& details);
UNITTEST_LINKAGE void CheckEqual(TestResults& results, char const* expected, char* actual, TestDetails const& details);
template< typename Expected, typename Actual, typename Tolerance >
bool AreClose(Expected const& expected, Actual const& actual, Tolerance const& tolerance)
{
return (actual >= (expected - tolerance)) && (actual <= (expected + tolerance));
}
template< typename Expected, typename Actual, typename Tolerance >
void CheckClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance,
TestDetails const& details)
{
if (!AreClose(expected, actual, tolerance))
{
UnitTest::MemoryOutStream stream;
stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual;
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual, typename Tolerance >
void CheckNotClose(TestResults& results, Expected const& expected, Actual const& actual, Tolerance const& tolerance,
TestDetails const& details)
{
if (AreClose(expected, actual, tolerance))
{
UnitTest::MemoryOutStream stream;
stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual;
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual >
void CheckArrayEqual(TestResults& results, Expected const& expected, Actual const& actual,
size_t const count, TestDetails const& details)
{
bool equal = true;
for (size_t i = 0; i < count; ++i)
equal &= (expected[i] == actual[i]);
if (!equal)
{
UnitTest::MemoryOutStream stream;
stream << "Expected [ ";
for (size_t expectedIndex = 0; expectedIndex < count; ++expectedIndex)
stream << DisplayValue(expected[expectedIndex]) << " ";
stream << "] but was [ ";
for (size_t actualIndex = 0; actualIndex < count; ++actualIndex)
stream << DisplayValue(actual[actualIndex]) << " ";
stream << "]";
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual, typename Tolerance >
bool ArrayAreClose(Expected const& expected, Actual const& actual, size_t const count, Tolerance const& tolerance)
{
bool equal = true;
for (size_t i = 0; i < count; ++i)
equal &= AreClose(expected[i], actual[i], tolerance);
return equal;
}
template< typename Expected, typename Actual, typename Tolerance >
void CheckArrayClose(TestResults& results, Expected const& expected, Actual const& actual,
size_t const count, Tolerance const& tolerance, TestDetails const& details)
{
bool equal = ArrayAreClose(expected, actual, count, tolerance);
if (!equal)
{
UnitTest::MemoryOutStream stream;
stream << "Expected [ ";
for (size_t expectedIndex = 0; expectedIndex < count; ++expectedIndex)
stream << expected[expectedIndex] << " ";
stream << "] +/- " << tolerance << " but was [ ";
for (size_t actualIndex = 0; actualIndex < count; ++actualIndex)
stream << actual[actualIndex] << " ";
stream << "]";
results.OnTestFailure(details, stream.GetText());
}
}
template< typename Expected, typename Actual, typename Tolerance >
void CheckArray2DClose(TestResults& results, Expected const& expected, Actual const& actual,
size_t const rows, size_t const columns, Tolerance const& tolerance, TestDetails const& details)
{
bool equal = true;
for (size_t i = 0; i < rows; ++i)
equal &= ArrayAreClose(expected[i], actual[i], columns, tolerance);
if (!equal)
{
UnitTest::MemoryOutStream stream;
stream << "Expected [ ";
for (size_t expectedRow = 0; expectedRow < rows; ++expectedRow)
{
stream << "[ ";
for (size_t expectedColumn = 0; expectedColumn < columns; ++expectedColumn)
stream << expected[expectedRow][expectedColumn] << " ";
stream << "] ";
}
stream << "] +/- " << tolerance << " but was [ ";
for (size_t actualRow = 0; actualRow < rows; ++actualRow)
{
stream << "[ ";
for (size_t actualColumn = 0; actualColumn < columns; ++actualColumn)
stream << actual[actualRow][actualColumn] << " ";
stream << "] ";
}
stream << "]";
results.OnTestFailure(details, stream.GetText());
}
}
}
#if defined(__GNUC__) && !defined(__clang__) && !defined(__llvm__)
#pragma GCC diagnostic pop
#endif
#if defined(__clang__) || defined(__llvm__)
#pragma clang diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,66 @@
#include "CompositeTestReporter.h"
#include <cstddef>
namespace UnitTest {
CompositeTestReporter::CompositeTestReporter()
: m_reporterCount(0)
{}
int CompositeTestReporter::GetReporterCount() const
{
return m_reporterCount;
}
bool CompositeTestReporter::AddReporter(TestReporter* reporter)
{
if (m_reporterCount == kMaxReporters)
return false;
m_reporters[m_reporterCount++] = reporter;
return true;
}
bool CompositeTestReporter::RemoveReporter(TestReporter* reporter)
{
for (int index = 0; index < m_reporterCount; ++index)
{
if (m_reporters[index] == reporter)
{
m_reporters[index] = m_reporters[m_reporterCount - 1];
--m_reporterCount;
return true;
}
}
return false;
}
void CompositeTestReporter::ReportFailure(TestDetails const& details, char const* failure)
{
for (int index = 0; index < m_reporterCount; ++index)
m_reporters[index]->ReportFailure(details, failure);
}
void CompositeTestReporter::ReportTestStart(TestDetails const& test)
{
for (int index = 0; index < m_reporterCount; ++index)
m_reporters[index]->ReportTestStart(test);
}
void CompositeTestReporter::ReportTestFinish(TestDetails const& test, float secondsElapsed)
{
for (int index = 0; index < m_reporterCount; ++index)
m_reporters[index]->ReportTestFinish(test, secondsElapsed);
}
void CompositeTestReporter::ReportSummary(int totalTestCount,
int failedTestCount,
int failureCount,
float secondsElapsed)
{
for (int index = 0; index < m_reporterCount; ++index)
m_reporters[index]->ReportSummary(totalTestCount, failedTestCount, failureCount, secondsElapsed);
}
}

View File

@@ -0,0 +1,34 @@
#ifndef UNITTEST_COMPOSITETESTREPORTER_H
#define UNITTEST_COMPOSITETESTREPORTER_H
#include "TestReporter.h"
namespace UnitTest {
class UNITTEST_LINKAGE CompositeTestReporter : public TestReporter
{
public:
CompositeTestReporter();
int GetReporterCount() const;
bool AddReporter(TestReporter* reporter);
bool RemoveReporter(TestReporter* reporter);
virtual void ReportTestStart(TestDetails const& test);
virtual void ReportFailure(TestDetails const& test, char const* failure);
virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed);
virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed);
private:
enum { kMaxReporters = 16 };
TestReporter* m_reporters[kMaxReporters];
int m_reporterCount;
// revoked
CompositeTestReporter(const CompositeTestReporter&);
CompositeTestReporter& operator =(const CompositeTestReporter&);
};
}
#endif

View File

@@ -0,0 +1,84 @@
#ifndef UNITTEST_CONFIG_H
#define UNITTEST_CONFIG_H
// Standard defines documented here: http://predef.sourceforge.net
#if defined(_MSC_VER)
#pragma warning(disable:4702)// unreachable code
#pragma warning(disable:4722)// destructor never returns, potential memory leak
#if (_MSC_VER == 1200) // VC6
#define UNITTEST_COMPILER_IS_MSVC6
#pragma warning(disable:4786)
#pragma warning(disable:4290)
#endif
#ifdef _USRDLL
#define UNITTEST_WIN32_DLL
#endif
#define UNITTEST_WIN32
#endif
#if defined(unix) || defined(__unix__) || defined(__unix) || defined(linux) || \
defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) \
|| defined (__HAIKU__) || defined(_AIX)
#define UNITTEST_POSIX
#endif
#if defined(__MINGW32__)
#define UNITTEST_MINGW
#endif
// By default, MemoryOutStream is implemented in terms of std::ostringstream.
// This is useful if you are using the CHECK macros on objects that have something like this defined:
// std::ostringstream& operator<<(std::ostringstream& s, const YourObject& value)
//
// On the other hand, it can be more expensive.
// Un-comment this line to use the custom MemoryOutStream (no deps on std::ostringstream).
// #define UNITTEST_USE_CUSTOM_STREAMS
// Developer note: This dual-macro setup is to preserve compatibility with UnitTest++ 1.4 users
// who may have used or defined UNITTEST_USE_CUSTOM_STREAMS outside of this configuration file, as
// well as Google Code HEAD users that may have used or defined
// UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM outside of this configuration file.
#ifndef UNITTEST_USE_CUSTOM_STREAMS
#define UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM
#endif
// DeferredTestReporter uses the STL to collect test results for subsequent export by reporters like
// XmlTestReporter. If you don't want to use this functionality, uncomment this line and no STL
// headers or code will be compiled into UnitTest++
//#define UNITTEST_NO_DEFERRED_REPORTER
// By default, asserts that you report via UnitTest::ReportAssert() abort the current test and
// continue to the next one by throwing an exception, which unwinds the stack naturally, destroying
// all auto variables on its way back down. If you don't want to (or can't) use exceptions for your
// platform/compiler, uncomment this line. All exception code will be removed from UnitTest++,
// assert recovery will be done via setjmp/longjmp, and NO correct stack unwinding will happen!
//#define UNITTEST_NO_EXCEPTIONS
// std namespace qualification: used for functions like strcpy that
// may live in std:: namespace (cstring header).
#if defined( UNITTEST_COMPILER_IS_MSVC6 )
#define UNIITEST_NS_QUAL_STD(x) x
#else
#define UNIITEST_NS_QUAL_STD(x) ::std::x
#endif
// By default, UnitTest++ will attempt to define "short" macro names like CHECK and CHECK_EQUAL
// for "public" interface macros etc. Defining UNITTEST_DISABLE_SHORT_MACROS in your project
// will disable this behavior, leaving only the longer macros "namespaced" with the UNITTEST_
// prefix.
//
// "Internal" utility macros will only have the UNITTEST_IMPL_ prefix.
// #define UNITTEST_DISABLE_SHORT_MACROS
#endif

View File

@@ -0,0 +1,18 @@
#include "CurrentTest.h"
#include <cstddef>
namespace UnitTest {
UNITTEST_LINKAGE TestResults*& CurrentTest::Results()
{
static TestResults* testResults = NULL;
return testResults;
}
UNITTEST_LINKAGE const TestDetails*& CurrentTest::Details()
{
static const TestDetails* testDetails = NULL;
return testDetails;
}
}

View File

@@ -0,0 +1,19 @@
#ifndef UNITTEST_CURRENTTESTRESULTS_H
#define UNITTEST_CURRENTTESTRESULTS_H
#include "HelperMacros.h"
namespace UnitTest {
class TestResults;
class TestDetails;
namespace CurrentTest
{
UNITTEST_LINKAGE TestResults*& Results();
UNITTEST_LINKAGE const TestDetails*& Details();
}
}
#endif

View File

@@ -0,0 +1,33 @@
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "DeferredTestReporter.h"
#include "TestDetails.h"
using namespace UnitTest;
void DeferredTestReporter::ReportTestStart(TestDetails const& details)
{
m_results.push_back(DeferredTestResult(details.suiteName, details.testName));
}
void DeferredTestReporter::ReportFailure(TestDetails const& details, char const* failure)
{
DeferredTestResult& r = m_results.back();
r.failed = true;
r.failures.push_back(DeferredTestFailure(details.lineNumber, failure));
r.failureFile = details.filename;
}
void DeferredTestReporter::ReportTestFinish(TestDetails const&, float secondsElapsed)
{
DeferredTestResult& r = m_results.back();
r.timeElapsed = secondsElapsed;
}
DeferredTestReporter::DeferredTestResultList& DeferredTestReporter::GetResults()
{
return m_results;
}
#endif

View File

@@ -0,0 +1,35 @@
#ifndef UNITTEST_DEFERREDTESTREPORTER_H
#define UNITTEST_DEFERREDTESTREPORTER_H
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "TestReporter.h"
#include "DeferredTestResult.h"
#include <vector>
UNITTEST_STDVECTOR_LINKAGE(UnitTest::DeferredTestResult);
namespace UnitTest
{
class UNITTEST_LINKAGE DeferredTestReporter : public TestReporter
{
public:
virtual void ReportTestStart(TestDetails const& details);
virtual void ReportFailure(TestDetails const& details, char const* failure);
virtual void ReportTestFinish(TestDetails const& details, float secondsElapsed);
typedef std::vector< DeferredTestResult > DeferredTestResultList;
DeferredTestResultList& GetResults();
private:
DeferredTestResultList m_results;
};
}
#endif
#endif

View File

@@ -0,0 +1,43 @@
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "DeferredTestResult.h"
#include <cstring>
namespace UnitTest
{
DeferredTestFailure::DeferredTestFailure()
: lineNumber(-1)
{
failureStr[0] = '\0';
}
DeferredTestFailure::DeferredTestFailure(int lineNumber_, const char* failureStr_)
: lineNumber(lineNumber_)
{
UNIITEST_NS_QUAL_STD(strcpy)(failureStr, failureStr_);
}
DeferredTestResult::DeferredTestResult()
: suiteName("")
, testName("")
, failureFile("")
, timeElapsed(0.0f)
, failed(false)
{}
DeferredTestResult::DeferredTestResult(char const* suite, char const* test)
: suiteName(suite)
, testName(test)
, failureFile("")
, timeElapsed(0.0f)
, failed(false)
{}
DeferredTestResult::~DeferredTestResult()
{}
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef UNITTEST_DEFERREDTESTRESULT_H
#define UNITTEST_DEFERREDTESTRESULT_H
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "HelperMacros.h"
#include <string>
#include <vector>
namespace UnitTest
{
class UNITTEST_LINKAGE DeferredTestFailure
{
public:
DeferredTestFailure();
DeferredTestFailure(int lineNumber_, const char* failureStr_);
int lineNumber;
char failureStr[1024];
};
}
UNITTEST_STDVECTOR_LINKAGE(UnitTest::DeferredTestFailure);
namespace UnitTest
{
class UNITTEST_LINKAGE DeferredTestResult
{
public:
DeferredTestResult();
DeferredTestResult(char const* suite, char const* test);
~DeferredTestResult();
std::string suiteName;
std::string testName;
std::string failureFile;
typedef std::vector< DeferredTestFailure > FailureVec;
FailureVec failures;
float timeElapsed;
bool failed;
};
}
#endif
#endif

View File

@@ -0,0 +1,20 @@
#ifndef UNITTEST_EXCEPTIONMACROS_H
#define UNITTEST_EXCEPTIONMACROS_H
#include "Config.h"
#ifndef UNITTEST_NO_EXCEPTIONS
#define UNITTEST_IMPL_TRY(x) try x
#define UNITTEST_IMPL_THROW(x) throw x
#define UNITTEST_IMPL_RETHROW(ExceptionType) catch(ExceptionType&) { throw; }
#define UNITTEST_IMPL_CATCH(ExceptionType, ExceptionName, CatchBody) catch(ExceptionType& ExceptionName) CatchBody
#define UNITTEST_IMPL_CATCH_ALL(CatchBody) catch(...) CatchBody
#else
#define UNITTEST_IMPL_TRY(x) x
#define UNITTEST_IMPL_THROW(x)
#define UNITTEST_IMPL_RETHROW(ExceptionType)
#define UNITTEST_IMPL_CATCH(ExceptionType, ExceptionName, CatchBody)
#define UNITTEST_IMPL_CATCH_ALL(CatchBody)
#endif
#endif

View File

@@ -0,0 +1,61 @@
#ifndef UNITTEST_EXECUTE_TEST_H
#define UNITTEST_EXECUTE_TEST_H
#include "Config.h"
#include "ExceptionMacros.h"
#include "TestDetails.h"
#include "TestResults.h"
#include "MemoryOutStream.h"
#include "AssertException.h"
#include "RequiredCheckException.h"
#include "CurrentTest.h"
#ifdef UNITTEST_NO_EXCEPTIONS
#include "ReportAssertImpl.h"
#endif
#ifdef UNITTEST_POSIX
#include "Posix/SignalTranslator.h"
#endif
namespace UnitTest {
template< typename T >
void ExecuteTest(T& testObject, TestDetails const& details, bool isMockTest)
{
if (isMockTest == false)
CurrentTest::Details() = &details;
#ifdef UNITTEST_NO_EXCEPTIONS
if (UNITTEST_SET_ASSERT_JUMP_TARGET() == 0)
{
#endif
#ifndef UNITTEST_POSIX
UNITTEST_IMPL_TRY({ testObject.RunImpl(); })
#else
UNITTEST_IMPL_TRY
({
UNITTEST_THROW_SIGNALS_POSIX_ONLY
testObject.RunImpl();
})
#endif
UNITTEST_IMPL_CATCH(RequiredCheckException, exc, { (void)exc; })
UNITTEST_IMPL_CATCH(AssertException, exc, { (void)exc; })
UNITTEST_IMPL_CATCH(std::exception, exc,
{
MemoryOutStream stream;
stream << "Unhandled exception: " << exc.what();
CurrentTest::Results()->OnTestFailure(details, stream.GetText());
})
UNITTEST_IMPL_CATCH_ALL
({
CurrentTest::Results()->OnTestFailure(details, "Unhandled exception: test crashed");
})
#ifdef UNITTEST_NO_EXCEPTIONS
}
#endif
}
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef UNITTEST_HELPERMACROS_H
#define UNITTEST_HELPERMACROS_H
#include "Config.h"
#define UNITTEST_MULTILINE_MACRO_BEGIN do {
#if defined(UNITTEST_WIN32) && !defined(UNITTEST_COMPILER_IS_MSVC6)
#define UNITTEST_MULTILINE_MACRO_END \
} __pragma(warning(push)) __pragma(warning(disable: 4127)) while (0) __pragma(warning(pop))
#else
#define UNITTEST_MULTILINE_MACRO_END } while(0)
#endif
#ifdef UNITTEST_WIN32_DLL
#define UNITTEST_IMPORT __declspec(dllimport)
#define UNITTEST_EXPORT __declspec(dllexport)
#ifdef UNITTEST_DLL_EXPORT
#define UNITTEST_LINKAGE UNITTEST_EXPORT
#define UNITTEST_IMPEXP_TEMPLATE
#else
#define UNITTEST_LINKAGE UNITTEST_IMPORT
#define UNITTEST_IMPEXP_TEMPLATE extern
#endif
#define UNITTEST_STDVECTOR_LINKAGE(T) \
__pragma(warning(push)) \
__pragma(warning(disable: 4231)) \
UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::allocator< T >; \
UNITTEST_IMPEXP_TEMPLATE template class UNITTEST_LINKAGE std::vector< T >; \
__pragma(warning(pop))
#else
#define UNITTEST_IMPORT
#define UNITTEST_EXPORT
#define UNITTEST_LINKAGE
#define UNITTEST_IMPEXP_TEMPLATE
#define UNITTEST_STDVECTOR_LINKAGE(T)
#endif
#ifdef UNITTEST_WIN32
#define UNITTEST_JMPBUF jmp_buf
#define UNITTEST_SETJMP setjmp
#define UNITTEST_LONGJMP longjmp
#elif defined UNITTEST_POSIX
#define UNITTEST_JMPBUF std::jmp_buf
#define UNITTEST_SETJMP setjmp
#define UNITTEST_LONGJMP std::longjmp
#endif
#endif

View File

@@ -0,0 +1,218 @@
#include "MemoryOutStream.h"
#ifdef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM
namespace UnitTest {
char const* MemoryOutStream::GetText() const
{
m_text = this->str();
return m_text.c_str();
}
void MemoryOutStream::Clear()
{
this->str(std::string());
m_text = this->str();
}
#ifdef UNITTEST_COMPILER_IS_MSVC6
#define snprintf _snprintf
template<typename ValueType>
std::ostream& FormatToStream(std::ostream& stream, char const* format, ValueType const& value)
{
using namespace std;
const size_t BUFFER_SIZE=32;
char txt[BUFFER_SIZE];
snprintf(txt, BUFFER_SIZE, format, value);
return stream << txt;
}
std::ostream& operator<<(std::ostream& stream, __int64 const n)
{
return FormatToStream(stream, "%I64d", n);
}
std::ostream& operator<<(std::ostream& stream, unsigned __int64 const n)
{
return FormatToStream(stream, "%I64u", n);
}
#endif
}
#else
#include <cstring>
#include <cstdio>
#if _MSC_VER
#define snprintf _snprintf
#endif
namespace UnitTest {
namespace {
template<typename ValueType>
void FormatToStream(MemoryOutStream& stream, char const* format, ValueType const& value)
{
using namespace std;
const size_t BUFFER_SIZE=32;
char txt[BUFFER_SIZE];
snprintf(txt, BUFFER_SIZE, format, value);
stream << txt;
}
int RoundUpToMultipleOfPow2Number (int n, int pow2Number)
{
return (n + (pow2Number - 1)) & ~(pow2Number - 1);
}
}
MemoryOutStream::MemoryOutStream(int const size)
: m_capacity (0)
, m_buffer (0)
{
GrowBuffer(size);
}
MemoryOutStream::~MemoryOutStream()
{
delete [] m_buffer;
}
void MemoryOutStream::Clear()
{
m_buffer[0] = '\0';
}
char const* MemoryOutStream::GetText() const
{
return m_buffer;
}
MemoryOutStream& MemoryOutStream::operator <<(char const* txt)
{
using namespace std;
int const bytesLeft = m_capacity - (int)strlen(m_buffer);
int const bytesRequired = (int)strlen(txt) + 1;
if (bytesRequired > bytesLeft)
{
int const requiredCapacity = bytesRequired + m_capacity - bytesLeft;
GrowBuffer(requiredCapacity);
}
strcat(m_buffer, txt);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(int const n)
{
FormatToStream(*this, "%i", n);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(long const n)
{
FormatToStream(*this, "%li", n);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(unsigned long const n)
{
FormatToStream(*this, "%lu", n);
return *this;
}
#ifdef UNITTEST_COMPILER_IS_MSVC6
MemoryOutStream& MemoryOutStream::operator <<(__int64 const n)
#else
MemoryOutStream& MemoryOutStream::operator <<(long long const n)
#endif
{
#ifdef UNITTEST_WIN32
FormatToStream(*this, "%I64d", n);
#else
FormatToStream(*this, "%lld", n);
#endif
return *this;
}
#ifdef UNITTEST_COMPILER_IS_MSVC6
MemoryOutStream& MemoryOutStream::operator <<(unsigned __int64 const n)
#else
MemoryOutStream& MemoryOutStream::operator <<(unsigned long long const n)
#endif
{
#ifdef UNITTEST_WIN32
FormatToStream(*this, "%I64u", n);
#else
FormatToStream(*this, "%llu", n);
#endif
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(float const f)
{
FormatToStream(*this, "%0.6f", f);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(void const* p)
{
FormatToStream(*this, "%p", p);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(unsigned int const s)
{
FormatToStream(*this, "%u", s);
return *this;
}
MemoryOutStream& MemoryOutStream::operator <<(double const d)
{
FormatToStream(*this, "%0.6f", d);
return *this;
}
int MemoryOutStream::GetCapacity() const
{
return m_capacity;
}
void MemoryOutStream::GrowBuffer(int const desiredCapacity)
{
int const newCapacity = RoundUpToMultipleOfPow2Number(desiredCapacity, GROW_CHUNK_SIZE);
using namespace std;
char* buffer = new char[newCapacity];
if (m_buffer)
strcpy(buffer, m_buffer);
else
strcpy(buffer, "");
delete [] m_buffer;
m_buffer = buffer;
m_capacity = newCapacity;
}
}
#endif

View File

@@ -0,0 +1,87 @@
#ifndef UNITTEST_MEMORYOUTSTREAM_H
#define UNITTEST_MEMORYOUTSTREAM_H
#include "Config.h"
#include "HelperMacros.h"
#ifdef UNITTEST_MEMORYOUTSTREAM_IS_STD_OSTRINGSTREAM
#include <sstream>
namespace UnitTest
{
class UNITTEST_LINKAGE MemoryOutStream : public std::ostringstream
{
public:
MemoryOutStream() {}
~MemoryOutStream() {}
void Clear();
char const* GetText() const;
private:
MemoryOutStream(MemoryOutStream const&);
void operator =(MemoryOutStream const&);
mutable std::string m_text;
};
#ifdef UNITTEST_COMPILER_IS_MSVC6
std::ostream& operator<<(std::ostream& stream, __int64 const n);
std::ostream& operator<<(std::ostream& stream, unsigned __int64 const n);
#endif
}
#else
#include <cstddef>
#ifdef UNITTEST_COMPILER_IS_MSVC6
namespace std {}
#endif
namespace UnitTest
{
class UNITTEST_LINKAGE MemoryOutStream
{
public:
explicit MemoryOutStream(int const size = 256);
~MemoryOutStream();
void Clear();
char const* GetText() const;
MemoryOutStream& operator <<(char const* txt);
MemoryOutStream& operator <<(int n);
MemoryOutStream& operator <<(long n);
MemoryOutStream& operator <<(unsigned long n);
#ifdef UNITTEST_COMPILER_IS_MSVC6
MemoryOutStream& operator <<(__int64 n);
MemoryOutStream& operator <<(unsigned __int64 n);
#else
MemoryOutStream& operator <<(long long n);
MemoryOutStream& operator <<(unsigned long long n);
#endif
MemoryOutStream& operator <<(float f);
MemoryOutStream& operator <<(double d);
MemoryOutStream& operator <<(void const* p);
MemoryOutStream& operator <<(unsigned int s);
enum { GROW_CHUNK_SIZE = 32 };
int GetCapacity() const;
private:
void operator= (MemoryOutStream const&);
void GrowBuffer(int capacity);
int m_capacity;
char* m_buffer;
};
}
#endif
#endif

View File

@@ -0,0 +1,46 @@
#include "SignalTranslator.h"
namespace UnitTest {
sigjmp_buf* SignalTranslator::s_jumpTarget = 0;
namespace {
void SignalHandler(int sig)
{
siglongjmp(*SignalTranslator::s_jumpTarget, sig );
}
}
SignalTranslator::SignalTranslator()
{
m_oldJumpTarget = s_jumpTarget;
s_jumpTarget = &m_currentJumpTarget;
struct sigaction action;
action.sa_flags = 0;
action.sa_handler = SignalHandler;
sigemptyset( &action.sa_mask );
sigaction( SIGSEGV, &action, &m_old_SIGSEGV_action );
sigaction( SIGFPE, &action, &m_old_SIGFPE_action );
sigaction( SIGTRAP, &action, &m_old_SIGTRAP_action );
sigaction( SIGBUS, &action, &m_old_SIGBUS_action );
sigaction( SIGILL, &action, &m_old_SIGILL_action );
}
SignalTranslator::~SignalTranslator()
{
sigaction( SIGILL, &m_old_SIGILL_action, 0 );
sigaction( SIGBUS, &m_old_SIGBUS_action, 0 );
sigaction( SIGTRAP, &m_old_SIGTRAP_action, 0 );
sigaction( SIGFPE, &m_old_SIGFPE_action, 0 );
sigaction( SIGSEGV, &m_old_SIGSEGV_action, 0 );
s_jumpTarget = m_oldJumpTarget;
}
}

View File

@@ -0,0 +1,41 @@
#ifndef UNITTEST_SIGNALTRANSLATOR_H
#define UNITTEST_SIGNALTRANSLATOR_H
#include <setjmp.h>
#include <signal.h>
namespace UnitTest {
class SignalTranslator
{
public:
SignalTranslator();
~SignalTranslator();
static sigjmp_buf* s_jumpTarget;
private:
sigjmp_buf m_currentJumpTarget;
sigjmp_buf* m_oldJumpTarget;
struct sigaction m_old_SIGFPE_action;
struct sigaction m_old_SIGTRAP_action;
struct sigaction m_old_SIGSEGV_action;
struct sigaction m_old_SIGBUS_action;
struct sigaction m_old_SIGILL_action;
};
#if !defined (__GNUC__)
#define UNITTEST_EXTENSION
#else
#define UNITTEST_EXTENSION __extension__
#endif
#define UNITTEST_THROW_SIGNALS_POSIX_ONLY \
UnitTest::SignalTranslator sig; \
if (UNITTEST_EXTENSION sigsetjmp(*UnitTest::SignalTranslator::s_jumpTarget, 1) != 0) \
throw ("Unhandled system exception");
}
#endif

View File

@@ -0,0 +1,33 @@
#include "TimeHelpers.h"
#include <unistd.h>
namespace UnitTest {
Timer::Timer()
{
m_startTime.tv_sec = 0;
m_startTime.tv_usec = 0;
}
void Timer::Start()
{
gettimeofday(&m_startTime, 0);
}
double Timer::GetTimeInMs() const
{
struct timeval currentTime;
gettimeofday(&currentTime, 0);
double const dsecs = currentTime.tv_sec - m_startTime.tv_sec;
double const dus = currentTime.tv_usec - m_startTime.tv_usec;
return (dsecs * 1000.0) + (dus / 1000.0);
}
void TimeHelpers::SleepMs(int ms)
{
usleep(static_cast<useconds_t>(ms * 1000));
}
}

View File

@@ -0,0 +1,28 @@
#ifndef UNITTEST_TIMEHELPERS_H
#define UNITTEST_TIMEHELPERS_H
#include <sys/time.h>
namespace UnitTest {
class Timer
{
public:
Timer();
void Start();
double GetTimeInMs() const;
private:
struct timeval m_startTime;
};
namespace TimeHelpers
{
void SleepMs(int ms);
}
}
#endif

View File

@@ -0,0 +1,71 @@
#include "ReportAssert.h"
#include "ReportAssertImpl.h"
#include "AssertException.h"
#include "CurrentTest.h"
#include "TestResults.h"
#include "TestDetails.h"
#ifdef UNITTEST_NO_EXCEPTIONS
#include "ReportAssertImpl.h"
#endif
namespace UnitTest {
namespace
{
bool& AssertExpectedFlag()
{
static bool s_assertExpected = false;
return s_assertExpected;
}
}
UNITTEST_LINKAGE void ReportAssert(char const* description, char const* filename, int lineNumber)
{
Detail::ReportAssertEx(CurrentTest::Results(), CurrentTest::Details(),
description, filename, lineNumber);
}
namespace Detail {
#ifdef UNITTEST_NO_EXCEPTIONS
UNITTEST_JMPBUF* GetAssertJmpBuf()
{
static UNITTEST_JMPBUF s_jmpBuf;
return &s_jmpBuf;
}
#endif
UNITTEST_LINKAGE void ReportAssertEx(TestResults* testResults,
const TestDetails* testDetails,
char const* description,
char const* filename,
int lineNumber)
{
if (AssertExpectedFlag() == false)
{
TestDetails assertDetails(testDetails->testName, testDetails->suiteName, filename, lineNumber);
testResults->OnTestFailure(assertDetails, description);
}
ExpectAssert(false);
#ifndef UNITTEST_NO_EXCEPTIONS
throw AssertException();
#else
UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET();
#endif
}
UNITTEST_LINKAGE void ExpectAssert(bool expected)
{
AssertExpectedFlag() = expected;
}
UNITTEST_LINKAGE bool AssertExpected()
{
return AssertExpectedFlag();
}
}
}

View File

@@ -0,0 +1,12 @@
#ifndef UNITTEST_ASSERT_H
#define UNITTEST_ASSERT_H
#include "HelperMacros.h"
namespace UnitTest {
UNITTEST_LINKAGE void ReportAssert(char const* description, char const* filename, int lineNumber);
}
#endif

View File

@@ -0,0 +1,46 @@
#ifndef UNITTEST_REPORTASSERTIMPL_H
#define UNITTEST_REPORTASSERTIMPL_H
#include "Config.h"
#include "HelperMacros.h"
#ifdef UNITTEST_NO_EXCEPTIONS
#include <csetjmp>
#endif
namespace UnitTest {
class TestResults;
class TestDetails;
namespace Detail {
UNITTEST_LINKAGE void ExpectAssert(bool expected);
UNITTEST_LINKAGE void ReportAssertEx(TestResults* testResults,
const TestDetails* testDetails,
char const* description,
char const* filename,
int lineNumber);
UNITTEST_LINKAGE bool AssertExpected();
#ifdef UNITTEST_NO_EXCEPTIONS
UNITTEST_LINKAGE UNITTEST_JMPBUF* GetAssertJmpBuf();
#ifdef UNITTEST_WIN32
#define UNITTEST_SET_ASSERT_JUMP_TARGET() \
__pragma(warning(push)) __pragma(warning(disable: 4611)) \
UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf()) \
__pragma(warning(pop))
#else
#define UNITTEST_SET_ASSERT_JUMP_TARGET() UNITTEST_SETJMP(*UnitTest::Detail::GetAssertJmpBuf())
#endif
#define UNITTEST_JUMP_TO_ASSERT_JUMP_TARGET() UNITTEST_LONGJMP(*UnitTest::Detail::GetAssertJmpBuf(), 1)
#endif
}
}
#endif

View File

@@ -0,0 +1,16 @@
#ifndef UNITTEST_REQUIREMACROS_H
#define UNITTEST_REQUIREMACROS_H
#include "RequiredCheckTestReporter.h"
#define UNITTEST_REQUIRE for(UnitTest::RequiredCheckTestReporter decoratedReporter(*UnitTest::CurrentTest::Results()); decoratedReporter.Next(); )
#ifndef UNITTEST_DISABLE_SHORT_MACROS
#ifdef REQUIRE
#error REQUIRE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_REQUIRE instead
#else
#define REQUIRE UNITTEST_REQUIRE
#endif
#endif
#endif

View File

@@ -0,0 +1,17 @@
#include "RequiredCheckException.h"
#ifndef UNITTEST_NO_EXCEPTIONS
namespace UnitTest {
RequiredCheckException::RequiredCheckException()
{
}
RequiredCheckException::~RequiredCheckException() throw()
{
}
}
#endif

View File

@@ -0,0 +1,23 @@
#ifndef UNITTEST_REQUIREDCHECKEXCEPTION_H
#define UNITTEST_REQUIREDCHECKEXCEPTION_H
#include "Config.h"
#ifndef UNITTEST_NO_EXCEPTIONS
#include "HelperMacros.h"
#include <exception>
namespace UnitTest {
class UNITTEST_LINKAGE RequiredCheckException : public std::exception
{
public:
RequiredCheckException();
virtual ~RequiredCheckException() throw();
};
}
#endif
#endif

View File

@@ -0,0 +1,26 @@
#include "RequiredCheckTestReporter.h"
#include "CurrentTest.h"
#include "TestResults.h"
namespace UnitTest {
RequiredCheckTestReporter::RequiredCheckTestReporter(TestResults& results)
: m_results(results)
, m_originalTestReporter(results.m_testReporter)
, m_throwingReporter(results.m_testReporter)
, m_continue(0)
{
m_results.m_testReporter = &m_throwingReporter;
}
RequiredCheckTestReporter::~RequiredCheckTestReporter()
{
m_results.m_testReporter = m_originalTestReporter;
}
bool RequiredCheckTestReporter::Next()
{
return m_continue++ == 0;
}
}

View File

@@ -0,0 +1,33 @@
#ifndef UNITTEST_REQUIRED_CHECK_TEST_REPORTER_H
#define UNITTEST_REQUIRED_CHECK_TEST_REPORTER_H
#include "HelperMacros.h"
#include "ThrowingTestReporter.h"
namespace UnitTest {
class TestResults;
// This RAII class decorates the current TestReporter with
// a version that throws after reporting a failure.
class UNITTEST_LINKAGE RequiredCheckTestReporter
{
public:
explicit RequiredCheckTestReporter(TestResults& results);
~RequiredCheckTestReporter();
bool Next();
private:
RequiredCheckTestReporter(RequiredCheckTestReporter const&);
RequiredCheckTestReporter& operator =(RequiredCheckTestReporter const&);
TestResults& m_results;
TestReporter* m_originalTestReporter;
ThrowingTestReporter m_throwingReporter;
int m_continue;
};
}
#endif

View File

@@ -0,0 +1,38 @@
#include "Config.h"
#include "Test.h"
#include "TestList.h"
#include "TestResults.h"
#include "AssertException.h"
#include "MemoryOutStream.h"
#include "ExecuteTest.h"
#ifdef UNITTEST_POSIX
#include "Posix/SignalTranslator.h"
#endif
namespace UnitTest {
TestList& Test::GetTestList()
{
static TestList s_list;
return s_list;
}
Test::Test(char const* testName, char const* suiteName, char const* filename, int lineNumber)
: m_details(testName, suiteName, filename, lineNumber)
, m_nextTest(0)
, m_isMockTest(false)
{}
Test::~Test()
{}
void Test::Run()
{
ExecuteTest(*this, m_details, m_isMockTest);
}
void Test::RunImpl() const
{}
}

View File

@@ -0,0 +1,35 @@
#ifndef UNITTEST_TEST_H
#define UNITTEST_TEST_H
#include "TestDetails.h"
namespace UnitTest {
class TestResults;
class TestList;
class UNITTEST_LINKAGE Test
{
public:
explicit Test(char const* testName, char const* suiteName = "DefaultSuite", char const* filename = "", int lineNumber = 0);
virtual ~Test();
void Run();
TestDetails const m_details;
Test* m_nextTest;
mutable bool m_isMockTest;
static TestList& GetTestList();
virtual void RunImpl() const;
private:
Test(Test const&);
Test& operator =(Test const&);
};
}
#endif

View File

@@ -0,0 +1,22 @@
#include "TestDetails.h"
namespace UnitTest {
TestDetails::TestDetails(char const* testName_, char const* suiteName_, char const* filename_, int lineNumber_)
: suiteName(suiteName_)
, testName(testName_)
, filename(filename_)
, lineNumber(lineNumber_)
, timeConstraintExempt(false)
{}
TestDetails::TestDetails(const TestDetails& details, int lineNumber_)
: suiteName(details.suiteName)
, testName(details.testName)
, filename(details.filename)
, lineNumber(lineNumber_)
, timeConstraintExempt(details.timeConstraintExempt)
{}
}

View File

@@ -0,0 +1,27 @@
#ifndef UNITTEST_TESTDETAILS_H
#define UNITTEST_TESTDETAILS_H
#include "HelperMacros.h"
namespace UnitTest {
class UNITTEST_LINKAGE TestDetails
{
public:
TestDetails(char const* testName, char const* suiteName, char const* filename, int lineNumber);
TestDetails(const TestDetails& details, int lineNumber);
char const* const suiteName;
char const* const testName;
char const* const filename;
int const lineNumber;
mutable bool timeConstraintExempt;
TestDetails(TestDetails const&); // Why is it public? --> http://gcc.gnu.org/bugs.html#cxx_rvalbind
private:
TestDetails& operator=(TestDetails const&);
};
}
#endif

View File

@@ -0,0 +1,38 @@
#include "TestList.h"
#include "Test.h"
#include <cassert>
namespace UnitTest {
TestList::TestList()
: m_head(0)
, m_tail(0)
{}
void TestList::Add(Test* test)
{
if (m_tail == 0)
{
assert(m_head == 0);
m_head = test;
m_tail = test;
}
else
{
m_tail->m_nextTest = test;
m_tail = test;
}
}
Test* TestList::GetHead() const
{
return m_head;
}
ListAdder::ListAdder(TestList& list, Test* test)
{
list.Add(test);
}
}

View File

@@ -0,0 +1,33 @@
#ifndef UNITTEST_TESTLIST_H
#define UNITTEST_TESTLIST_H
#include "HelperMacros.h"
namespace UnitTest {
class Test;
class UNITTEST_LINKAGE TestList
{
public:
TestList();
void Add (Test* test);
Test* GetHead() const;
private:
Test* m_head;
Test* m_tail;
};
class UNITTEST_LINKAGE ListAdder
{
public:
ListAdder(TestList& list, Test* test);
};
}
#endif

View File

@@ -0,0 +1,126 @@
#ifndef UNITTEST_TESTMACROS_H
#define UNITTEST_TESTMACROS_H
#include "Config.h"
#include "TestSuite.h"
#include "ExceptionMacros.h"
#include "ExecuteTest.h"
#include "AssertException.h"
#include "TestDetails.h"
#include "MemoryOutStream.h"
#ifndef UNITTEST_POSIX
#define UNITTEST_THROW_SIGNALS_POSIX_ONLY
#else
#include "Posix/SignalTranslator.h"
#endif
#define UNITTEST_SUITE(Name) \
namespace Suite ## Name { \
namespace UnitTestSuite { \
inline char const* GetSuiteName () { \
return #Name; \
} \
} \
} \
namespace Suite ## Name
#define UNITTEST_IMPL_TEST(Name, List) \
class Test ## Name : public UnitTest::Test \
{ \
public: \
Test ## Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \
private: \
virtual void RunImpl() const; \
} static test ## Name ## Instance; \
\
static UnitTest::ListAdder adder ## Name (List, &test ## Name ## Instance); \
\
void Test ## Name::RunImpl() const
#define UNITTEST_TEST(Name) UNITTEST_IMPL_TEST(Name, UnitTest::Test::GetTestList())
#define UNITTEST_IMPL_TEST_FIXTURE(Fixture, Name, List) \
class Fixture ## Name ## Helper : public Fixture \
{ \
public: \
explicit Fixture ## Name ## Helper(UnitTest::TestDetails const& details) : m_details(details) {} \
void RunImpl(); \
UnitTest::TestDetails const& m_details; \
virtual ~Fixture ## Name ## Helper(); \
private: \
Fixture ## Name ## Helper(Fixture ## Name ## Helper const&); \
Fixture ## Name ## Helper& operator =(Fixture ## Name ## Helper const&); \
}; \
Fixture ## Name ## Helper::~Fixture ## Name ## Helper(){} \
\
class Test ## Fixture ## Name : public UnitTest::Test \
{ \
public: \
Test ## Fixture ## Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \
private: \
virtual void RunImpl() const; \
} static test ## Fixture ## Name ## Instance; \
\
static UnitTest::ListAdder adder ## Fixture ## Name (List, &test ## Fixture ## Name ## Instance); \
\
void Test ## Fixture ## Name::RunImpl() const \
{ \
volatile bool ctorOk = false; \
UNITTEST_IMPL_TRY \
({ \
Fixture ## Name ## Helper fixtureHelper(m_details); \
ctorOk = true; \
UnitTest::ExecuteTest(fixtureHelper, m_details, false); \
}) \
UNITTEST_IMPL_CATCH (UnitTest::AssertException, e, \
{ \
(void)e; \
}) \
UNITTEST_IMPL_CATCH (std::exception, e, \
{ \
UnitTest::MemoryOutStream stream; \
stream << "Unhandled exception: " << e.what(); \
UnitTest::CurrentTest::Results()->OnTestFailure(m_details, stream.GetText()); \
}) \
UNITTEST_IMPL_CATCH_ALL \
({ \
if (ctorOk) \
{ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \
"Unhandled exception while destroying fixture " #Fixture); \
} \
else \
{ \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \
"Unhandled exception while constructing fixture " #Fixture); \
} \
}) \
} \
void Fixture ## Name ## Helper::RunImpl()
#define UNITTEST_TEST_FIXTURE(Fixture,Name) UNITTEST_IMPL_TEST_FIXTURE(Fixture, Name, UnitTest::Test::GetTestList())
#ifndef UNITTEST_DISABLE_SHORT_MACROS
#ifdef SUITE
#error SUITE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_SUITE instead
#else
#define SUITE(name) UNITTEST_SUITE(name)
#endif
#ifdef TEST
#error TEST already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_TEST instead
#else
#define TEST(Name) UNITTEST_TEST(Name)
#endif
#ifdef TEST_FIXTURE
#error TEST_FIXTURE already defined, re-configure with UNITTEST_ENABLE_SHORT_MACROS set to 0 and use UNITTEST_TEST_FIXTURE instead
#else
#define TEST_FIXTURE(Fixture,Name) UNITTEST_TEST_FIXTURE(Fixture,Name)
#endif
#endif
#endif

View File

@@ -0,0 +1,8 @@
#include "TestReporter.h"
namespace UnitTest {
TestReporter::~TestReporter()
{}
}

View File

@@ -0,0 +1,22 @@
#ifndef UNITTEST_TESTREPORTER_H
#define UNITTEST_TESTREPORTER_H
#include "HelperMacros.h"
namespace UnitTest {
class TestDetails;
class UNITTEST_LINKAGE TestReporter
{
public:
virtual ~TestReporter();
virtual void ReportTestStart(TestDetails const& test) = 0;
virtual void ReportFailure(TestDetails const& test, char const* failure) = 0;
virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed) = 0;
virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) = 0;
};
}
#endif

View File

@@ -0,0 +1,44 @@
#include "TestReporterStdout.h"
#include <cstdio>
#include "TestDetails.h"
// cstdio doesn't pull in namespace std on VC6, so we do it here.
#if defined(UNITTEST_WIN32) && (_MSC_VER == 1200)
namespace std {}
#endif
namespace UnitTest {
void TestReporterStdout::ReportFailure(TestDetails const& details, char const* failure)
{
using namespace std;
#if defined(__APPLE__) || defined(__GNUG__)
char const* const errorFormat = "%s:%d:%d: error: Failure in %s: %s\n";
fprintf(stderr, errorFormat, details.filename, details.lineNumber, 1, details.testName, failure);
#else
char const* const errorFormat = "%s(%d): error: Failure in %s: %s\n";
fprintf(stderr, errorFormat, details.filename, details.lineNumber, details.testName, failure);
#endif
}
void TestReporterStdout::ReportTestStart(TestDetails const& /*test*/)
{}
void TestReporterStdout::ReportTestFinish(TestDetails const& /*test*/, float)
{}
void TestReporterStdout::ReportSummary(int const totalTestCount, int const failedTestCount,
int const failureCount, float const secondsElapsed)
{
using namespace std;
if (failureCount > 0)
printf("FAILURE: %d out of %d tests failed (%d failures).\n", failedTestCount, totalTestCount, failureCount);
else
printf("Success: %d tests passed.\n", totalTestCount);
printf("Test time: %.2f seconds.\n", secondsElapsed);
}
}

View File

@@ -0,0 +1,19 @@
#ifndef UNITTEST_TESTREPORTERSTDOUT_H
#define UNITTEST_TESTREPORTERSTDOUT_H
#include "TestReporter.h"
namespace UnitTest {
class UNITTEST_LINKAGE TestReporterStdout : public TestReporter
{
private:
virtual void ReportTestStart(TestDetails const& test);
virtual void ReportFailure(TestDetails const& test, char const* failure);
virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed);
virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed);
};
}
#endif

View File

@@ -0,0 +1,59 @@
#include "TestResults.h"
#include "TestReporter.h"
#include "TestDetails.h"
namespace UnitTest {
TestResults::TestResults(TestReporter* testReporter)
: m_testReporter(testReporter)
, m_totalTestCount(0)
, m_failedTestCount(0)
, m_failureCount(0)
, m_currentTestFailed(false)
{}
void TestResults::OnTestStart(TestDetails const& test)
{
++m_totalTestCount;
m_currentTestFailed = false;
if (m_testReporter)
m_testReporter->ReportTestStart(test);
}
void TestResults::OnTestFailure(TestDetails const& test, char const* failure)
{
++m_failureCount;
if (!m_currentTestFailed)
{
++m_failedTestCount;
m_currentTestFailed = true;
}
if (m_testReporter)
m_testReporter->ReportFailure(test, failure);
}
void TestResults::OnTestFinish(TestDetails const& test, float secondsElapsed)
{
if (m_testReporter)
m_testReporter->ReportTestFinish(test, secondsElapsed);
}
int TestResults::GetTotalTestCount() const
{
return m_totalTestCount;
}
int TestResults::GetFailedTestCount() const
{
return m_failedTestCount;
}
int TestResults::GetFailureCount() const
{
return m_failureCount;
}
}

View File

@@ -0,0 +1,41 @@
#ifndef UNITTEST_TESTRESULTS_H
#define UNITTEST_TESTRESULTS_H
#include "HelperMacros.h"
namespace UnitTest {
class RequiredCheckTestReporter;
class TestReporter;
class TestDetails;
class UNITTEST_LINKAGE TestResults
{
public:
explicit TestResults(TestReporter* reporter = 0);
void OnTestStart(TestDetails const& test);
void OnTestFailure(TestDetails const& test, char const* failure);
void OnTestFinish(TestDetails const& test, float secondsElapsed);
int GetTotalTestCount() const;
int GetFailedTestCount() const;
int GetFailureCount() const;
private:
friend class RequiredCheckTestReporter;
TestReporter* m_testReporter;
int m_totalTestCount;
int m_failedTestCount;
int m_failureCount;
bool m_currentTestFailed;
TestResults(TestResults const&);
TestResults& operator =(TestResults const&);
};
}
#endif

View File

@@ -0,0 +1,82 @@
#include "TestRunner.h"
#include "TestResults.h"
#include "TestReporter.h"
#include "TestReporterStdout.h"
#include "TimeHelpers.h"
#include "MemoryOutStream.h"
#include <cstring>
namespace UnitTest {
int RunAllTests()
{
TestReporterStdout reporter;
TestRunner runner(reporter);
return runner.RunTestsIf(Test::GetTestList(), NULL, True(), 0);
}
TestRunner::TestRunner(TestReporter& reporter)
: m_reporter(&reporter)
, m_result(new TestResults(&reporter))
, m_timer(new Timer)
{
m_timer->Start();
}
TestRunner::~TestRunner()
{
delete m_result;
delete m_timer;
}
TestResults* TestRunner::GetTestResults()
{
return m_result;
}
int TestRunner::Finish() const
{
float const secondsElapsed = static_cast<float>(m_timer->GetTimeInMs() / 1000.0);
m_reporter->ReportSummary(m_result->GetTotalTestCount(),
m_result->GetFailedTestCount(),
m_result->GetFailureCount(),
secondsElapsed);
return m_result->GetFailureCount();
}
bool TestRunner::IsTestInSuite(const Test* const curTest, char const* suiteName) const
{
using namespace std;
return (suiteName == NULL) || !strcmp(curTest->m_details.suiteName, suiteName);
}
void TestRunner::RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const
{
if (curTest->m_isMockTest == false)
CurrentTest::Results() = result;
Timer testTimer;
testTimer.Start();
result->OnTestStart(curTest->m_details);
curTest->Run();
double const testTimeInMs = testTimer.GetTimeInMs();
if (maxTestTimeInMs > 0 && testTimeInMs > maxTestTimeInMs && !curTest->m_details.timeConstraintExempt)
{
MemoryOutStream stream;
stream << "Global time constraint failed. Expected under " << maxTestTimeInMs <<
"ms but took " << testTimeInMs << "ms.";
result->OnTestFailure(curTest->m_details, stream.GetText());
}
result->OnTestFinish(curTest->m_details, static_cast< float >(testTimeInMs / 1000.0));
}
}

View File

@@ -0,0 +1,61 @@
#ifndef UNITTEST_TESTRUNNER_H
#define UNITTEST_TESTRUNNER_H
#include "Test.h"
#include "TestList.h"
#include "CurrentTest.h"
namespace UnitTest {
class TestReporter;
class TestResults;
class Timer;
UNITTEST_LINKAGE int RunAllTests();
struct True
{
bool operator()(const Test* const) const
{
return true;
}
};
class UNITTEST_LINKAGE TestRunner
{
public:
explicit TestRunner(TestReporter& reporter);
~TestRunner();
template< class Predicate >
int RunTestsIf(TestList const& list, char const* suiteName,
const Predicate& predicate, int maxTestTimeInMs) const
{
Test* curTest = list.GetHead();
while (curTest != 0)
{
if (IsTestInSuite(curTest, suiteName) && predicate(curTest))
RunTest(m_result, curTest, maxTestTimeInMs);
curTest = curTest->m_nextTest;
}
return Finish();
}
TestResults* GetTestResults();
private:
TestReporter* m_reporter;
TestResults* m_result;
Timer* m_timer;
int Finish() const;
bool IsTestInSuite(const Test* const curTest, char const* suiteName) const;
void RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const;
};
}
#endif

View File

@@ -0,0 +1,12 @@
#ifndef UNITTEST_TESTSUITE_H
#define UNITTEST_TESTSUITE_H
namespace UnitTestSuite
{
inline char const* GetSuiteName ()
{
return "DefaultSuite";
}
}
#endif

View File

@@ -0,0 +1,61 @@
#include "ThrowingTestReporter.h"
#include "RequiredCheckException.h"
#ifdef UNITTEST_NO_EXCEPTIONS
#include "ReportAssertImpl.h"
#endif
namespace UnitTest {
ThrowingTestReporter::ThrowingTestReporter(TestReporter* decoratedReporter)
: m_decoratedReporter(decoratedReporter)
{}
//virtual
ThrowingTestReporter::~ThrowingTestReporter()
{}
//virtual
void ThrowingTestReporter::ReportTestStart(TestDetails const& test)
{
if(m_decoratedReporter)
{
m_decoratedReporter->ReportTestStart(test);
}
}
//virtual
void ThrowingTestReporter::ReportFailure(TestDetails const& test, char const* failure)
{
if(m_decoratedReporter)
{
m_decoratedReporter->ReportFailure(test, failure);
}
#ifndef UNITTEST_NO_EXCEPTIONS
throw RequiredCheckException();
#else
static const int stopTest = 1;
UNITTEST_LONGJMP(*UnitTest::Detail::GetAssertJmpBuf(), stopTest);
#endif
}
//virtual
void ThrowingTestReporter::ReportTestFinish(TestDetails const& test, float secondsElapsed)
{
if(m_decoratedReporter)
{
m_decoratedReporter->ReportTestFinish(test, secondsElapsed);
}
}
//virtual
void ThrowingTestReporter::ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed)
{
if(m_decoratedReporter)
{
m_decoratedReporter->ReportSummary(totalTestCount, failedTestCount, failureCount, secondsElapsed);
}
}
}

View File

@@ -0,0 +1,26 @@
#ifndef UNITTEST_THROWINGTESTREPORTER_H
#define UNITTEST_THROWINGTESTREPORTER_H
#include "TestReporter.h"
namespace UnitTest {
// A TestReporter that throws when ReportFailure is called. Otherwise it
// forwards the calls to a decorated TestReporter
class ThrowingTestReporter : public TestReporter
{
public:
explicit ThrowingTestReporter(TestReporter* reporter);
virtual ~ThrowingTestReporter();
virtual void ReportTestStart(TestDetails const& test);
virtual void ReportFailure(TestDetails const& test, char const* failure);
virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed);
virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed);
private:
TestReporter* m_decoratedReporter;
};
}
#endif

View File

@@ -0,0 +1,29 @@
#include "TimeConstraint.h"
#include "TestResults.h"
#include "MemoryOutStream.h"
#include "CurrentTest.h"
namespace UnitTest {
TimeConstraint::TimeConstraint(int ms, TestDetails const& details, int lineNumber)
: m_details(details, lineNumber)
, m_maxMs(ms)
{
m_timer.Start();
}
TimeConstraint::~TimeConstraint()
{
double const totalTimeInMs = m_timer.GetTimeInMs();
if (totalTimeInMs > m_maxMs)
{
MemoryOutStream stream;
stream << "Time constraint failed. Expected to run test under " << m_maxMs <<
"ms but took " << totalTimeInMs << "ms.";
CurrentTest::Results()->OnTestFailure(m_details, stream.GetText());
}
}
}

View File

@@ -0,0 +1,37 @@
#ifndef UNITTEST_TIMECONSTRAINT_H
#define UNITTEST_TIMECONSTRAINT_H
#include "TimeHelpers.h"
#include "HelperMacros.h"
#include "TestDetails.h"
namespace UnitTest {
class TestResults;
class UNITTEST_LINKAGE TimeConstraint
{
public:
TimeConstraint(int ms, TestDetails const& details, int lineNumber);
~TimeConstraint();
private:
void operator=(TimeConstraint const&);
TimeConstraint(TimeConstraint const&);
Timer m_timer;
TestDetails const m_details;
int const m_maxMs;
};
#define UNITTEST_TIME_CONSTRAINT(ms) \
UnitTest::TimeConstraint unitTest__timeConstraint__(ms, m_details, __LINE__)
#define UNITTEST_TIME_CONSTRAINT_EXEMPT() \
UNITTEST_MULTILINE_MACRO_BEGIN \
m_details.timeConstraintExempt = true; \
UNITTEST_MULTILINE_MACRO_END
}
#endif

View File

@@ -0,0 +1,7 @@
#include "Config.h"
#if defined UNITTEST_POSIX
#include "Posix/TimeHelpers.h"
#else
#include "Win32/TimeHelpers.h"
#endif

View File

@@ -0,0 +1 @@
#include "UnitTestPP.h"

View File

@@ -0,0 +1,12 @@
#ifndef UNITTESTPP_H
#define UNITTESTPP_H
#include "Config.h"
#include "TestMacros.h"
#include "CheckMacros.h"
#include "RequireMacros.h"
#include "TestRunner.h"
#include "TimeConstraint.h"
#include "ReportAssert.h"
#endif

View File

@@ -0,0 +1,49 @@
#include "TimeHelpers.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace UnitTest {
Timer::Timer()
: m_threadHandle(::GetCurrentThread())
, m_startTime(0)
{
#if defined(UNITTEST_WIN32) && (_MSC_VER == 1200) // VC6 doesn't have DWORD_PTR
typedef unsigned long DWORD_PTR;
#endif
DWORD_PTR systemMask;
::GetProcessAffinityMask(GetCurrentProcess(), &m_processAffinityMask, &systemMask);
::SetThreadAffinityMask(m_threadHandle, 1);
::QueryPerformanceFrequency(reinterpret_cast< LARGE_INTEGER* >(&m_frequency));
::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask);
}
void Timer::Start()
{
m_startTime = GetTime();
}
double Timer::GetTimeInMs() const
{
__int64 const elapsedTime = GetTime() - m_startTime;
double const seconds = double(elapsedTime) / double(m_frequency);
return seconds * 1000.0;
}
__int64 Timer::GetTime() const
{
LARGE_INTEGER curTime;
::SetThreadAffinityMask(m_threadHandle, 1);
::QueryPerformanceCounter(&curTime);
::SetThreadAffinityMask(m_threadHandle, m_processAffinityMask);
return curTime.QuadPart;
}
void TimeHelpers::SleepMs(int ms)
{
::Sleep(ms);
}
}

View File

@@ -0,0 +1,45 @@
#ifndef UNITTEST_TIMEHELPERS_H
#define UNITTEST_TIMEHELPERS_H
#include "../Config.h"
#include "../HelperMacros.h"
#ifdef UNITTEST_MINGW
#ifndef __int64
#define __int64 long long
#endif
#endif
namespace UnitTest {
class UNITTEST_LINKAGE Timer
{
public:
Timer();
void Start();
double GetTimeInMs() const;
private:
__int64 GetTime() const;
void* m_threadHandle;
#if defined(_WIN64)
unsigned __int64 m_processAffinityMask;
#else
unsigned long m_processAffinityMask;
#endif
__int64 m_startTime;
__int64 m_frequency;
};
namespace TimeHelpers
{
UNITTEST_LINKAGE void SleepMs(int ms);
}
}
#endif

View File

@@ -0,0 +1,130 @@
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "XmlTestReporter.h"
#include <iostream>
#include <sstream>
#include <string>
using std::string;
using std::ostringstream;
using std::ostream;
namespace {
void ReplaceChar(string& str, char c, string const& replacement)
{
for (size_t pos = str.find(c); pos != string::npos; pos = str.find(c, pos + 1))
str.replace(pos, 1, replacement);
}
string XmlEscape(string const& value)
{
string escaped = value;
ReplaceChar(escaped, '&', "&amp;");
ReplaceChar(escaped, '<', "&lt;");
ReplaceChar(escaped, '>', "&gt;");
ReplaceChar(escaped, '\'', "&apos;");
ReplaceChar(escaped, '\"', "&quot;");
return escaped;
}
string BuildFailureMessage(string const& file, int line, string const& message)
{
ostringstream failureMessage;
failureMessage << file << "(" << line << ") : " << message;
return failureMessage.str();
}
}
namespace UnitTest {
XmlTestReporter::XmlTestReporter(ostream& ostream)
: m_ostream(ostream)
{}
void XmlTestReporter::ReportSummary(int totalTestCount, int failedTestCount,
int failureCount, float secondsElapsed)
{
AddXmlElement(m_ostream, NULL);
BeginResults(m_ostream, totalTestCount, failedTestCount, failureCount, secondsElapsed);
DeferredTestResultList const& results = GetResults();
for (DeferredTestResultList::const_iterator i = results.begin(); i != results.end(); ++i)
{
BeginTest(m_ostream, *i);
if (i->failed)
AddFailure(m_ostream, *i);
EndTest(m_ostream, *i);
}
EndResults(m_ostream);
}
void XmlTestReporter::AddXmlElement(ostream& os, char const* encoding)
{
os << "<?xml version=\"1.0\"";
if (encoding != NULL)
os << " encoding=\"" << encoding << "\"";
os << "?>";
}
void XmlTestReporter::BeginResults(std::ostream& os, int totalTestCount, int failedTestCount,
int failureCount, float secondsElapsed)
{
os << "<unittest-results"
<< " tests=\"" << totalTestCount << "\""
<< " failedtests=\"" << failedTestCount << "\""
<< " failures=\"" << failureCount << "\""
<< " time=\"" << secondsElapsed << "\""
<< ">";
}
void XmlTestReporter::EndResults(std::ostream& os)
{
os << "</unittest-results>";
}
void XmlTestReporter::BeginTest(std::ostream& os, DeferredTestResult const& result)
{
os << "<test"
<< " suite=\"" << result.suiteName << "\""
<< " name=\"" << result.testName << "\""
<< " time=\"" << result.timeElapsed << "\"";
}
void XmlTestReporter::EndTest(std::ostream& os, DeferredTestResult const& result)
{
if (result.failed)
os << "</test>";
else
os << "/>";
}
void XmlTestReporter::AddFailure(std::ostream& os, DeferredTestResult const& result)
{
os << ">"; // close <test> element
for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin();
it != result.failures.end();
++it)
{
string const escapedMessage = XmlEscape(std::string(it->failureStr));
string const message = BuildFailureMessage(result.failureFile, it->lineNumber, escapedMessage);
os << "<failure" << " message=\"" << message << "\"" << "/>";
}
}
}
#endif

View File

@@ -0,0 +1,38 @@
#ifndef UNITTEST_XMLTESTREPORTER_H
#define UNITTEST_XMLTESTREPORTER_H
#include "Config.h"
#ifndef UNITTEST_NO_DEFERRED_REPORTER
#include "DeferredTestReporter.h"
#include <iosfwd>
namespace UnitTest
{
class UNITTEST_LINKAGE XmlTestReporter : public DeferredTestReporter
{
public:
explicit XmlTestReporter(std::ostream& ostream);
virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed);
private:
XmlTestReporter(XmlTestReporter const&);
XmlTestReporter& operator=(XmlTestReporter const&);
void AddXmlElement(std::ostream& os, char const* encoding);
void BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed);
void EndResults(std::ostream& os);
void BeginTest(std::ostream& os, DeferredTestResult const& result);
void AddFailure(std::ostream& os, DeferredTestResult const& result);
void EndTest(std::ostream& os, DeferredTestResult const& result);
std::ostream& m_ostream;
};
}
#endif
#endif