diff --git a/UnitTest++/CheckMacros.h b/UnitTest++/CheckMacros.h index d79d503..bc9fbcf 100644 --- a/UnitTest++/CheckMacros.h +++ b/UnitTest++/CheckMacros.h @@ -41,6 +41,10 @@ if (!UnitTest::Check(value)) \ UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), #value); \ }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -60,7 +64,11 @@ UT_TRY \ ({ \ UnitTest::CheckEqual(*UnitTest::CurrentTest::Results(), expected, actual, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ - }) \ + }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -81,6 +89,10 @@ ({ \ UnitTest::CheckClose(*UnitTest::CurrentTest::Results(), expected, actual, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -100,7 +112,11 @@ UT_TRY \ ({ \ UnitTest::CheckArrayEqual(*UnitTest::CurrentTest::Results(), expected, actual, count, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ - }) \ + }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -121,6 +137,10 @@ ({ \ UnitTest::CheckArrayClose(*UnitTest::CurrentTest::Results(), expected, actual, count, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ @@ -140,7 +160,11 @@ UT_TRY \ ({ \ UnitTest::CheckArray2DClose(*UnitTest::CurrentTest::Results(), expected, actual, rows, columns, tolerance, UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__)); \ - }) \ + }) \ + UT_CATCH (UnitTest::AssertException, e, \ + { \ + UT_THROW(); \ + }) \ UT_CATCH (std::exception, e, \ { \ UnitTest::MemoryOutStream message; \ diff --git a/UnitTest++/RequireMacros.h b/UnitTest++/RequireMacros.h index 747bda7..9fee8eb 100644 --- a/UnitTest++/RequireMacros.h +++ b/UnitTest++/RequireMacros.h @@ -1,19 +1,14 @@ #ifndef UNITTEST_REQUIREMACROS_H #define UNITTEST_REQUIREMACROS_H -#include "HelperMacros.h" -#include "ExceptionMacros.h" -#include "CurrentTest.h" +#include "RequiredCheckTestReporter.h" #ifdef REQUIRE #error UnitTest++ redefines REQUIRE #endif #ifndef UNITTEST_NO_EXCEPTIONS - #define REQUIRE \ - for (int failuresBeforeTest = UnitTest::CurrentTest::Results()->GetFailureCount(), newFailures = 0, run = 0; \ - (run == 0) || ((newFailures != 0) && (throw UnitTest::AssertException(), true)); \ - newFailures = UnitTest::CurrentTest::Results()->GetFailureCount() - failuresBeforeTest, run = 1) + #define REQUIRE for(UnitTest::RequiredCheckTestReporter decoratedReporter(UnitTest::CurrentTest::Results()); decoratedReporter.next(); ) #endif #ifdef UNITTEST_NO_EXCEPTIONS diff --git a/UnitTest++/RequiredCheckTestReporter.cpp b/UnitTest++/RequiredCheckTestReporter.cpp new file mode 100644 index 0000000..cae20db --- /dev/null +++ b/UnitTest++/RequiredCheckTestReporter.cpp @@ -0,0 +1,29 @@ +#include "RequiredCheckTestReporter.h" + +#include "CurrentTest.h" +#include "TestResults.h" + +namespace UnitTest { + + RequiredCheckTestReporter::RequiredCheckTestReporter(TestResults* results) + : m_results(results) + , m_throwingReporter(0) + , m_continue(0) + { + if(m_results) + { + m_throwingReporter.setDecorated(m_results->m_testReporter); + m_results->m_testReporter = &m_throwingReporter; + } + } + + RequiredCheckTestReporter::~RequiredCheckTestReporter() + { + if(m_results) m_results->m_testReporter = m_throwingReporter.getDecorated(); + } + + 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..22613e9 --- /dev/null +++ b/UnitTest++/RequiredCheckTestReporter.h @@ -0,0 +1,29 @@ +#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; + ThrowingTestReporter m_throwingReporter; + int m_continue; + }; +} + +#endif + diff --git a/UnitTest++/TestResults.h b/UnitTest++/TestResults.h index c56a632..024ace3 100644 --- a/UnitTest++/TestResults.h +++ b/UnitTest++/TestResults.h @@ -5,6 +5,7 @@ namespace UnitTest { +class RequiredCheckTestReporter; class TestReporter; class TestDetails; @@ -22,6 +23,9 @@ namespace UnitTest { int GetFailureCount() const; private: + friend class RequiredCheckTestReporter; + +private: 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..45ccade --- /dev/null +++ b/UnitTest++/ThrowingTestReporter.cpp @@ -0,0 +1,51 @@ +#include "ThrowingTestReporter.h" +#include "AssertException.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 AssertException(); + } + + //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); + } + + TestReporter* ThrowingTestReporter::getDecorated() const + { + return m_decoratedReporter; + } + + void ThrowingTestReporter::setDecorated(TestReporter* reporter) + { + m_decoratedReporter = reporter; + } + +} diff --git a/UnitTest++/ThrowingTestReporter.h b/UnitTest++/ThrowingTestReporter.h new file mode 100644 index 0000000..0a02a51 --- /dev/null +++ b/UnitTest++/ThrowingTestReporter.h @@ -0,0 +1,29 @@ +#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); + + TestReporter* getDecorated() const; + void setDecorated(TestReporter* reporter); + + private: + TestReporter* m_decoratedReporter; + }; +} + +#endif diff --git a/tests/TestRequireMacros.cpp b/tests/TestRequireMacros.cpp index 869de32..46732a2 100644 --- a/tests/TestRequireMacros.cpp +++ b/tests/TestRequireMacros.cpp @@ -117,7 +117,37 @@ TEST(RequireMacroSupportsMultipleChecksWithFailingChecks) 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::AssertException&) + { + exception = true; + } + + failure = (testResults.GetFailureCount() > 0); + } + CHECK(failure); + CHECK(exception); + CHECK(!run); +} + TEST(FailureReportsCorrectTestName) { RecordingReporter reporter;