diff --git a/UnitTest++/CheckMacros.h b/UnitTest++/CheckMacros.h index d79d503..e9dae64 100644 --- a/UnitTest++/CheckMacros.h +++ b/UnitTest++/CheckMacros.h @@ -5,6 +5,7 @@ #include "ExceptionMacros.h" #include "Checks.h" #include "AssertException.h" +#include "RequiredCheckException.h" #include "MemoryOutStream.h" #include "TestDetails.h" #include "CurrentTest.h" @@ -37,10 +38,11 @@ #define CHECK(value) \ UNITTEST_MULTILINE_MACRO_BEGIN \ UT_TRY \ - ({ \ + ({ \ if (!UnitTest::Check(value)) \ UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -58,9 +60,10 @@ #define CHECK_EQUAL(expected, actual) \ UNITTEST_MULTILINE_MACRO_BEGIN \ UT_TRY \ - ({ \ + ({ \ UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -69,7 +72,7 @@ message.GetText()); \ }) \ UT_CATCH_ALL \ - ({ \ + ({ \ UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \ }) \ @@ -78,9 +81,10 @@ #define CHECK_CLOSE(expected, actual, tolerance) \ UNITTEST_MULTILINE_MACRO_BEGIN \ UT_TRY \ - ({ \ + ({ \ UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -89,7 +93,7 @@ message.GetText()); \ }) \ UT_CATCH_ALL \ - ({ \ + ({ \ UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \ "Unhandled exception in CHECK_CLOSE(" #expected ", " #actual ")"); \ }) \ @@ -101,6 +105,7 @@ ({ \ UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), expected, actual, count, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -121,6 +126,7 @@ ({ \ UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -141,6 +147,7 @@ ({ \ UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_RETHROW (UnitTest::RequiredCheckException) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ diff --git a/UnitTest++/ExceptionMacros.h b/UnitTest++/ExceptionMacros.h index ca8757e..027a5da 100644 --- a/UnitTest++/ExceptionMacros.h +++ b/UnitTest++/ExceptionMacros.h @@ -6,11 +6,13 @@ #ifndef UNITTEST_NO_EXCEPTIONS #define UT_TRY(x) try x #define UT_THROW(x) throw x + #define UT_RETHROW(ExceptionType) catch(ExceptionType&) { throw; } #define UT_CATCH(ExceptionType, ExceptionName, CatchBody) catch(ExceptionType& ExceptionName) CatchBody #define UT_CATCH_ALL(CatchBody) catch(...) CatchBody #else #define UT_TRY(x) x #define UT_THROW(x) + #define UT_RETHROW() #define UT_CATCH(ExceptionType, ExceptionName, CatchBody) #define UT_CATCH_ALL(CatchBody) #endif diff --git a/UnitTest++/ExecuteTest.h b/UnitTest++/ExecuteTest.h index c6917fc..8e516db 100644 --- a/UnitTest++/ExecuteTest.h +++ b/UnitTest++/ExecuteTest.h @@ -7,6 +7,7 @@ #include "TestResults.h" #include "MemoryOutStream.h" #include "AssertException.h" +#include "RequiredCheckException.h" #include "CurrentTest.h" #ifdef UNITTEST_NO_EXCEPTIONS @@ -38,6 +39,7 @@ namespace UnitTest { testObject.RunImpl(); }) #endif + UT_CATCH(RequiredCheckException, e, { (void)e; }) UT_CATCH(AssertException, e, { (void)e; }) UT_CATCH(std::exception, e, { diff --git a/UnitTest++/Makefile.am b/UnitTest++/Makefile.am index 32f6477..a512fca 100644 --- a/UnitTest++/Makefile.am +++ b/UnitTest++/Makefile.am @@ -1,7 +1,7 @@ lib_LTLIBRARIES = UnitTest++/libUnitTest++.la pkgincludedir = $(includedir)/UnitTest++/ -nobase_pkginclude_HEADERS = UnitTest++/UnitTest++.h UnitTest++/UnitTestPP.h UnitTest++/Config.h UnitTest++/HelperMacros.h UnitTest++/Test.h UnitTest++/TestDetails.h UnitTest++/TestList.h UnitTest++/TestSuite.h UnitTest++/TestResults.h UnitTest++/TestMacros.h UnitTest++/CheckMacros.h UnitTest++/TestRunner.h UnitTest++/TimeConstraint.h UnitTest++/ExecuteTest.h UnitTest++/AssertException.h UnitTest++/MemoryOutStream.h UnitTest++/CurrentTest.h UnitTest++/Checks.h UnitTest++/TimeHelpers.h UnitTest++/ExceptionMacros.h UnitTest++/ReportAssert.h UnitTest++/ReportAssertImpl.h UnitTest++/TestReporter.h UnitTest++/TestReporterStdout.h UnitTest++/CompositeTestReporter.h UnitTest++/DeferredTestReporter.h UnitTest++/DeferredTestResult.h -UnitTest___libUnitTest___la_SOURCES = UnitTest++/AssertException.cpp UnitTest++/Test.cpp UnitTest++/Checks.cpp UnitTest++/TestRunner.cpp UnitTest++/TestResults.cpp UnitTest++/TestReporter.cpp UnitTest++/TestReporterStdout.cpp UnitTest++/ReportAssert.cpp UnitTest++/TestList.cpp UnitTest++/TimeConstraint.cpp UnitTest++/TestDetails.cpp UnitTest++/MemoryOutStream.cpp UnitTest++/DeferredTestReporter.cpp UnitTest++/DeferredTestResult.cpp UnitTest++/XmlTestReporter.cpp UnitTest++/CurrentTest.cpp UnitTest++/CompositeTestReporter.cpp +nobase_pkginclude_HEADERS = UnitTest++/AssertException.h UnitTest++/CheckMacros.h UnitTest++/Checks.h UnitTest++/CompositeTestReporter.h UnitTest++/Config.h UnitTest++/CurrentTest.h UnitTest++/DeferredTestReporter.h UnitTest++/DeferredTestResult.h UnitTest++/ExceptionMacros.h UnitTest++/ExecuteTest.h UnitTest++/HelperMacros.h UnitTest++/MemoryOutStream.h UnitTest++/ReportAssert.h UnitTest++/ReportAssertImpl.h UnitTest++/RequireMacros.h UnitTest++/RequiredCheckException.h UnitTest++/RequiredCheckTestReporter.h UnitTest++/Test.h UnitTest++/TestDetails.h UnitTest++/TestList.h UnitTest++/TestMacros.h UnitTest++/TestReporter.h UnitTest++/TestReporterStdout.h UnitTest++/TestResults.h UnitTest++/TestRunner.h UnitTest++/TestSuite.h UnitTest++/ThrowingTestReporter.h UnitTest++/TimeConstraint.h UnitTest++/TimeHelpers.h UnitTest++/UnitTest++.h UnitTest++/UnitTestPP.h UnitTest++/XmlTestReporter.h +UnitTest___libUnitTest___la_SOURCES = UnitTest++/AssertException.cpp UnitTest++/Checks.cpp UnitTest++/CompositeTestReporter.cpp UnitTest++/CurrentTest.cpp UnitTest++/DeferredTestReporter.cpp UnitTest++/DeferredTestResult.cpp UnitTest++/MemoryOutStream.cpp UnitTest++/ReportAssert.cpp UnitTest++/RequiredCheckException.cpp UnitTest++/RequiredCheckTestReporter.cpp UnitTest++/Test.cpp UnitTest++/TestDetails.cpp UnitTest++/TestList.cpp UnitTest++/TestReporter.cpp UnitTest++/TestReporterStdout.cpp UnitTest++/TestResults.cpp UnitTest++/TestRunner.cpp UnitTest++/ThrowingTestReporter.cpp UnitTest++/TimeConstraint.cpp UnitTest++/XmlTestReporter.cpp if WINDOWS nobase_pkginclude_HEADERS += UnitTest++/Win32/TimeHelpers.h diff --git a/UnitTest++/RequireMacros.h b/UnitTest++/RequireMacros.h new file mode 100644 index 0000000..ea1f6b9 --- /dev/null +++ b/UnitTest++/RequireMacros.h @@ -0,0 +1,18 @@ +#ifndef UNITTEST_REQUIREMACROS_H +#define UNITTEST_REQUIREMACROS_H + +#include "RequiredCheckTestReporter.h" + +#ifdef REQUIRE + #error UnitTest++ redefines REQUIRE +#endif + +#ifndef UNITTEST_NO_EXCEPTIONS + #define REQUIRE for(UnitTest::RequiredCheckTestReporter decoratedReporter(*UnitTest::CurrentTest::Results()); decoratedReporter.Next(); ) +#endif + +#ifdef UNITTEST_NO_EXCEPTIONS + #define REQUIRE +#endif + +#endif \ No newline at end of file diff --git a/UnitTest++/RequiredCheckException.cpp b/UnitTest++/RequiredCheckException.cpp new file mode 100644 index 0000000..874370e --- /dev/null +++ b/UnitTest++/RequiredCheckException.cpp @@ -0,0 +1,17 @@ +#include "RequiredCheckException.h" + +#ifndef UNITTEST_NO_EXCEPTIONS + +namespace UnitTest { + + RequiredCheckException::RequiredCheckException() + { + } + + RequiredCheckException::~RequiredCheckException() throw() + { + } + +} + +#endif diff --git a/UnitTest++/RequiredCheckException.h b/UnitTest++/RequiredCheckException.h new file mode 100644 index 0000000..c9a36da --- /dev/null +++ b/UnitTest++/RequiredCheckException.h @@ -0,0 +1,23 @@ +#ifndef UNITTEST_REQUIREDCHECKEXCEPTION_H +#define UNITTEST_REQUIREDCHECKEXCEPTION_H + +#include "Config.h" +#ifndef UNITTEST_NO_EXCEPTIONS + +#include "HelperMacros.h" +#include + +namespace UnitTest { + + class UNITTEST_LINKAGE RequiredCheckException : public std::exception + { + public: + RequiredCheckException(); + virtual ~RequiredCheckException() throw(); + }; + +} + +#endif + +#endif diff --git a/UnitTest++/RequiredCheckTestReporter.cpp b/UnitTest++/RequiredCheckTestReporter.cpp new file mode 100644 index 0000000..7c21d20 --- /dev/null +++ b/UnitTest++/RequiredCheckTestReporter.cpp @@ -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; + } +} \ No newline at end of file diff --git a/UnitTest++/RequiredCheckTestReporter.h b/UnitTest++/RequiredCheckTestReporter.h new file mode 100644 index 0000000..117ae01 --- /dev/null +++ b/UnitTest++/RequiredCheckTestReporter.h @@ -0,0 +1,30 @@ +#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: + TestResults& m_results; + TestReporter* m_originalTestReporter; + ThrowingTestReporter m_throwingReporter; + int m_continue; + }; +} + +#endif + diff --git a/UnitTest++/TestResults.h b/UnitTest++/TestResults.h index c56a632..a4d8e60 100644 --- a/UnitTest++/TestResults.h +++ b/UnitTest++/TestResults.h @@ -5,6 +5,7 @@ namespace UnitTest { + class RequiredCheckTestReporter; class TestReporter; class TestDetails; @@ -22,6 +23,8 @@ namespace UnitTest { int GetFailureCount() const; private: + friend class RequiredCheckTestReporter; + TestReporter* m_testReporter; int m_totalTestCount; int m_failedTestCount; diff --git a/UnitTest++/ThrowingTestReporter.cpp b/UnitTest++/ThrowingTestReporter.cpp new file mode 100644 index 0000000..672f042 --- /dev/null +++ b/UnitTest++/ThrowingTestReporter.cpp @@ -0,0 +1,51 @@ +#include "ThrowingTestReporter.h" +#include "RequiredCheckException.h" + +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); + } + throw RequiredCheckException(); + } + + //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); + } + } + +} diff --git a/UnitTest++/ThrowingTestReporter.h b/UnitTest++/ThrowingTestReporter.h new file mode 100644 index 0000000..34e105e --- /dev/null +++ b/UnitTest++/ThrowingTestReporter.h @@ -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 diff --git a/UnitTest++/UnitTestPP.h b/UnitTest++/UnitTestPP.h index c9bbc0c..3e02d31 100644 --- a/UnitTest++/UnitTestPP.h +++ b/UnitTest++/UnitTestPP.h @@ -4,6 +4,7 @@ #include "Config.h" #include "TestMacros.h" #include "CheckMacros.h" +#include "RequireMacros.h" #include "TestRunner.h" #include "TimeConstraint.h" #include "ReportAssert.h" diff --git a/configure.ac b/configure.ac index 7b77b73..46e3be6 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,8 @@ AC_SUBST([LIBUNITTEST_SO_VERSION], [1:5:1]) AC_PROG_CXX AC_PROG_CC +AX_CXX_COMPILE_STDCXX_11(noext, optional) + # Checks for libraries. # Checks for header files. diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 0000000..66d41f5 --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,558 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXXFLAGS to +# enable support. VERSION may be '11' (for the C++11 standard) or '14' +# (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [], + [$1], [14], [], + [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++$1 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + + AC_SUBST(HAVE_CXX$1) + fi +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_seperators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) \ No newline at end of file diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000..09db383 --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,39 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 14 + +include([ax_cxx_compile_stdcxx.m4]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) diff --git a/tests/Makefile.am b/tests/Makefile.am index 5306292..fe7cffd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ check_PROGRAMS = UnitTest++/TestUnitTest++ -UnitTest___TestUnitTest___SOURCES = tests/Main.cpp tests/TestAssertHandler.cpp tests/TestCheckMacros.cpp tests/TestChecks.cpp tests/TestCompositeTestReporter.cpp tests/TestCurrentTest.cpp tests/TestDeferredTestReporter.cpp tests/TestExceptions.cpp tests/TestMemoryOutStream.cpp tests/TestTest.cpp tests/TestTestList.cpp tests/TestTestMacros.cpp tests/TestTestResults.cpp tests/TestTestRunner.cpp tests/TestTestSuite.cpp tests/TestTimeConstraint.cpp tests/TestTimeConstraintMacro.cpp tests/TestUnitTestPP.cpp tests/TestXmlTestReporter.cpp +UnitTest___TestUnitTest___SOURCES = tests/Main.cpp tests/TestAssertHandler.cpp tests/TestCheckMacros.cpp tests/TestChecks.cpp tests/TestCompositeTestReporter.cpp tests/TestCurrentTest.cpp tests/TestDeferredTestReporter.cpp tests/TestExceptions.cpp tests/TestMemoryOutStream.cpp tests/TestRequireMacros.cpp tests/TestTest.cpp tests/TestTestList.cpp tests/TestTestMacros.cpp tests/TestTestResults.cpp tests/TestTestRunner.cpp tests/TestTestSuite.cpp tests/TestTimeConstraint.cpp tests/TestTimeConstraintMacro.cpp tests/TestUnitTestPP.cpp tests/TestXmlTestReporter.cpp UnitTest___TestUnitTest___LDADD = UnitTest++/libUnitTest++.la TESTS = UnitTest++/TestUnitTest++ diff --git a/tests/TestRequireMacros.cpp b/tests/TestRequireMacros.cpp new file mode 100644 index 0000000..6b76004 --- /dev/null +++ b/tests/TestRequireMacros.cpp @@ -0,0 +1,854 @@ +#include "UnitTest++/UnitTestPP.h" +#include "UnitTest++/CurrentTest.h" +#include "RecordingReporter.h" +#include "ScopedCurrentTest.h" + +using namespace std; + +#ifndef UNITTEST_NO_EXCEPTIONS + +namespace { + + TEST(RequireCheckSucceedsOnTrue) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK(true); + } + catch(const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckFailsOnFalse) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK(false); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + + TEST(RequireMacroSupportsMultipleChecks) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try{ + REQUIRE + { + CHECK(true); + CHECK_EQUAL(1,1); + } + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + + TEST(RequireMacroSupportsMultipleChecksWithFailingChecks) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try{ + REQUIRE + { + CHECK(true); + CHECK_EQUAL(1,2); + } + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequireMacroDoesntExecuteCodeAfterAFailingCheck) + { + bool failure = false; + bool exception = false; + bool run = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try{ + REQUIRE + { + CHECK(false); + run = true; // this shouldn't get executed. + } + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + CHECK(!run); + } + + TEST(FailureReportsCorrectTestName) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK(false); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL(m_details.testName, reporter.lastFailedTest); + } + + TEST(RequiredCheckFailureIncludesCheckContents) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + const bool yaddayadda = false; + + try + { + REQUIRE CHECK(yaddayadda); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "yaddayadda")); + } + + TEST(RequiredCheckEqualSucceedsOnEqual) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_EQUAL(1,1); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckEqualFailsOnNotEqual) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_EQUAL(1, 2); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequiredCheckEqualFailureContainsCorrectDetails) + { + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails const testDetails("testName", "suiteName", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + try + { + line = __LINE__; REQUIRE CHECK_EQUAL(1, 123); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL("testName", reporter.lastFailedTest); + CHECK_EQUAL("suiteName", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + int g_sideEffect = 0; + int FunctionWithSideEffects() + { + ++g_sideEffect; + return 1; + } + + TEST(RequiredCheckEqualDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_EQUAL(1, FunctionWithSideEffects()); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckEqualDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_EQUAL(2, FunctionWithSideEffects()); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + + TEST(RequiredCheckCloseSucceedsOnEqual) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_CLOSE(1.0f, 1.001f, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckCloseFailsOnNotEqual) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_CLOSE (1.0f, 1.1f, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequiredCheckCloseFailureContainsCorrectDetails) + { + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails testDetails("test", "suite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + try + { + line = __LINE__; REQUIRE CHECK_CLOSE(1.0f, 1.1f, 0.01f); + CHECK(false); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL("test", reporter.lastFailedTest); + CHECK_EQUAL("suite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + TEST(RequiredCheckCloseDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_CLOSE (1, FunctionWithSideEffects(), 0.1f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckCloseDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + try + { + REQUIRE CHECK_CLOSE(2, FunctionWithSideEffects(), 0.1f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckArrayCloseSucceedsOnEqual) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + const float data[4] = { 0, 1, 2, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE (data, data, 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckArrayCloseFailsOnNotEqual) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequiredCheckArrayCloseFailureIncludesCheckExpectedAndActual) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); + } + + TEST(RequiredCheckArrayCloseFailureContainsCorrectDetails) + { + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails testDetails("arrayCloseTest", "arrayCloseSuite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + line = __LINE__; REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("arrayCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + TEST(RequiredCheckArrayCloseFailureIncludesTolerance) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + float const data1[4] = { 0, 1, 2, 3 }; + float const data2[4] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "0.01")); + } + + TEST(RequiredCheckArrayEqualSuceedsOnEqual) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + const float data[4] = { 0, 1, 2, 3 }; + + try + { + REQUIRE CHECK_ARRAY_EQUAL (data, data, 4); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckArrayEqualFailsOnNotEqual) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequiredCheckArrayEqualFailureIncludesCheckExpectedAndActual) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); + } + + TEST(RequiredCheckArrayEqualFailureContainsCorrectInfo) + { + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + try + { + line = __LINE__; REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL("RequiredCheckArrayEqualFailureContainsCorrectInfo", reporter.lastFailedTest); + CHECK_EQUAL(__FILE__, reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + float const* FunctionWithSideEffects2() + { + ++g_sideEffect; + static float const data[] = {1,2,3,4}; + return data; + } + + TEST(RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[] = { 0, 1, 2, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[] = { 0, 1, 3, 3 }; + + try + { + REQUIRE CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckArray2DCloseSucceedsOnEqual) + { + bool failure = true; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + const float data[2][2] = { {0, 1}, {2, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE(data, data, 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(!failure); + CHECK(!exception); + } + + TEST(RequiredCheckArray2DCloseFailsOnNotEqual) + { + bool failure = false; + bool exception = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + + CHECK(failure); + CHECK(exception); + } + + TEST(RequiredCheckArray2DCloseFailureIncludesCheckExpectedAndActual) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ [ 0 1 ] [ 2 3 ] ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ [ 0 1 ] [ 3 3 ] ]")); + } + + TEST(RequiredCheckArray2DCloseFailureContainsCorrectDetails) + { + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails testDetails("array2DCloseTest", "array2DCloseSuite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + + try + { + line = __LINE__; REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("array2DCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + TEST(RequiredCheckArray2DCloseFailureIncludesTolerance) + { + RecordingReporter reporter; + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + float const data1[2][2] = { {0, 1}, {2, 3} }; + float const data2[2][2] = { {0, 1}, {3, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + + CHECK(strstr(reporter.lastFailedMessage, "0.01")); + } + + float const* const* FunctionWithSideEffects3() + { + ++g_sideEffect; + static float const data1[] = {0,1}; + static float const data2[] = {2,3}; + static const float* const data[] = {data1, data2}; + return data; + } + + TEST(RequiredCheckArray2DCloseDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[2][2] = { {0, 1}, {2, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + + TEST(RequiredCheckArray2DCloseDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[2][2] = { {0, 1}, {3, 3} }; + + try + { + REQUIRE CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + } + catch (const UnitTest::RequiredCheckException&) + {} + } + CHECK_EQUAL(1, g_sideEffect); + } + +} + +#endif