Moved all AssertionHandler logic into RunContext and de-virtualised interface

This makes the assertion handling much less "chatty". AssertionHandler is now just a thin shim over RunContext
This commit is contained in:
Phil Nash 2017-11-27 22:21:47 +03:00
parent 5461242ffe
commit 4b614ee1d1
5 changed files with 179 additions and 81 deletions

View File

@ -15,6 +15,7 @@
#include "catch_debugger.h" #include "catch_debugger.h"
#include "catch_interfaces_registry_hub.h" #include "catch_interfaces_registry_hub.h"
#include "catch_capture_matchers.h" #include "catch_capture_matchers.h"
#include "catch_run_context.h"
#include <cassert> #include <cassert>
@ -57,58 +58,19 @@ namespace Catch {
StringRef capturedExpression, StringRef capturedExpression,
ResultDisposition::Flags resultDisposition ) ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() ) m_resultCapture( static_cast<RunContext&>( getResultCapture() ) )
{ {}
m_resultCapture.assertionStarting( m_assertionInfo );
}
AssertionHandler::~AssertionHandler() { AssertionHandler::~AssertionHandler() {
if ( !m_completed ) { if ( !m_completed )
handleMessage(ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"); m_resultCapture.handleIncomplete( m_assertionInfo );
m_resultCapture.exceptionEarlyReported();
}
} }
void AssertionHandler::handleExpr( ITransientExpression const& expr ) { void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
bool negated = isFalseTest( m_assertionInfo.resultDisposition );
bool result = expr.getResult() != negated;
if(result && !getCurrentContext().getConfig()->includeSuccessfulResults())
{
m_resultCapture.assertionRun();
m_resultCapture.assertionPassed();
return;
}
handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated );
}
void AssertionHandler::handle( ResultWas::OfType resultType ) {
handle( resultType, nullptr, false );
} }
void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const &message) { void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const &message) {
AssertionResultData data( resultType, LazyExpression( false ) ); m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
data.message = message;
handle( data, nullptr );
}
void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) {
AssertionResultData data( resultType, LazyExpression( negated ) );
handle( data, expr );
}
void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) {
m_resultCapture.assertionRun();
AssertionResult assertionResult{ m_assertionInfo, resultData };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
m_resultCapture.assertionEnded( assertionResult );
if( !assertionResult.isOk() ) {
m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak();
m_shouldThrow =
getCurrentContext().getRunner()->aborting() ||
(m_assertionInfo.resultDisposition & ResultDisposition::Normal);
}
} }
auto AssertionHandler::allowThrows() const -> bool { auto AssertionHandler::allowThrows() const -> bool {
@ -117,7 +79,7 @@ namespace Catch {
void AssertionHandler::complete() { void AssertionHandler::complete() {
setCompleted(); setCompleted();
if( m_shouldDebugBreak ) { if( m_reaction.shouldDebugBreak ) {
// If you find your debugger stopping you here then go one level up on the // If you find your debugger stopping you here then go one level up on the
// call-stack for the code that caused it (typically a failed assertion) // call-stack for the code that caused it (typically a failed assertion)
@ -125,7 +87,7 @@ namespace Catch {
// (To go back to the test and change execution, jump over the throw, next) // (To go back to the test and change execution, jump over the throw, next)
CATCH_BREAK_INTO_DEBUGGER(); CATCH_BREAK_INTO_DEBUGGER();
} }
if( m_shouldThrow ) if( m_reaction.shouldThrow )
throw Catch::TestFailureException(); throw Catch::TestFailureException();
} }
void AssertionHandler::setCompleted() { void AssertionHandler::setCompleted() {
@ -133,22 +95,22 @@ namespace Catch {
} }
void AssertionHandler::handleUnexpectedInflightException() { void AssertionHandler::handleUnexpectedInflightException() {
handleMessage(ResultWas::ThrewException, Catch::translateActiveException()); m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
} }
void AssertionHandler::handleExceptionThrownAsExpected() { void AssertionHandler::handleExceptionThrownAsExpected() {
handle( Catch::ResultWas::Ok ); m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
} }
void AssertionHandler::handleExceptionNotThrownAsExpected() { void AssertionHandler::handleExceptionNotThrownAsExpected() {
handle( Catch::ResultWas::Ok ); m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
} }
void AssertionHandler::handleUnexpectedExceptionNotThrown() { void AssertionHandler::handleUnexpectedExceptionNotThrown() {
handle( Catch::ResultWas::DidntThrowException ); m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
} }
void AssertionHandler::handleThrowingCallSkipped() { void AssertionHandler::handleThrowingCallSkipped() {
handle( Catch::ResultWas::Ok ); m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
} }
// This is the overload that takes a string and infers the Equals matcher from it // This is the overload that takes a string and infers the Equals matcher from it

View File

@ -16,10 +16,12 @@ namespace Catch {
struct TestFailureException{}; struct TestFailureException{};
struct AssertionResultData; struct AssertionResultData;
struct IResultCapture; struct IResultCapture;
class RunContext;
class LazyExpression { class LazyExpression {
friend class AssertionHandler; friend class AssertionHandler;
friend struct AssertionStats; friend struct AssertionStats;
friend class RunContext;
ITransientExpression const* m_transientExpression = nullptr; ITransientExpression const* m_transientExpression = nullptr;
bool m_isNegated; bool m_isNegated;
@ -33,12 +35,16 @@ namespace Catch {
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
}; };
struct AssertionReaction {
bool shouldDebugBreak = false;
bool shouldThrow = false;
};
class AssertionHandler { class AssertionHandler {
AssertionInfo m_assertionInfo; AssertionInfo m_assertionInfo;
bool m_shouldDebugBreak = false; AssertionReaction m_reaction;
bool m_shouldThrow = false;
bool m_completed = false; bool m_completed = false;
IResultCapture& m_resultCapture; RunContext& m_resultCapture;
public: public:
AssertionHandler AssertionHandler
@ -67,11 +73,6 @@ namespace Catch {
// query // query
auto allowThrows() const -> bool; auto allowThrows() const -> bool;
private:
void handle( ResultWas::OfType resultType );
void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated );
void handle( AssertionResultData const& resultData, ITransientExpression const* expr );
}; };
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );

View File

@ -27,8 +27,6 @@ namespace Catch {
virtual ~IResultCapture(); virtual ~IResultCapture();
virtual void assertionStarting( AssertionInfo const& info ) = 0;
virtual void assertionEnded( AssertionResult const& result ) = 0;
virtual bool sectionStarted( SectionInfo const& sectionInfo, virtual bool sectionStarted( SectionInfo const& sectionInfo,
Counts& assertions ) = 0; Counts& assertions ) = 0;
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;

View File

@ -40,7 +40,8 @@ namespace Catch {
m_context(getCurrentMutableContext()), m_context(getCurrentMutableContext()),
m_config(_config), m_config(_config),
m_reporter(std::move(reporter)), m_reporter(std::move(reporter)),
m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal },
m_includeSuccessfulResults( m_config->includeSuccessfulResults() )
{ {
m_context.setRunner(this); m_context.setRunner(this);
m_context.setConfig(m_config); m_context.setConfig(m_config);
@ -109,9 +110,6 @@ namespace Catch {
return *m_reporter; return *m_reporter;
} }
void RunContext::assertionStarting(AssertionInfo const& info) {
m_reporter->assertionStarting( info );
}
void RunContext::assertionEnded(AssertionResult const & result) { void RunContext::assertionEnded(AssertionResult const & result) {
if (result.getResultType() == ResultWas::Ok) { if (result.getResultType() == ResultWas::Ok) {
m_totals.assertions.passed++; m_totals.assertions.passed++;
@ -223,7 +221,7 @@ namespace Catch {
tempResult.message = message; tempResult.message = message;
AssertionResult result(m_lastAssertionInfo, tempResult); AssertionResult result(m_lastAssertionInfo, tempResult);
getResultCapture().assertionEnded(result); assertionEnded(result);
handleUnfinishedSections(); handleUnfinishedSections();
@ -296,14 +294,9 @@ namespace Catch {
} catch (...) { } catch (...) {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin. // are reported without translation at the point of origin.
if (m_shouldReportUnexpected) { if( m_shouldReportUnexpected ) {
AssertionHandler handler AssertionReaction dummyReaction;
( m_lastAssertionInfo.macroName, handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition );
handler.handleUnexpectedInflightException();
handler.setCompleted();
} }
} }
m_testCaseTracker->close(); m_testCaseTracker->close();
@ -333,6 +326,119 @@ namespace Catch {
m_unfinishedSections.clear(); m_unfinishedSections.clear();
} }
void RunContext::handleExpr(
AssertionInfo const& info,
ITransientExpression const& expr,
AssertionReaction& reaction
) {
m_reporter->assertionStarting( info );
assertionRun();
bool negated = isFalseTest( info.resultDisposition );
bool result = expr.getResult() != negated;
if( result ) {
if (!m_includeSuccessfulResults) {
assertionRun();
assertionPassed();
}
else {
reportExpr(info, ResultWas::Ok, &expr, negated);
}
}
else {
reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
populateReaction( reaction );
}
}
void RunContext::reportExpr(
AssertionInfo const &info,
ResultWas::OfType resultType,
ITransientExpression const *expr,
bool negated ) {
m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( negated ) );
AssertionResult assertionResult{ info, data };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
assertionEnded( assertionResult );
}
void RunContext::handleMessage(
AssertionInfo const& info,
ResultWas::OfType resultType,
StringRef const &message,
AssertionReaction& reaction
) {
m_reporter->assertionStarting( info );
m_lastAssertionInfo = info;
assertionRun();
AssertionResultData data( resultType, LazyExpression( false ) );
data.message = message;
AssertionResult assertionResult{ m_lastAssertionInfo, data };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
populateReaction( reaction );
}
void RunContext::handleUnexpectedExceptionNotThrown(
AssertionInfo const& info,
AssertionReaction& reaction
) {
handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
}
void RunContext::handleUnexpectedInflightException(
AssertionInfo const& info,
std::string const& message,
AssertionReaction& reaction
) {
m_lastAssertionInfo = info;
assertionRun();
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = message;
AssertionResult assertionResult{ info, data };
assertionEnded( assertionResult );
populateReaction( reaction );
}
void RunContext::populateReaction( AssertionReaction& reaction ) {
reaction.shouldDebugBreak = m_config->shouldDebugBreak();
reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
}
void RunContext::handleIncomplete(
AssertionInfo const& info
) {
m_lastAssertionInfo = info;
assertionRun();
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
AssertionResult assertionResult{ info, data };
assertionEnded( assertionResult );
}
void RunContext::handleNonExpr(
AssertionInfo const &info,
ResultWas::OfType resultType,
AssertionReaction &reaction
) {
m_lastAssertionInfo = info;
assertionRun();
AssertionResultData data( resultType, LazyExpression( false ) );
AssertionResult assertionResult{ info, data };
assertionEnded( assertionResult );
if( !assertionResult.isOk() )
populateReaction( reaction );
}
IResultCapture& getResultCapture() { IResultCapture& getResultCapture() {
if (auto* capture = getCurrentContext().getResultCapture()) if (auto* capture = getCurrentContext().getResultCapture())
return *capture; return *capture;

View File

@ -75,11 +75,41 @@ namespace Catch {
IConfigPtr config() const; IConfigPtr config() const;
IStreamingReporter& reporter() const; IStreamingReporter& reporter() const;
private: // IResultCapture // Assertion handlers
void handleExpr
( AssertionInfo const& info,
ITransientExpression const& expr,
AssertionReaction& reaction );
void handleMessage
( AssertionInfo const& info,
ResultWas::OfType resultType,
StringRef const &message,
AssertionReaction& reaction );
void handleUnexpectedExceptionNotThrown
( AssertionInfo const& info,
AssertionReaction& reaction );
void handleUnexpectedInflightException
( AssertionInfo const& info,
std::string const& message,
AssertionReaction& reaction );
void handleIncomplete
( AssertionInfo const& info );
void handleNonExpr
( AssertionInfo const &info,
ResultWas::OfType resultType,
AssertionReaction &reaction );
void reportExpr
(AssertionInfo const &info,
ResultWas::OfType resultType,
ITransientExpression const *expr,
bool negated );
void assertionStarting(AssertionInfo const& info) override; void populateReaction( AssertionReaction& reaction );
void assertionEnded(AssertionResult const& result) override;
public: // IResultCapture
void assertionEnded(AssertionResult const& result); // devirt
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
bool testForMissingAssertions(Counts& assertions); bool testForMissingAssertions(Counts& assertions);
@ -103,9 +133,9 @@ namespace Catch {
bool lastAssertionPassed() override; bool lastAssertionPassed() override;
void assertionPassed() override; void assertionPassed() override; // devirt
void assertionRun() override; void assertionRun() override; // devirt
public: public:
// !TBD We need to do this another way! // !TBD We need to do this another way!
@ -138,6 +168,7 @@ namespace Catch {
TrackerContext m_trackerContext; TrackerContext m_trackerContext;
std::size_t m_prevPassed = 0; std::size_t m_prevPassed = 0;
bool m_shouldReportUnexpected = true; bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
}; };
IResultCapture& getResultCapture(); IResultCapture& getResultCapture();