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..c3b1e30 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(ExceptionType) #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++/RequireMacros.h b/UnitTest++/RequireMacros.h new file mode 100644 index 0000000..0830e99 --- /dev/null +++ b/UnitTest++/RequireMacros.h @@ -0,0 +1,12 @@ +#ifndef UNITTEST_REQUIREMACROS_H +#define UNITTEST_REQUIREMACROS_H + +#include "RequiredCheckTestReporter.h" + +#ifdef REQUIRE + #error UnitTest++ redefines REQUIRE +#endif + +#define REQUIRE for(UnitTest::RequiredCheckTestReporter decoratedReporter(*UnitTest::CurrentTest::Results()); decoratedReporter.Next(); ) + +#endif 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..4e56149 --- /dev/null +++ b/UnitTest++/ThrowingTestReporter.cpp @@ -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); + } + } + +} 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/tests/TestRequireMacrosWithExceptionsOff.cpp b/tests/TestRequireMacrosWithExceptionsOff.cpp new file mode 100644 index 0000000..d43fbc1 --- /dev/null +++ b/tests/TestRequireMacrosWithExceptionsOff.cpp @@ -0,0 +1,738 @@ +#include "UnitTest++/UnitTestPP.h" +#include "UnitTest++/CurrentTest.h" +#include "RecordingReporter.h" +#include "ScopedCurrentTest.h" + +#include + +using namespace std; + +#ifdef UNITTEST_NO_EXCEPTIONS + +// NOTE: unit tests here use a work around for std::longjmp +// taking us out of the current running unit test. We use a +// follow on test to check the previous test exhibited correct +// behavior. + +namespace { + + static RecordingReporter reporter; + static std::string testName; + static bool next = false; + static int line = 0; + + // Use destructor to reset our globals + struct DoValidationOn + { + ~DoValidationOn() + { + testName = ""; + next = false; + line = 0; + + reporter.lastFailedLine = 0; + memset(reporter.lastFailedTest, 0, sizeof(reporter.lastFailedTest)); + memset(reporter.lastFailedSuite, 0, sizeof(reporter.lastFailedSuite)); + memset(reporter.lastFailedFile, 0, sizeof(reporter.lastFailedFile)); + } + }; + + TEST(RequireCheckSucceedsOnTrue) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK(true); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequireCheckSucceedsOnTrue_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckFailsOnFalse) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK(false); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckFailsOnFalse_FollowOn) + { + CHECK(!next); + } + + TEST(RequireMacroSupportsMultipleChecks) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE + { + CHECK(true); + CHECK_EQUAL(1,1); + } + + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequireMacroSupportsMultipleChecks_FollowOn) + { + CHECK(next); + } + + TEST(RequireMacroSupportsMultipleChecksWithFailingChecks) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE + { + CHECK(true); + CHECK_EQUAL(1,2); + } + + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequireMacroSupportsMultipleChecksWithFailingChecks_FollowOn) + { + CHECK(!next); + } + + TEST(RequireMacroDoesntExecuteCodeAfterAFailingCheck) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE + { + CHECK(false); + next = true; + } + } + } + + TEST_FIXTURE(DoValidationOn, RequireMacroDoesntExecuteCodeAfterAFailingCheck_FollowOn) + { + CHECK(!next); + } + + TEST(FailureReportsCorrectTestName) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + testName = m_details.testName; + REQUIRE CHECK(false); + } + } + + TEST_FIXTURE(DoValidationOn, FailureReportsCorrectTestName_FollowOn) + { + CHECK_EQUAL(testName, reporter.lastFailedTest); + } + + TEST(RequiredCheckFailureIncludesCheckContents) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + testName = m_details.testName; + const bool yaddayadda = false; + + REQUIRE CHECK(yaddayadda); + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckFailureIncludesCheckContents_FollowOn) + { + CHECK(strstr(reporter.lastFailedMessage, "yaddayadda")); + } + + TEST(RequiredCheckEqualSucceedsOnEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_EQUAL(1,1); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckEqualSucceedsOnEqual_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckEqualFailsOnNotEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_EQUAL(1, 2); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckEqualFailsOnNotEqual_FollowOn) + { +// TODO: check reporter last test name + CHECK(!next); + } + + TEST(RequiredCheckEqualFailureContainsCorrectDetails) + { + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails const testDetails("testName", "suiteName", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + line = __LINE__; REQUIRE CHECK_EQUAL(1, 123); + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckEqualFailureContainsCorrectDetails_FollowOn) + { + 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); + + REQUIRE CHECK_EQUAL(1, FunctionWithSideEffects()); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckEqualDoesNotHaveSideEffectsWhenPassing_FollowOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(next); + } + + TEST(RequiredCheckEqualDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_EQUAL(2, FunctionWithSideEffects()); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckEqualDoesNotHaveSideEffectsWhenFailing_FollowOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(!next); + } + + TEST(RequiredCheckCloseSucceedsOnEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_CLOSE(1.0f, 1.001f, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckCloseSucceedsOnEqual_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckCloseFailsOnNotEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_CLOSE (1.0f, 1.1f, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckCloseFailsOnNotEqual_FollowOn) + { + CHECK(!next); + } + + TEST(RequiredCheckCloseFailureContainsCorrectDetails) + { + { + UnitTest::TestResults testResults(&reporter); + UnitTest::TestDetails testDetails("test", "suite", "filename", -1); + ScopedCurrentTest scopedResults(testResults, &testDetails); + + line = __LINE__; REQUIRE CHECK_CLOSE(1.0f, 1.1f, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckCloseFailureContainsCorrectDetails_FollowOn) + { + CHECK_EQUAL("test", reporter.lastFailedTest); + CHECK_EQUAL("suite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + + CHECK(!next); + } + + TEST(RequiredCheckCloseDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_CLOSE (1, FunctionWithSideEffects(), 0.1f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckCloseDoesNotHaveSideEffectsWhenPassing_FollowOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(next); + } + + TEST(RequiredCheckCloseDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + REQUIRE CHECK_CLOSE(2, FunctionWithSideEffects(), 0.1f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckCloseDoesNotHaveSideEffectsWhenFailingOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(!next); + } + + TEST(RequiredCheckArrayCloseSucceedsOnEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + const float data[4] = { 0, 1, 2, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE (data, data, 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseSucceedsOnEqual_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckArrayCloseFailsOnNotEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseFailsOnNotEqual_FollowOn) + { + CHECK(!next); + } + + TEST(RequiredCheckArrayCloseFailureIncludesCheckExpectedAndActual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE(data1, data2, 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseFailureIncludesCheckExpectedAndActual_FollowOn) + { + CHECK(!next); + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); + } + + TEST(RequiredCheckArrayCloseFailureContainsCorrectDetails) + { + { + 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 }; + + line = __LINE__; REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseFailureContainsCorrectDetails_FollowOn) + { + CHECK(!next); + + CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("arrayCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + TEST(RequiredCheckArrayCloseFailureIncludesTolerance) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + float const data1[4] = { 0, 1, 2, 3 }; + float const data2[4] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseFailureIncludesTolerance_FollowOn) + { + CHECK(!next); + CHECK(strstr(reporter.lastFailedMessage, "0.01")); + } + + TEST(RequiredCheckArrayEqualSuceedsOnEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + const float data[4] = { 0, 1, 2, 3 }; + + REQUIRE CHECK_ARRAY_EQUAL (data, data, 4); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayEqualSuceedsOnEqual_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckArrayEqualFailsOnNotEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayEqualFailsOnNotEqual) + { + CHECK(!next); + } + + TEST(RequiredCheckArrayEqualFailureIncludesCheckExpectedAndActual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayEqualFailureIncludesCheckExpectedAndActual_FollowOn) + { + CHECK(!next); + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); + } + + TEST(RequiredCheckArrayEqualFailureContainsCorrectInfo) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + + line = __LINE__; REQUIRE CHECK_ARRAY_EQUAL (data1, data2, 4); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayEqualFailureContainsCorrectInfo_FollowOn) + { + CHECK(!next); + + CHECK_EQUAL("RequiredCheckArrayEqualFailureContainsCorrectInfo", reporter.lastFailedTest); + CHECK_EQUAL(__FILE__, reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + float const* FunctionWithSideEffects2() + { + ++g_sideEffect; + static float const data[] = { 0, 1, 2, 3}; + return data; + } + + TEST(RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenPassing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[] = { 0, 1, 2, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenPassing_FollowOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(next); + } + + TEST(RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenFailing) + { + g_sideEffect = 0; + { + UnitTest::TestResults testResults; + ScopedCurrentTest scopedResults(testResults); + + const float data[] = { 0, 1, 3, 3 }; + + REQUIRE CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArrayCloseDoesNotHaveSideEffectsWhenFailing_FollowOn) + { + CHECK_EQUAL(1, g_sideEffect); + CHECK(!next); + } + + TEST(RequiredCheckArray2DCloseSucceedsOnEqual) + { + { + UnitTest::TestResults testResults(&reporter); + ScopedCurrentTest scopedResults(testResults); + + const float data[2][2] = { {0, 1}, {2, 3} }; + + REQUIRE CHECK_ARRAY2D_CLOSE(data, data, 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseSucceedsOnEqual_FollowOn) + { + CHECK(next); + } + + TEST(RequiredCheckArray2DCloseFailsOnNotEqual) + { + { + 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} }; + + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseFailsOnNotEqual_FollowOn) + { + CHECK(!next); + } + + TEST(RequiredCheckArray2DCloseFailureIncludesCheckExpectedAndActual) + { + { + 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} }; + + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseFailureIncludesCheckExpectedAndActual_FollowOn) + { + CHECK(!next); + + CHECK(strstr(reporter.lastFailedMessage, "xpected [ [ 0 1 ] [ 2 3 ] ]")); + CHECK(strstr(reporter.lastFailedMessage, "was [ [ 0 1 ] [ 3 3 ] ]")); + } + + TEST(RequiredCheckArray2DCloseFailureContainsCorrectDetails) + { + { + 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} }; + + line = __LINE__; REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseFailureContainsCorrectDetails_FollowOn) + { + CHECK(!next); + + CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("array2DCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("filename", reporter.lastFailedFile); + CHECK_EQUAL(line, reporter.lastFailedLine); + } + + TEST(RequiredCheckArray2DCloseFailureIncludesTolerance) + { + { + 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} }; + + REQUIRE CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseFailureIncludesTolerance_FollowOn) + { + CHECK(!next); + 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} }; + + REQUIRE CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseDoesNotHaveSideEffectsWhenPassing_FollowOn) + { + CHECK(next); + 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} }; + + REQUIRE CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + next = true; + } + } + + TEST_FIXTURE(DoValidationOn, RequiredCheckArray2DCloseDoesNotHaveSideEffectsWhenFailing_FollowOn) + { + CHECK(!next); + CHECK_EQUAL(1, g_sideEffect); + } +} + +#endif diff --git a/tests/TestRequireMacrosWithExceptionsOn.cpp b/tests/TestRequireMacrosWithExceptionsOn.cpp new file mode 100644 index 0000000..6b76004 --- /dev/null +++ b/tests/TestRequireMacrosWithExceptionsOn.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