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_interfaces_registry_hub.h"
#include "catch_capture_matchers.h"
#include "catch_run_context.h"
#include <cassert>
@ -57,58 +58,19 @@ namespace Catch {
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() )
{
m_resultCapture.assertionStarting( m_assertionInfo );
}
m_resultCapture( static_cast<RunContext&>( getResultCapture() ) )
{}
AssertionHandler::~AssertionHandler() {
if ( !m_completed ) {
handleMessage(ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE");
m_resultCapture.exceptionEarlyReported();
}
if ( !m_completed )
m_resultCapture.handleIncomplete( m_assertionInfo );
}
void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
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 );
m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
}
void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const &message) {
AssertionResultData data( resultType, LazyExpression( false ) );
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);
}
m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
}
auto AssertionHandler::allowThrows() const -> bool {
@ -117,7 +79,7 @@ namespace Catch {
void AssertionHandler::complete() {
setCompleted();
if( m_shouldDebugBreak ) {
if( m_reaction.shouldDebugBreak ) {
// 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)
@ -125,7 +87,7 @@ namespace Catch {
// (To go back to the test and change execution, jump over the throw, next)
CATCH_BREAK_INTO_DEBUGGER();
}
if( m_shouldThrow )
if( m_reaction.shouldThrow )
throw Catch::TestFailureException();
}
void AssertionHandler::setCompleted() {
@ -133,22 +95,22 @@ namespace Catch {
}
void AssertionHandler::handleUnexpectedInflightException() {
handleMessage(ResultWas::ThrewException, Catch::translateActiveException());
m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
}
void AssertionHandler::handleExceptionThrownAsExpected() {
handle( Catch::ResultWas::Ok );
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
}
void AssertionHandler::handleExceptionNotThrownAsExpected() {
handle( Catch::ResultWas::Ok );
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
}
void AssertionHandler::handleUnexpectedExceptionNotThrown() {
handle( Catch::ResultWas::DidntThrowException );
m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
}
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

View File

@ -16,10 +16,12 @@ namespace Catch {
struct TestFailureException{};
struct AssertionResultData;
struct IResultCapture;
class RunContext;
class LazyExpression {
friend class AssertionHandler;
friend struct AssertionStats;
friend class RunContext;
ITransientExpression const* m_transientExpression = nullptr;
bool m_isNegated;
@ -33,12 +35,16 @@ namespace Catch {
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
};
struct AssertionReaction {
bool shouldDebugBreak = false;
bool shouldThrow = false;
};
class AssertionHandler {
AssertionInfo m_assertionInfo;
bool m_shouldDebugBreak = false;
bool m_shouldThrow = false;
AssertionReaction m_reaction;
bool m_completed = false;
IResultCapture& m_resultCapture;
RunContext& m_resultCapture;
public:
AssertionHandler
@ -67,11 +73,6 @@ namespace Catch {
// query
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 );

View File

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

View File

@ -40,7 +40,8 @@ namespace Catch {
m_context(getCurrentMutableContext()),
m_config(_config),
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.setConfig(m_config);
@ -109,9 +110,6 @@ namespace Catch {
return *m_reporter;
}
void RunContext::assertionStarting(AssertionInfo const& info) {
m_reporter->assertionStarting( info );
}
void RunContext::assertionEnded(AssertionResult const & result) {
if (result.getResultType() == ResultWas::Ok) {
m_totals.assertions.passed++;
@ -223,7 +221,7 @@ namespace Catch {
tempResult.message = message;
AssertionResult result(m_lastAssertionInfo, tempResult);
getResultCapture().assertionEnded(result);
assertionEnded(result);
handleUnfinishedSections();
@ -296,14 +294,9 @@ namespace Catch {
} catch (...) {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
if (m_shouldReportUnexpected) {
AssertionHandler handler
( m_lastAssertionInfo.macroName,
m_lastAssertionInfo.lineInfo,
m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition );
handler.handleUnexpectedInflightException();
handler.setCompleted();
if( m_shouldReportUnexpected ) {
AssertionReaction dummyReaction;
handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
}
}
m_testCaseTracker->close();
@ -333,6 +326,119 @@ namespace Catch {
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() {
if (auto* capture = getCurrentContext().getResultCapture())
return *capture;

View File

@ -75,11 +75,41 @@ namespace Catch {
IConfigPtr config() 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 assertionEnded(AssertionResult const& result) override;
void populateReaction( AssertionReaction& reaction );
public: // IResultCapture
void assertionEnded(AssertionResult const& result); // devirt
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
bool testForMissingAssertions(Counts& assertions);
@ -103,9 +133,9 @@ namespace Catch {
bool lastAssertionPassed() override;
void assertionPassed() override;
void assertionPassed() override; // devirt
void assertionRun() override;
void assertionRun() override; // devirt
public:
// !TBD We need to do this another way!
@ -138,6 +168,7 @@ namespace Catch {
TrackerContext m_trackerContext;
std::size_t m_prevPassed = 0;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
};
IResultCapture& getResultCapture();