From 5e60050299ace9652c50103b8febbb0e4be67475 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 01:02:24 +0100 Subject: [PATCH 01/20] Removed default ctors for AssertionInfo, AssertionResult and SourceLineInfo --- include/internal/catch_assertionresult.cpp | 2 -- include/internal/catch_assertionresult.h | 3 +-- include/internal/catch_common.cpp | 1 - include/internal/catch_common.h | 4 ++-- include/internal/catch_notimplemented_exception.cpp | 3 +-- include/internal/catch_notimplemented_exception.h | 1 - include/internal/catch_run_context.cpp | 8 +++++--- include/internal/catch_run_context.hpp | 2 +- projects/SelfTest/PartTrackerTests.cpp | 2 +- 9 files changed, 11 insertions(+), 15 deletions(-) diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index 9a4b0c65..63c8b22c 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -49,8 +49,6 @@ namespace Catch { return reconstructedExpression; } - AssertionResult::AssertionResult() {} - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 89a96298..eac589c6 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -39,7 +39,7 @@ namespace Catch { struct AssertionInfo { - AssertionInfo() = default; + AssertionInfo() = delete; AssertionInfo( char const * _macroName, SourceLineInfo const& _lineInfo, char const * _capturedExpression, @@ -66,7 +66,6 @@ namespace Catch { class AssertionResult { public: - AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); diff --git a/include/internal/catch_common.cpp b/include/internal/catch_common.cpp index 753b9487..01c18ba4 100644 --- a/include/internal/catch_common.cpp +++ b/include/internal/catch_common.cpp @@ -15,7 +15,6 @@ namespace Catch { - SourceLineInfo::SourceLineInfo() noexcept : file(""), line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept : file( _file ), line( _line ) diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index c62fafe2..269643ae 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -47,10 +47,10 @@ namespace Catch { struct SourceLineInfo { - SourceLineInfo() noexcept; + SourceLineInfo() = delete; SourceLineInfo( char const* _file, std::size_t _line ) noexcept; - SourceLineInfo(SourceLineInfo const& other) = default; + SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; diff --git a/include/internal/catch_notimplemented_exception.cpp b/include/internal/catch_notimplemented_exception.cpp index 62188ef3..f44d8e10 100644 --- a/include/internal/catch_notimplemented_exception.cpp +++ b/include/internal/catch_notimplemented_exception.cpp @@ -11,8 +11,7 @@ namespace Catch { - NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) - : m_lineInfo( lineInfo ) { + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) { std::ostringstream oss; oss << lineInfo << ": function "; oss << "not implemented"; diff --git a/include/internal/catch_notimplemented_exception.h b/include/internal/catch_notimplemented_exception.h index 4769c57d..19e185b6 100644 --- a/include/internal/catch_notimplemented_exception.h +++ b/include/internal/catch_notimplemented_exception.h @@ -25,7 +25,6 @@ namespace Catch { private: std::string m_what; - SourceLineInfo m_lineInfo; }; } // end namespace Catch diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index b54742ff..57e79ef6 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -19,10 +19,12 @@ namespace Catch { } RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) - : m_runInfo(_config->name()), + : m_runInfo(_config->name()), m_context(getCurrentMutableContext()), m_config(_config), - m_reporter(std::move(reporter)) { + m_reporter(std::move(reporter)), + m_lastAssertionInfo( "", SourceLineInfo("",0), "", ResultDisposition::Normal ) + { m_context.setRunner(this); m_context.setConfig(m_config); m_context.setResultCapture(this); @@ -180,7 +182,7 @@ namespace Catch { } const AssertionResult * RunContext::getLastResult() const { - return &m_lastResult; + return &(*m_lastResult); } void RunContext::exceptionEarlyReported() { diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index ee923e88..9e9f8974 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -111,7 +111,7 @@ namespace Catch { IMutableContext& m_context; TestCase const* m_activeTestCase = nullptr; ITracker* m_testCaseTracker; - AssertionResult m_lastResult; + Option m_lastResult; IConfigPtr m_config; Totals m_totals; diff --git a/projects/SelfTest/PartTrackerTests.cpp b/projects/SelfTest/PartTrackerTests.cpp index ff21e74d..26473de2 100644 --- a/projects/SelfTest/PartTrackerTests.cpp +++ b/projects/SelfTest/PartTrackerTests.cpp @@ -37,7 +37,7 @@ using namespace Catch; //} Catch::TestCaseTracking::NameAndLocation makeNAL( std::string const& name ) { - return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo() ); + return Catch::TestCaseTracking::NameAndLocation( name, Catch::SourceLineInfo("",0) ); } TEST_CASE( "Tracker" ) { From 59f9bcf1ed38afc363dbb899e38821a44132589c Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 01:08:07 +0100 Subject: [PATCH 02/20] Reduced AssertionInfo to a pure record type --- include/internal/catch_assertionresult.cpp | 14 +------------- include/internal/catch_assertionresult.h | 21 ++++++--------------- include/internal/catch_result_builder.cpp | 2 +- include/internal/catch_run_context.cpp | 6 +++--- 4 files changed, 11 insertions(+), 32 deletions(-) diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index 63c8b22c..f6bb2cfb 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -14,17 +14,7 @@ namespace Catch { bool DecomposedExpression::isBinaryExpression() const { return false; } - - AssertionInfo::AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition) - : macroName( _macroName ), - lineInfo( _lineInfo ), - capturedExpression( _capturedExpression ), - resultDisposition( _resultDisposition ) - {} - + void AssertionResultData::negate( bool parenthesize ) { negated = !negated; parenthesized = parenthesize; @@ -54,8 +44,6 @@ namespace Catch { m_resultData( data ) {} - AssertionResult::~AssertionResult() {} - // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index eac589c6..8c0d198a 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -39,16 +39,12 @@ namespace Catch { struct AssertionInfo { - AssertionInfo() = delete; - AssertionInfo( char const * _macroName, - SourceLineInfo const& _lineInfo, - char const * _capturedExpression, - ResultDisposition::Flags _resultDisposition); - - char const * macroName = nullptr; + char const * macroName; SourceLineInfo lineInfo; - char const * capturedExpression = nullptr; - ResultDisposition::Flags resultDisposition = ResultDisposition::Normal; + char const * capturedExpression; + ResultDisposition::Flags resultDisposition; + + AssertionInfo() = delete; }; struct AssertionResultData @@ -66,13 +62,8 @@ namespace Catch { class AssertionResult { public: + AssertionResult() = delete; AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - ~AssertionResult(); - - AssertionResult( AssertionResult const& ) = default; - AssertionResult( AssertionResult && ) = default; - AssertionResult& operator = ( AssertionResult const& ) = default; - AssertionResult& operator = ( AssertionResult && ) = default; bool isOk() const; bool succeeded() const; diff --git a/include/internal/catch_result_builder.cpp b/include/internal/catch_result_builder.cpp index b3a7f28f..c154010a 100644 --- a/include/internal/catch_result_builder.cpp +++ b/include/internal/catch_result_builder.cpp @@ -34,7 +34,7 @@ namespace Catch { SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 57e79ef6..8b89df9c 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -23,7 +23,7 @@ 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_context.setRunner(this); m_context.setConfig(m_config); @@ -107,7 +107,7 @@ namespace Catch { static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); // Reset working state - m_lastAssertionInfo = AssertionInfo("", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition); + m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; m_lastResult = result; } @@ -250,7 +250,7 @@ namespace Catch { double duration = 0; m_shouldReportUnexpected = true; try { - m_lastAssertionInfo = AssertionInfo("TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal); + m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; seedRng(*m_config); From f8148ebae1e07c5609ed0af5993694e2972d0dfd Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 01:22:21 +0100 Subject: [PATCH 03/20] Made macroName and capturedExpression StringRefs --- include/internal/catch_assertionresult.cpp | 12 ++++++------ include/internal/catch_assertionresult.h | 5 +++-- include/internal/catch_interfaces_reporter.cpp | 2 +- include/internal/catch_result_builder.cpp | 8 ++++---- include/internal/catch_result_builder.h | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index f6bb2cfb..6819cd63 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -14,7 +14,7 @@ namespace Catch { bool DecomposedExpression::isBinaryExpression() const { return false; } - + void AssertionResultData::negate( bool parenthesize ) { negated = !negated; parenthesized = parenthesize; @@ -68,16 +68,16 @@ namespace Catch { std::string AssertionResult::getExpression() const { if (isFalseTest(m_info.resultDisposition)) - return '!' + std::string(m_info.capturedExpression); + return '!' + std::string(m_info.capturedExpression.c_str()); else - return std::string(m_info.capturedExpression); + return std::string(m_info.capturedExpression.c_str()); } std::string AssertionResult::getExpressionInMacro() const { if( m_info.macroName[0] == 0 ) - return std::string(m_info.capturedExpression); + return std::string(m_info.capturedExpression.c_str()); else - return std::string(m_info.macroName) + "( " + m_info.capturedExpression + " )"; + return std::string(m_info.macroName.c_str()) + "( " + m_info.capturedExpression.c_str() + " )"; } bool AssertionResult::hasExpandedExpression() const { @@ -96,7 +96,7 @@ namespace Catch { } std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; + return m_info.macroName.c_str(); } void AssertionResult::discardDecomposedExpression() const { diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 8c0d198a..7e67faaa 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -11,6 +11,7 @@ #include #include "catch_result_type.h" #include "catch_common.h" +#include "catch_stringref.h" namespace Catch { @@ -39,9 +40,9 @@ namespace Catch { struct AssertionInfo { - char const * macroName; + StringRef macroName; SourceLineInfo lineInfo; - char const * capturedExpression; + StringRef capturedExpression; ResultDisposition::Flags resultDisposition; AssertionInfo() = delete; diff --git a/include/internal/catch_interfaces_reporter.cpp b/include/internal/catch_interfaces_reporter.cpp index 8ad16248..2f820bf8 100644 --- a/include/internal/catch_interfaces_reporter.cpp +++ b/include/internal/catch_interfaces_reporter.cpp @@ -40,7 +40,7 @@ namespace Catch { if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + MessageBuilder builder( assertionResult.getTestMacroName().c_str(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); diff --git a/include/internal/catch_result_builder.cpp b/include/internal/catch_result_builder.cpp index c154010a..a908c359 100644 --- a/include/internal/catch_result_builder.cpp +++ b/include/internal/catch_result_builder.cpp @@ -30,9 +30,9 @@ namespace Catch { } - ResultBuilder::ResultBuilder( char const* macroName, + ResultBuilder::ResultBuilder( StringRef macroName, SourceLineInfo const& lineInfo, - char const* capturedExpression, + StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } { @@ -99,7 +99,7 @@ namespace Catch { assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); AssertionResultData data = m_data; data.resultType = ResultWas::Ok; - data.reconstructedExpression = m_assertionInfo.capturedExpression; + data.reconstructedExpression = m_assertionInfo.capturedExpression.c_str(); std::string actualMessage = Catch::translateActiveException(); if( !matcher.match( actualMessage ) ) { @@ -166,7 +166,7 @@ namespace Catch { } void ResultBuilder::reconstructExpression( std::string& dest ) const { - dest = m_assertionInfo.capturedExpression; + dest = m_assertionInfo.capturedExpression.c_str(); } void ResultBuilder::setExceptionGuard() { diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index 6639b541..1ccdd9c0 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -31,9 +31,9 @@ namespace Catch { class ResultBuilder : public DecomposedExpression { public: - ResultBuilder( char const* macroName, + ResultBuilder( StringRef macroName, SourceLineInfo const& lineInfo, - char const* capturedExpression, + StringRef capturedExpression, ResultDisposition::Flags resultDisposition); ~ResultBuilder(); From f247ce5bff025281d4a7e9fa76aa78eb8479ddfe Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 17:53:01 +0100 Subject: [PATCH 04/20] First cut of new AssertionHandler/ Decomposer - integrated into INTERNAL_CATCH_TEST. Needs more work to fully replace existing stuff --- CMakeLists.txt | 5 + include/internal/catch_assertionhandler.cpp | 135 ++++++++++++++++ include/internal/catch_assertionhandler.h | 61 +++++++ include/internal/catch_assertioninfo.h | 29 ++++ include/internal/catch_assertionresult.cpp | 36 +++-- include/internal/catch_assertionresult.h | 36 +++-- include/internal/catch_capture.hpp | 14 +- include/internal/catch_decomposer.cpp | 23 +++ include/internal/catch_decomposer.h | 149 ++++++++++++++++++ .../internal/catch_interfaces_reporter.cpp | 2 + include/internal/catch_result_builder.cpp | 4 +- include/internal/catch_result_builder.h | 6 +- include/internal/catch_run_context.cpp | 2 +- include/reporters/catch_reporter_bases.hpp | 6 +- 14 files changed, 469 insertions(+), 39 deletions(-) create mode 100644 include/internal/catch_assertionhandler.cpp create mode 100644 include/internal/catch_assertionhandler.h create mode 100644 include/internal/catch_assertioninfo.h create mode 100644 include/internal/catch_decomposer.cpp create mode 100644 include/internal/catch_decomposer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 211bfd9d..e454e330 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,8 @@ CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external) # Please keep these ordered alphabetically set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_approx.hpp + ${HEADER_DIR}/internal/catch_assertionhandler.h + ${HEADER_DIR}/internal/catch_assertioninfo.h ${HEADER_DIR}/internal/catch_assertionresult.h ${HEADER_DIR}/internal/catch_capture.hpp ${HEADER_DIR}/internal/catch_clara.h @@ -132,6 +134,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_console_colour.hpp ${HEADER_DIR}/internal/catch_context.h ${HEADER_DIR}/internal/catch_debugger.h + ${HEADER_DIR}/internal/catch_decomposer.h ${HEADER_DIR}/internal/catch_default_main.hpp ${HEADER_DIR}/internal/catch_enforce.h ${HEADER_DIR}/internal/catch_errno_guard.h @@ -198,6 +201,7 @@ set(INTERNAL_HEADERS ) set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_approx.cpp + ${HEADER_DIR}/internal/catch_assertionhandler.cpp ${HEADER_DIR}/internal/catch_assertionresult.cpp ${HEADER_DIR}/internal/catch_benchmark.cpp ${HEADER_DIR}/internal/catch_commandline.cpp @@ -206,6 +210,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_console_colour.cpp ${HEADER_DIR}/internal/catch_context.cpp ${HEADER_DIR}/internal/catch_debugger.cpp + ${HEADER_DIR}/internal/catch_decomposer.cpp ${HEADER_DIR}/internal/catch_errno_guard.cpp ${HEADER_DIR}/internal/catch_evaluate.cpp ${HEADER_DIR}/internal/catch_exception_translator_registry.cpp diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp new file mode 100644 index 00000000..a71a2dc2 --- /dev/null +++ b/include/internal/catch_assertionhandler.cpp @@ -0,0 +1,135 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "catch_assertionhandler.h" +#include "catch_assertionresult.h" +#include "catch_interfaces_capture.h" +#include "catch_interfaces_runner.h" +#include "catch_context.h" +#include "catch_debugger.h" +#include "catch_interfaces_registry_hub.h" + +#include // !TBD + +namespace Catch { + + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } + { + getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); + } + + void AssertionHandler::handle( ITransientExpression const& expr ) { + + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + bool result = expr.getResult() != negated; + + AssertionResultData data( result ? ResultWas::Ok : ResultWas::ExpressionFailed, LazyExpression( negated ) ); + + // Deprecated +// data.negated = negated; +// data.parenthesized = negated && expr.isBinaryExpression(); // !TBD: needed? +// data.decomposedExpression = nullptr; // !TBD +// data.reconstructedExpression = ""; // !TBD + + + getResultCapture().assertionRun(); + + AssertionResult assertionResult{ m_assertionInfo, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = &expr; + + getResultCapture().assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) { + m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); + m_shouldThrow = + getCurrentContext().getRunner()->aborting() || + (m_assertionInfo.resultDisposition & ResultDisposition::Normal); + } + } + + auto AssertionHandler::shouldDebugBreak() const -> bool { + return m_shouldDebugBreak; + } + void AssertionHandler::reactWithDebugBreak() const { + if (m_shouldDebugBreak) { + /////////////////////////////////////////////////////////////////// + // To inspect the state during test, you need to go one level up the callstack + // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call + /////////////////////////////////////////////////////////////////// + CATCH_BREAK_INTO_DEBUGGER(); + } + reactWithoutDebugBreak(); + } + void AssertionHandler::reactWithoutDebugBreak() const { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + void AssertionHandler::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + useActiveException(); + } + void AssertionHandler::useActiveException() { + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( negated ) ); + data.message = Catch::translateActiveException(); + + //data.decomposedExpression = &expr; // for lazy reconstruction + + AssertionResult result( m_assertionInfo, data ); + + getResultCapture().assertionEnded( result ); + + // !TBD: factor this out? handleResult()? + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) + m_shouldThrow = true; + } + + } + +} // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h new file mode 100644 index 00000000..8c8dff67 --- /dev/null +++ b/include/internal/catch_assertionhandler.h @@ -0,0 +1,61 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED +#define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED + +#include "catch_decomposer.h" +#include "catch_assertioninfo.h" + +namespace Catch { + + struct TestFailureException{}; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + bool m_shouldDebugBreak = false; + bool m_shouldThrow = false; + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + + void handle( ITransientExpression const& expr ); + + template + void handle( ExprLhs const& expr ) { + handle( expr.makeUnaryExpr() ); + } + + auto shouldDebugBreak() const -> bool; + void reactWithDebugBreak() const; + void reactWithoutDebugBreak() const; + void useActiveException( ResultDisposition::Flags resultDisposition ); + void useActiveException(); + }; + +} // namespace Catch + +#endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED diff --git a/include/internal/catch_assertioninfo.h b/include/internal/catch_assertioninfo.h new file mode 100644 index 00000000..21646b21 --- /dev/null +++ b/include/internal/catch_assertioninfo.h @@ -0,0 +1,29 @@ +/* + * Created by Phil on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED +#define TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED + +#include "catch_result_type.h" +#include "catch_common.h" +#include "catch_stringref.h" + +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + AssertionInfo() = delete; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_ASSERTIONINFO_H_INCLUDED diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index 6819cd63..877f53bf 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -24,17 +24,30 @@ namespace Catch { resultType = ResultWas::Ok; } - std::string const& AssertionResultData::reconstructExpression() const { - if( decomposedExpression != nullptr ) { - decomposedExpression->reconstructExpression( reconstructedExpression ); - if( parenthesized ) { - reconstructedExpression.insert( 0, 1, '(' ); - reconstructedExpression.append( 1, ')' ); + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + + // Try new LazyExpression first... + if( lazyExpression ) { + // !TBD Use stringstream for now, but rework above to pass stream in + std::ostringstream oss; + oss << lazyExpression; + reconstructedExpression = oss.str(); } - if( negated ) { - reconstructedExpression.insert( 0, 1, '!' ); + + // ... if not, fall back to decomposedExpression + else if( decomposedExpression != nullptr ) { + decomposedExpression->reconstructExpression( reconstructedExpression ); + if( parenthesized ) { + reconstructedExpression.insert( 0, 1, '(' ); + reconstructedExpression.append( 1, ')' ); + } + if( negated ) { + reconstructedExpression.insert( 0, 1, '!' ); + } + decomposedExpression = nullptr; } - decomposedExpression = nullptr; } return reconstructedExpression; } @@ -85,7 +98,10 @@ namespace Catch { } std::string AssertionResult::getExpandedExpression() const { - return m_resultData.reconstructExpression(); + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; } std::string AssertionResult::getMessage() const { diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 7e67faaa..9bd8e39d 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -9,9 +9,11 @@ #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include +#include "catch_assertioninfo.h" #include "catch_result_type.h" #include "catch_common.h" #include "catch_stringref.h" +#include "catch_assertionhandler.h" namespace Catch { @@ -37,28 +39,32 @@ namespace Catch { template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); }; +} - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - AssertionInfo() = delete; - }; +namespace Catch { struct AssertionResultData { - void negate( bool parenthesize ); - std::string const& reconstructExpression() const; + AssertionResultData() = delete; + + // !TBD We won't need this constructor once the deprecated fields are removed + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ) + : resultType( _resultType ), + lazyExpression( _lazyExpression ) + {} - mutable DecomposedExpression const* decomposedExpression = nullptr; - mutable std::string reconstructedExpression; - std::string message; ResultWas::OfType resultType = ResultWas::Unknown; + std::string message; + + LazyExpression lazyExpression; + + // deprecated: bool negated = false; bool parenthesized = false; + void negate( bool parenthesize ); + std::string reconstructExpression() const; + mutable DecomposedExpression const* decomposedExpression = nullptr; + mutable std::string reconstructedExpression; }; class AssertionResult { @@ -81,7 +87,7 @@ namespace Catch { void discardDecomposedExpression() const; void expandDecomposedExpression() const; - protected: + //protected: AssertionInfo m_info; AssertionResultData m_resultData; }; diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index c5438266..aafafeef 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -8,6 +8,7 @@ #ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED +#include "catch_assertionhandler.h" #include "catch_result_builder.h" #include "catch_message.h" #include "catch_interfaces_capture.h" @@ -43,7 +44,10 @@ // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); + resultBuilder.react(); +#define INTERNAL_CATCH_REACT2( handler ) \ + if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + handler.reactWithDebugBreak(); #define INTERNAL_CATCH_TRY try #define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } @@ -53,13 +57,13 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - ( __catchResult <= __VA_ARGS__ ).endExpression(); \ + catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ - INTERNAL_CATCH_REACT( __catchResult ) \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler, resultDisposition ) \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. diff --git a/include/internal/catch_decomposer.cpp b/include/internal/catch_decomposer.cpp new file mode 100644 index 00000000..6e69bc43 --- /dev/null +++ b/include/internal/catch_decomposer.cpp @@ -0,0 +1,23 @@ +/* + * Created by Phil Nash on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "catch_decomposer.h" +#include "catch_config.hpp" + +namespace Catch { + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ) { + + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} \ No newline at end of file diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h new file mode 100644 index 00000000..82e386a5 --- /dev/null +++ b/include/internal/catch_decomposer.h @@ -0,0 +1,149 @@ +/* + * Created by Phil Nash on 8/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED +#define TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED + +#include "catch_tostring.h" +#include "catch_stringref.h" + +#include + +namespace Catch { + + struct ITransientExpression { + virtual auto isBinaryExpression() const -> bool = 0; + virtual auto getResult() const -> bool = 0; + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + }; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ); + + template + class BinaryExpr : public ITransientExpression { + bool m_result; + LhsT m_lhs; + std::string m_op; + RhsT m_rhs; + + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } + + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } + + public: + BinaryExpr( bool comparisionResult, LhsT lhs, StringRef op, RhsT rhs ) + : m_result( comparisionResult ), + m_lhs( lhs ), + m_op( op.c_str() ), + m_rhs( rhs ) + {} + }; + + template + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; + + auto isBinaryExpression() const -> bool override { return false; } + auto getResult() const -> bool override { return m_lhs ? true : false; } + + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } + + public: + UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} + }; + + + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template + auto compareEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs == rhs; }; + template + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); }; + template + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; }; + + template + auto compareNotEqual( LhsT lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; + template + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); }; + template + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; }; + + + template + class ExprLhs { + LhsT m_lhs; + public: + ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + + template + auto operator == ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); + } + auto operator == ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); + } + + template + auto operator != ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); + } + auto operator != ( bool rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); + } + + template + auto operator > ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); + } + template + auto operator < ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); + } + template + auto operator >= ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); + } + template + auto operator <= ( RhsT&& rhs ) -> BinaryExpr const { + return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); + } + + auto makeUnaryExpr() const -> UnaryExpr { + return UnaryExpr( m_lhs ); + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template + void handleExpression( ExprLhs const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template + auto operator <= ( T& lhs ) -> ExprLhs { + return ExprLhs( lhs ); + } + template + auto operator <= ( T const& lhs ) -> ExprLhs { + return ExprLhs( lhs ); + } + auto operator <=( bool value ) -> ExprLhs { + return ExprLhs( value ); + } + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED diff --git a/include/internal/catch_interfaces_reporter.cpp b/include/internal/catch_interfaces_reporter.cpp index 2f820bf8..05117f9e 100644 --- a/include/internal/catch_interfaces_reporter.cpp +++ b/include/internal/catch_interfaces_reporter.cpp @@ -37,6 +37,8 @@ namespace Catch { infoMessages( _infoMessages ), totals( _totals ) { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere diff --git a/include/internal/catch_result_builder.cpp b/include/internal/catch_result_builder.cpp index a908c359..db7dfb14 100644 --- a/include/internal/catch_result_builder.cpp +++ b/include/internal/catch_result_builder.cpp @@ -13,7 +13,6 @@ #include "catch_interfaces_capture.h" #include "catch_interfaces_registry_hub.h" #include "catch_matchers_string.h" -#include "catch_wildcard_pattern.hpp" #include "catch_debugger.h" #include @@ -34,7 +33,8 @@ namespace Catch { SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_data( ResultWas::Unknown, LazyExpression( false ) ) { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h index 1ccdd9c0..6d3a9efc 100644 --- a/include/internal/catch_result_builder.h +++ b/include/internal/catch_result_builder.h @@ -8,8 +8,10 @@ #ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED -#include "catch_result_type.h" #include "catch_assertionresult.h" +#include "catch_decomposer.h" + +#include "catch_result_type.h" #include "catch_common.h" #include "catch_matchers.hpp" @@ -17,8 +19,6 @@ namespace Catch { - struct TestFailureException{}; - template class ExpressionLhs; struct CopyableStream { diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 8b89df9c..509a18e6 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -192,7 +192,7 @@ namespace Catch { void RunContext::handleFatalErrorCondition(std::string const & message) { // Don't rebuild the result -- the stringification itself can cause more fatal errors // Instead, fake a result data. - AssertionResultData tempResult; + AssertionResultData tempResult( ResultWas::Unknown, { false } ); tempResult.resultType = ResultWas::FatalErrorCondition; tempResult.message = message; AssertionResult result(m_lastAssertionInfo, tempResult); diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index 37cc4e00..2f9a8013 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -193,14 +193,14 @@ namespace Catch { bool assertionEnded(AssertionStats const& assertionStats) override { assert(!m_sectionStack.empty()); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); // AssertionResult holds a pointer to a temporary DecomposedExpression, // which getExpandedExpression() calls to build the expression string. // Our section stack copy of the assertionResult will likely outlive the // temporary, so it must be expanded or discarded now to avoid calling // a destroyed object later. - prepareExpandedExpression(sectionNode.assertions.back().assertionResult); + prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); return true; } void sectionEnded(SectionStats const& sectionStats) override { From f033f4f1842cb3859b97855261d3119488783b20 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 19:36:18 +0100 Subject: [PATCH 05/20] integrated AssertionHandler into INTERNAL_CATCH_NO_THROW --- include/internal/catch_assertionhandler.cpp | 46 ++++++++------------- include/internal/catch_assertionhandler.h | 4 ++ include/internal/catch_capture.hpp | 11 ++--- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index a71a2dc2..1b7e1346 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -59,24 +59,17 @@ namespace Catch { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } - void AssertionHandler::handle( ITransientExpression const& expr ) { - - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; - - AssertionResultData data( result ? ResultWas::Ok : ResultWas::ExpressionFailed, LazyExpression( negated ) ); - - // Deprecated -// data.negated = negated; -// data.parenthesized = negated && expr.isBinaryExpression(); // !TBD: needed? -// data.decomposedExpression = nullptr; // !TBD -// data.reconstructedExpression = ""; // !TBD + 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 ) { getResultCapture().assertionRun(); - AssertionResult assertionResult{ m_assertionInfo, data }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = &expr; + AssertionResult assertionResult{ m_assertionInfo, resultData }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; getResultCapture().assertionEnded( assertionResult ); @@ -87,6 +80,16 @@ namespace Catch { (m_assertionInfo.resultDisposition & ResultDisposition::Normal); } } + void AssertionHandler::handle( ITransientExpression const& expr ) { + + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + bool result = expr.getResult() != negated; + + handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); + } + void AssertionHandler::handle( ResultWas::OfType resultType ) { + handle( resultType, nullptr, false ); + } auto AssertionHandler::shouldDebugBreak() const -> bool { return m_shouldDebugBreak; @@ -116,20 +119,7 @@ namespace Catch { AssertionResultData data( ResultWas::ThrewException, LazyExpression( negated ) ); data.message = Catch::translateActiveException(); - //data.decomposedExpression = &expr; // for lazy reconstruction - - AssertionResult result( m_assertionInfo, data ); - - getResultCapture().assertionEnded( result ); - - // !TBD: factor this out? handleResult()? - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) - m_shouldThrow = true; - } - + handle( data, nullptr ); } } // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 8c8dff67..0c8b020b 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -14,6 +14,7 @@ namespace Catch { struct TestFailureException{}; + struct AssertionResultData; class LazyExpression { friend class AssertionHandler; @@ -48,6 +49,9 @@ namespace Catch { void handle( ExprLhs const& expr ) { handle( expr.makeUnaryExpr() ); } + void handle( ResultWas::OfType resultType ); + void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); + void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); auto shouldDebugBreak() const -> bool; void reactWithDebugBreak() const; diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index aafafeef..9510d7a5 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -51,6 +51,7 @@ #define INTERNAL_CATCH_TRY try #define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } +#define INTERNAL_CATCH_CATCH2( capturer ) catch(...) { capturer.useActiveException(); } #endif @@ -62,7 +63,7 @@ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler, resultDisposition ) \ + } INTERNAL_CATCH_CATCH2( catchAssertionHandler ) \ INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. @@ -80,15 +81,15 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.useActiveException(); \ } \ - INTERNAL_CATCH_REACT( __catchResult ) \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// From 8a97beece21ac02ba71b03fe33f5ccaba36ff4c0 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 19:43:07 +0100 Subject: [PATCH 06/20] integrated AssertionHandler into INTERNAL_CATCH_THROWS_AS --- include/internal/catch_assertionhandler.cpp | 3 +++ include/internal/catch_assertionhandler.h | 1 + include/internal/catch_capture.hpp | 14 +++++++------- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index 1b7e1346..fe8e32a0 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -90,6 +90,9 @@ namespace Catch { void AssertionHandler::handle( ResultWas::OfType resultType ) { handle( resultType, nullptr, false ); } + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } auto AssertionHandler::shouldDebugBreak() const -> bool { return m_shouldDebugBreak; diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 0c8b020b..6e140e44 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -54,6 +54,7 @@ namespace Catch { void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); auto shouldDebugBreak() const -> bool; + auto allowThrows() const -> bool; void reactWithDebugBreak() const; void reactWithoutDebugBreak() const; void useActiveException( ResultDisposition::Flags resultDisposition ); diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 9510d7a5..68859412 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -112,21 +112,21 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType const& ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.useActiveException(); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) From 5f9172436883c535de4a119bd3b2314a2a5f9f70 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 20:17:09 +0100 Subject: [PATCH 07/20] integrated AssertionHandler into INTERNAL_CATCH_MSG --- include/internal/catch_assertionhandler.cpp | 32 ++++++++++----------- include/internal/catch_assertionhandler.h | 1 + include/internal/catch_capture.hpp | 7 ++--- include/internal/catch_message.h | 15 ++++++++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index fe8e32a0..d53b09fa 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -59,8 +59,22 @@ namespace Catch { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { + void AssertionHandler::handle( ITransientExpression const& expr ) { + bool negated = isFalseTest( m_assertionInfo.resultDisposition ); + bool result = expr.getResult() != negated; + + handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); + } + void AssertionHandler::handle( ResultWas::OfType resultType ) { + handle( resultType, nullptr, false ); + } + void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message.c_str(); + handle( data, nullptr ); + } + void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { AssertionResultData data( resultType, LazyExpression( negated ) ); handle( data, expr ); } @@ -80,16 +94,7 @@ namespace Catch { (m_assertionInfo.resultDisposition & ResultDisposition::Normal); } } - void AssertionHandler::handle( ITransientExpression const& expr ) { - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; - - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); - } auto AssertionHandler::allowThrows() const -> bool { return getCurrentContext().getConfig()->allowThrows(); } @@ -117,12 +122,7 @@ namespace Catch { useActiveException(); } void AssertionHandler::useActiveException() { - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( negated ) ); - data.message = Catch::translateActiveException(); - - handle( data, nullptr ); + handle( ResultWas::ThrewException, Catch::translateActiveException().c_str() ); } } // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 6e140e44..18137448 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -50,6 +50,7 @@ namespace Catch { handle( expr.makeUnaryExpr() ); } void handle( ResultWas::OfType resultType ); + void handle( ResultWas::OfType resultType, StringRef const& message ); void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 68859412..13101ec6 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -133,10 +133,9 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ - __catchResult.captureResult( messageType ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str().c_str() ); \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// diff --git a/include/internal/catch_message.h b/include/internal/catch_message.h index 2550fb41..553882b7 100644 --- a/include/internal/catch_message.h +++ b/include/internal/catch_message.h @@ -32,7 +32,19 @@ namespace Catch { static unsigned int globalCount; }; - struct MessageBuilder { + struct MessageStream { + + template + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + // !TBD reuse a global/ thread-local stream + std::ostringstream m_stream; + }; + + struct MessageBuilder : MessageStream { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ); @@ -44,7 +56,6 @@ namespace Catch { } MessageInfo m_info; - std::ostringstream m_stream; }; class ScopedMessage { From 2832e23aa9b4dab95e9391bfc2a8bf86a778b0fb Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 21:07:30 +0100 Subject: [PATCH 08/20] Restored exceptionGuard functionality under CATCH_CONFIG_FAST_COMPILE --- include/internal/catch_assertionhandler.cpp | 18 +++++++++++++++++- include/internal/catch_assertionhandler.h | 5 +++++ include/internal/catch_capture.hpp | 15 +++++++++------ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index d53b09fa..8d99e3d0 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -14,7 +14,7 @@ #include "catch_debugger.h" #include "catch_interfaces_registry_hub.h" -#include // !TBD +#include namespace Catch { @@ -58,6 +58,12 @@ namespace Catch { { getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); } + AssertionHandler::~AssertionHandler() { + if ( m_inExceptionGuard ) { + handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); + getCurrentContext().getResultCapture()->exceptionEarlyReported(); + } + } void AssertionHandler::handle( ITransientExpression const& expr ) { @@ -125,4 +131,14 @@ namespace Catch { handle( ResultWas::ThrewException, Catch::translateActiveException().c_str() ); } + void AssertionHandler::setExceptionGuard() { + assert( m_inExceptionGuard == false ); + m_inExceptionGuard = true; + } + void AssertionHandler::unsetExceptionGuard() { + assert( m_inExceptionGuard == true ); + m_inExceptionGuard = false; + } + + } // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 18137448..dbbd5157 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -36,12 +36,15 @@ namespace Catch { AssertionInfo m_assertionInfo; bool m_shouldDebugBreak = false; bool m_shouldThrow = false; + bool m_inExceptionGuard = false; + public: AssertionHandler ( StringRef macroName, SourceLineInfo const& lineInfo, StringRef capturedExpression, ResultDisposition::Flags resultDisposition ); + ~AssertionHandler(); void handle( ITransientExpression const& expr ); @@ -60,6 +63,8 @@ namespace Catch { void reactWithoutDebugBreak() const; void useActiveException( ResultDisposition::Flags resultDisposition ); void useActiveException(); + void setExceptionGuard(); + void unsetExceptionGuard(); }; } // namespace Catch diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 13101ec6..b13b9fe6 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -26,14 +26,17 @@ // macro in each assertion #define INTERNAL_CATCH_REACT( resultBuilder ) \ resultBuilder.react(); +#define INTERNAL_CATCH_REACT2( handler ) \ + handler.reactWithDebugBreak(); /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TRY -#define INTERNAL_CATCH_CATCH( capturer, disposition ) +#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); +#define INTERNAL_CATCH_CATCH( capturer, disposition ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_CATCH2( capturer ) capturer.unsetExceptionGuard(); #else // CATCH_CONFIG_FAST_COMPILE @@ -47,9 +50,9 @@ resultBuilder.react(); #define INTERNAL_CATCH_REACT2( handler ) \ if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithDebugBreak(); + handler.reactWithoutDebugBreak(); -#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_TRY( capturer ) try #define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } #define INTERNAL_CATCH_CATCH2( capturer ) catch(...) { capturer.useActiveException(); } @@ -59,7 +62,7 @@ #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition ); \ - INTERNAL_CATCH_TRY { \ + INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ @@ -147,7 +150,7 @@ #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ - INTERNAL_CATCH_TRY { \ + INTERNAL_CATCH_TRY( __catchResult ) { \ __catchResult.captureMatch( arg, matcher, #matcher ); \ } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ INTERNAL_CATCH_REACT( __catchResult ) \ From 9668410b8e415c22d2665a820a1e113acfd6ae64 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 23:31:43 +0100 Subject: [PATCH 09/20] integrated INTERNAL_CHECK_THAT with new AssertionHandler --- include/internal/catch_capture.hpp | 10 ++++----- include/internal/catch_decomposer.h | 32 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index b13b9fe6..ef152dae 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -149,11 +149,11 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ - INTERNAL_CATCH_TRY( __catchResult ) { \ - __catchResult.captureMatch( arg, matcher, #matcher ); \ - } INTERNAL_CATCH_CATCH( __catchResult, resultDisposition ) \ - INTERNAL_CATCH_REACT( __catchResult ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h index 82e386a5..f289387a 100644 --- a/include/internal/catch_decomposer.h +++ b/include/internal/catch_decomposer.h @@ -144,6 +144,38 @@ namespace Catch { } }; + // !TBD: this is just here temporarily + template + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT const& m_matcher; + StringRef m_matcherString; + bool m_result; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ), + m_result( matcher.match( arg ) ) + {} + + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString.c_str(); + else + os << matcherAsString; + } + }; + template + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + return MatchExpr( arg, matcher, matcherString ); + } + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED From ef4fa56b71e7013fe39609abfb25819b618c1177 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 8 Aug 2017 23:41:55 +0100 Subject: [PATCH 10/20] integrated INTERNAL_CATCH_THROWS_MATCHES with new AssertionHandler --- include/internal/catch_capture.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index ef152dae..ee63e044 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -175,23 +175,23 @@ /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, expr ) \ +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType ", " #matcher, resultDisposition ); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #exceptionType ", " #matcher, resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ - static_cast(expr); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + static_cast(__VA_ARGS__ ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType const& ex ) { \ - __catchResult.captureMatch( ex, matcher, #matcher ); \ + catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ } \ catch( ... ) { \ - __catchResult.useActiveException( resultDisposition ); \ + catchAssertionHandler.useActiveException(); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) #endif // CATCH_CONFIG_DISABLE_MATCHERS From 27fd8f80bd883df36c243bc355429977fd665c50 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 00:44:30 +0100 Subject: [PATCH 11/20] Integrated INTERNAL_CATCH_THROWS_STR_MATCHES with new AssertionHandler --- include/internal/catch_assertionhandler.cpp | 10 ++++++++++ include/internal/catch_assertionhandler.h | 6 ++++++ include/internal/catch_capture.hpp | 12 ++++++------ include/internal/catch_decomposer.cpp | 3 +-- include/internal/catch_decomposer.h | 4 +++- .../SelfTest/Baselines/console.std.approved.txt | 2 +- .../SelfTest/Baselines/console.sw.approved.txt | 16 +++++++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 2 +- projects/SelfTest/Baselines/xml.sw.approved.txt | 16 ++++++++-------- 9 files changed, 51 insertions(+), 20 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index 8d99e3d0..26f727a9 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -13,6 +13,7 @@ #include "catch_context.h" #include "catch_debugger.h" #include "catch_interfaces_registry_hub.h" +#include "catch_matchers_string.h" #include @@ -140,5 +141,14 @@ namespace Catch { m_inExceptionGuard = false; } + using StringMatcher = Matchers::Impl::MatcherBase; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + MatchExpr expr( Catch::translateActiveException(), matcher, matcherString ); + handler.handle( expr ); + } + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + } } // namespace Catch diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index dbbd5157..21a09875 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -10,6 +10,7 @@ #include "catch_decomposer.h" #include "catch_assertioninfo.h" +#include "catch_matchers_string.h" // !TBD: for exception matchers namespace Catch { @@ -67,6 +68,11 @@ namespace Catch { void unsetExceptionGuard(); }; + using StringMatcher = Matchers::Impl::MatcherBase; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + } // namespace Catch #endif // TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index ee63e044..6615edf1 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -159,18 +159,18 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureExpectedException( matcher ); \ + handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) diff --git a/include/internal/catch_decomposer.cpp b/include/internal/catch_decomposer.cpp index 6e69bc43..f7da22b5 100644 --- a/include/internal/catch_decomposer.cpp +++ b/include/internal/catch_decomposer.cpp @@ -12,7 +12,6 @@ namespace Catch { void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && lhs.find('\n') == std::string::npos && rhs.find('\n') == std::string::npos ) @@ -20,4 +19,4 @@ namespace Catch { else os << lhs << "\n" << op << "\n" << rhs; } -} \ No newline at end of file +} diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h index f289387a..3182b84a 100644 --- a/include/internal/catch_decomposer.h +++ b/include/internal/catch_decomposer.h @@ -10,6 +10,7 @@ #include "catch_tostring.h" #include "catch_stringref.h" +#include "catch_matchers.hpp" // !TBD: for exception matchers - move this #include @@ -148,7 +149,7 @@ namespace Catch { template class MatchExpr : public ITransientExpression { ArgT const& m_arg; - MatcherT const& m_matcher; + MatcherT m_matcher; StringRef m_matcherString; bool m_result; public: @@ -171,6 +172,7 @@ namespace Catch { os << matcherAsString; } }; + template auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { return MatchExpr( arg, matcher, matcherString ); diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 9e41f7f5..cd406b0c 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -485,7 +485,7 @@ ExceptionTests.cpp: ExceptionTests.cpp:: FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: - expected exception + "expected exception" equals: "should fail" ------------------------------------------------------------------------------- Nice descriptive name diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 971c0e32..80fd38c9 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -1428,6 +1428,8 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) +with expansion: + "expected exception" equals: "expected exception" ------------------------------------------------------------------------------- Exception messages can be tested for @@ -1439,6 +1441,8 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) ) +with expansion: + "expected exception" equals: "expected exception" (case insensitive) ------------------------------------------------------------------------------- Exception messages can be tested for @@ -1450,18 +1454,26 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), StartsWith( "expected" ) ) +with expansion: + "expected exception" starts with: "expected" ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), EndsWith( "exception" ) ) +with expansion: + "expected exception" ends with: "exception" ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), Contains( "except" ) ) +with expansion: + "expected exception" contains: "except" ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) ) +with expansion: + "expected exception" contains: "except" (case insensitive) ------------------------------------------------------------------------------- Expected exceptions that don't throw or unexpected exceptions fail the test @@ -1882,11 +1894,13 @@ ExceptionTests.cpp: ExceptionTests.cpp:: PASSED: REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ) +with expansion: + "expected exception" equals: "expected exception" ExceptionTests.cpp:: FAILED: REQUIRE_THROWS_WITH( thisThrows(), "should fail" ) with expansion: - expected exception + "expected exception" equals: "should fail" ------------------------------------------------------------------------------- Nice descriptive name diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 58807c18..3a1ebdab 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -311,7 +311,7 @@ MatchersTests.cpp: - + ExceptionTests.cpp: diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index e70ad12e..9cec8235 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -1646,7 +1646,7 @@ thisThrows(), "expected exception" - thisThrows(), "expected exception" + "expected exception" equals: "expected exception" @@ -1657,7 +1657,7 @@ thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) - thisThrows(), Equals( "expecteD Exception", Catch::CaseSensitive::No ) + "expected exception" equals: "expected exception" (case insensitive) @@ -1668,7 +1668,7 @@ thisThrows(), StartsWith( "expected" ) - thisThrows(), StartsWith( "expected" ) + "expected exception" starts with: "expected" @@ -1676,7 +1676,7 @@ thisThrows(), EndsWith( "exception" ) - thisThrows(), EndsWith( "exception" ) + "expected exception" ends with: "exception" @@ -1684,7 +1684,7 @@ thisThrows(), Contains( "except" ) - thisThrows(), Contains( "except" ) + "expected exception" contains: "except" @@ -1692,7 +1692,7 @@ thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) - thisThrows(), Contains( "exCept", Catch::CaseSensitive::No ) + "expected exception" contains: "except" (case insensitive) @@ -2172,7 +2172,7 @@ thisThrows(), "expected exception" - thisThrows(), "expected exception" + "expected exception" equals: "expected exception" @@ -2180,7 +2180,7 @@ thisThrows(), "should fail" - expected exception + "expected exception" equals: "should fail" From 201028d6ec787aa92ae12656804b807d2ec849a2 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 00:52:20 +0100 Subject: [PATCH 12/20] Integrated INTERNAL_CATCH_THROWS with new AssertionHandler --- include/internal/catch_capture.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 6615edf1..6c51a3b1 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -98,18 +98,18 @@ /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition); \ - if( __catchResult.allowThrows() ) \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__, resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureExpectedException( "" ); \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ } \ else \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( __catchResult ) \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// From 7df290dfc1a064d087f5252bc1aac5e832a16d7e Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 08:49:59 +0100 Subject: [PATCH 13/20] Integrated new AssertionHandler into unexpected exception handling in RunContext --- include/internal/catch_run_context.cpp | 13 +++++-------- include/internal/catch_run_context.hpp | 2 -- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 509a18e6..b0479797 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -270,7 +270,11 @@ namespace Catch { // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions // are reported without translation at the point of origin. if (m_shouldReportUnexpected) { - makeUnexpectedResultBuilder().useActiveException(); + AssertionHandler + ( m_lastAssertionInfo.macroName, + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression, + m_lastAssertionInfo.resultDisposition ).useActiveException(); } } m_testCaseTracker->close(); @@ -296,13 +300,6 @@ namespace Catch { fatalConditionHandler.reset(); } - ResultBuilder RunContext::makeUnexpectedResultBuilder() const { - return ResultBuilder(m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition); - } - void RunContext::handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index 9e9f8974..a356e3bf 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -103,8 +103,6 @@ namespace Catch { private: - ResultBuilder makeUnexpectedResultBuilder() const; - void handleUnfinishedSections(); TestRunInfo m_runInfo; From 8c95a81448d8216d8d133f6e98f3aae81c44cb76 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 09:08:33 +0100 Subject: [PATCH 14/20] Removed all (well, most) of the redundant, ResultBuilder-based, code --- CMakeLists.txt | 5 - include/internal/catch_assertionresult.cpp | 37 ---- include/internal/catch_assertionresult.h | 34 --- include/internal/catch_capture.hpp | 1 - include/internal/catch_evaluate.cpp | 38 ---- include/internal/catch_evaluate.hpp | 109 ---------- .../catch_exception_translator_registry.cpp | 2 +- include/internal/catch_expression_lhs.hpp | 176 ---------------- include/internal/catch_result_builder.cpp | 193 ------------------ include/internal/catch_result_builder.h | 118 ----------- include/internal/catch_run_context.hpp | 2 +- include/reporters/catch_reporter_bases.cpp | 5 +- 12 files changed, 3 insertions(+), 717 deletions(-) delete mode 100644 include/internal/catch_evaluate.cpp delete mode 100644 include/internal/catch_evaluate.hpp delete mode 100644 include/internal/catch_expression_lhs.hpp delete mode 100644 include/internal/catch_result_builder.cpp delete mode 100644 include/internal/catch_result_builder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e454e330..94f06f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,9 +138,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_default_main.hpp ${HEADER_DIR}/internal/catch_enforce.h ${HEADER_DIR}/internal/catch_errno_guard.h - ${HEADER_DIR}/internal/catch_evaluate.hpp ${HEADER_DIR}/internal/catch_exception_translator_registry.h - ${HEADER_DIR}/internal/catch_expression_lhs.hpp ${HEADER_DIR}/internal/catch_fatal_condition.h ${HEADER_DIR}/internal/catch_impl.hpp ${HEADER_DIR}/internal/catch_interfaces_capture.h @@ -165,7 +163,6 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_reenable_warnings.h ${HEADER_DIR}/internal/catch_reporter_registrars.hpp ${HEADER_DIR}/internal/catch_reporter_registry.hpp - ${HEADER_DIR}/internal/catch_result_builder.h ${HEADER_DIR}/internal/catch_result_type.h ${HEADER_DIR}/internal/catch_run_context.hpp ${HEADER_DIR}/internal/catch_benchmark.h @@ -212,7 +209,6 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_debugger.cpp ${HEADER_DIR}/internal/catch_decomposer.cpp ${HEADER_DIR}/internal/catch_errno_guard.cpp - ${HEADER_DIR}/internal/catch_evaluate.cpp ${HEADER_DIR}/internal/catch_exception_translator_registry.cpp ${HEADER_DIR}/internal/catch_fatal_condition.cpp ${HEADER_DIR}/internal/catch_list.cpp @@ -223,7 +219,6 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_notimplemented_exception.cpp ${HEADER_DIR}/internal/catch_registry_hub.cpp ${HEADER_DIR}/internal/catch_interfaces_reporter.cpp - ${HEADER_DIR}/internal/catch_result_builder.cpp ${HEADER_DIR}/internal/catch_result_type.cpp ${HEADER_DIR}/internal/catch_run_context.cpp ${HEADER_DIR}/internal/catch_section.cpp diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp index 877f53bf..04402000 100644 --- a/include/internal/catch_assertionresult.cpp +++ b/include/internal/catch_assertionresult.cpp @@ -10,44 +10,15 @@ namespace Catch { - - bool DecomposedExpression::isBinaryExpression() const { - return false; - } - - void AssertionResultData::negate( bool parenthesize ) { - negated = !negated; - parenthesized = parenthesize; - if( resultType == ResultWas::Ok ) - resultType = ResultWas::ExpressionFailed; - else if( resultType == ResultWas::ExpressionFailed ) - resultType = ResultWas::Ok; - } - std::string AssertionResultData::reconstructExpression() const { if( reconstructedExpression.empty() ) { - - // Try new LazyExpression first... if( lazyExpression ) { // !TBD Use stringstream for now, but rework above to pass stream in std::ostringstream oss; oss << lazyExpression; reconstructedExpression = oss.str(); } - - // ... if not, fall back to decomposedExpression - else if( decomposedExpression != nullptr ) { - decomposedExpression->reconstructExpression( reconstructedExpression ); - if( parenthesized ) { - reconstructedExpression.insert( 0, 1, '(' ); - reconstructedExpression.append( 1, ')' ); - } - if( negated ) { - reconstructedExpression.insert( 0, 1, '!' ); - } - decomposedExpression = nullptr; - } } return reconstructedExpression; } @@ -115,12 +86,4 @@ namespace Catch { return m_info.macroName.c_str(); } - void AssertionResult::discardDecomposedExpression() const { - m_resultData.decomposedExpression = nullptr; - } - - void AssertionResult::expandDecomposedExpression() const { - m_resultData.reconstructExpression(); - } - } // end namespace Catch diff --git a/include/internal/catch_assertionresult.h b/include/internal/catch_assertionresult.h index 9bd8e39d..b1177fa4 100644 --- a/include/internal/catch_assertionresult.h +++ b/include/internal/catch_assertionresult.h @@ -15,39 +15,12 @@ #include "catch_stringref.h" #include "catch_assertionhandler.h" -namespace Catch { - - struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; - - struct DecomposedExpression - { - DecomposedExpression() = default; - DecomposedExpression( DecomposedExpression const& ) = default; - DecomposedExpression& operator = ( DecomposedExpression const& ) = delete; - - virtual ~DecomposedExpression() = default; - virtual bool isBinaryExpression() const; - virtual void reconstructExpression( std::string& dest ) const = 0; - - // Only simple binary comparisons can be decomposed. - // If more complex check is required then wrap sub-expressions in parentheses. - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); - template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); - }; -} - namespace Catch { struct AssertionResultData { AssertionResultData() = delete; - // !TBD We won't need this constructor once the deprecated fields are removed AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ) : resultType( _resultType ), lazyExpression( _lazyExpression ) @@ -58,12 +31,7 @@ namespace Catch { LazyExpression lazyExpression; - // deprecated: - bool negated = false; - bool parenthesized = false; - void negate( bool parenthesize ); std::string reconstructExpression() const; - mutable DecomposedExpression const* decomposedExpression = nullptr; mutable std::string reconstructedExpression; }; @@ -84,8 +52,6 @@ namespace Catch { std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; - void discardDecomposedExpression() const; - void expandDecomposedExpression() const; //protected: AssertionInfo m_info; diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 6c51a3b1..5332df35 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -9,7 +9,6 @@ #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED #include "catch_assertionhandler.h" -#include "catch_result_builder.h" #include "catch_message.h" #include "catch_interfaces_capture.h" #include "catch_debugger.h" diff --git a/include/internal/catch_evaluate.cpp b/include/internal/catch_evaluate.cpp deleted file mode 100644 index 349f71e7..00000000 --- a/include/internal/catch_evaluate.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Created by Martin on 01/08/2017. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#include "catch_evaluate.hpp" - -#include "catch_enforce.h" - -namespace Catch { -namespace Internal { - - const char* operatorName(Operator op) { - switch (op) { - case IsEqualTo: - return "=="; - case IsNotEqualTo: - return "!="; - case IsLessThan: - return "<"; - case IsGreaterThan: - return ">"; - case IsLessThanOrEqualTo: - return "<="; - case IsGreaterThanOrEqualTo: - return ">="; - default: - CATCH_ERROR("Attempting to translate unknown operator!"); - } - } - - // nullptr_t support based on pull request #154 from Konstantin Baumann - std::nullptr_t opCast(std::nullptr_t) { return nullptr; } - -} // end of namespace Internal -} // end of namespace Catch diff --git a/include/internal/catch_evaluate.hpp b/include/internal/catch_evaluate.hpp deleted file mode 100644 index 33ccd5ef..00000000 --- a/include/internal/catch_evaluate.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Created by Phil on 04/03/2011. - * Copyright 2011 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#endif - -#include - -namespace Catch { -namespace Internal { - - enum Operator { - IsEqualTo, - IsNotEqualTo, - IsLessThan, - IsGreaterThan, - IsLessThanOrEqualTo, - IsGreaterThanOrEqualTo - }; - - const char* operatorName(Operator op); - - template - T& removeConst(T const &t) { return const_cast(t); } - - - // So the compare overloads can be operator agnostic we convey the operator as a template - // enum, which is used to specialise an Evaluator for doing the comparison. - template - struct Evaluator{}; - - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs) { - return bool(removeConst(lhs) == removeConst(rhs) ); - } - template - static bool evaluate( int lhs, T* rhs) { - return reinterpret_cast( lhs ) == rhs; - } - template - static bool evaluate( T* lhs, int rhs) { - return lhs == reinterpret_cast( rhs ); - } - }; - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool(removeConst(lhs) != removeConst(rhs) ); - } - template - static bool evaluate( int lhs, T* rhs) { - return reinterpret_cast( lhs ) != rhs; - } - template - static bool evaluate( T* lhs, int rhs) { - return lhs != reinterpret_cast( rhs ); - } - }; - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool(removeConst(lhs) < removeConst(rhs) ); - } - }; - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool(removeConst(lhs) > removeConst(rhs) ); - } - }; - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool(removeConst(lhs) >= removeConst(rhs) ); - } - }; - template<> - struct Evaluator { - template - static bool evaluate( T1 const& lhs, T2 const& rhs ) { - return bool(removeConst(lhs) <= removeConst(rhs) ); - } - }; - -} // end of namespace Internal -} // end of namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif // TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED diff --git a/include/internal/catch_exception_translator_registry.cpp b/include/internal/catch_exception_translator_registry.cpp index 1a857535..98b92316 100644 --- a/include/internal/catch_exception_translator_registry.cpp +++ b/include/internal/catch_exception_translator_registry.cpp @@ -6,8 +6,8 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ +#include "catch_assertionhandler.h" #include "catch_exception_translator_registry.h" -#include "catch_result_builder.h" #ifdef __OBJC__ #import "Foundation/Foundation.h" diff --git a/include/internal/catch_expression_lhs.hpp b/include/internal/catch_expression_lhs.hpp deleted file mode 100644 index 08625019..00000000 --- a/include/internal/catch_expression_lhs.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Created by Phil on 11/5/2012. - * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED - -#include "catch_result_builder.h" -#include "catch_evaluate.hpp" -#include "catch_tostring.h" - -namespace Catch { - -template -class BinaryExpression; - -template -class MatchExpression; - -// Wraps the LHS of an expression and overloads comparison operators -// for also capturing those and RHS (if any) -template -class ExpressionLhs : public DecomposedExpression { -public: - ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} - - ExpressionLhs( ExpressionLhs const& ) = default; - ExpressionLhs& operator = ( const ExpressionLhs& ) = delete; - - template - BinaryExpression - operator == ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - BinaryExpression - operator != ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - BinaryExpression - operator < ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - BinaryExpression - operator > ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - BinaryExpression - operator <= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - template - BinaryExpression - operator >= ( RhsT const& rhs ) { - return captureExpression( rhs ); - } - - BinaryExpression operator == ( bool rhs ) { - return captureExpression( rhs ); - } - - BinaryExpression operator != ( bool rhs ) { - return captureExpression( rhs ); - } - - void endExpression() { - m_truthy = m_lhs ? true : false; - m_rb - .setResultType( m_truthy ) - .endExpression( *this ); - } - - void reconstructExpression( std::string& dest ) const override { - dest = ::Catch::Detail::stringify( m_lhs ); - } - -private: - template - BinaryExpression captureExpression( RhsT& rhs ) const { - return BinaryExpression( m_rb, m_lhs, rhs ); - } - - template - BinaryExpression captureExpression( bool rhs ) const { - return BinaryExpression( m_rb, m_lhs, rhs ); - } - -private: - ResultBuilder& m_rb; - T m_lhs; - bool m_truthy = false; -}; - -template -class BinaryExpression : public DecomposedExpression { -public: - BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) - : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} - - BinaryExpression( BinaryExpression const& ) = default; - BinaryExpression& operator = ( BinaryExpression const& ) = delete; - - void endExpression() const { - m_rb - .setResultType( Internal::Evaluator::evaluate( m_lhs, m_rhs ) ) - .endExpression( *this ); - } - - bool isBinaryExpression() const override { - return true; - } - - void reconstructExpression( std::string& dest ) const override { - std::string lhs = ::Catch::Detail::stringify( m_lhs ); - std::string rhs = ::Catch::Detail::stringify( m_rhs ); - char delim = lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ? ' ' : '\n'; - dest.reserve( 7 + lhs.size() + rhs.size() ); - // 2 for spaces around operator - // 2 for operator - // 2 for parentheses (conditionally added later) - // 1 for negation (conditionally added later) - dest = lhs; - dest += delim; - dest += Internal::operatorName(Op); - dest += delim; - dest += rhs; - } - -private: - ResultBuilder& m_rb; - LhsT m_lhs; - RhsT m_rhs; -}; - -template -class MatchExpression : public DecomposedExpression { -public: - MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) - : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} - - bool isBinaryExpression() const override { - return true; - } - - void reconstructExpression( std::string& dest ) const override { - std::string matcherAsString = m_matcher.toString(); - dest = ::Catch::Detail::stringify( m_arg ); - dest += ' '; - if( matcherAsString == Detail::unprintableString ) - dest += m_matcherString; - else - dest += matcherAsString; - } - -private: - ArgT m_arg; - MatcherT m_matcher; - char const* m_matcherString; -}; - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED diff --git a/include/internal/catch_result_builder.cpp b/include/internal/catch_result_builder.cpp deleted file mode 100644 index db7dfb14..00000000 --- a/include/internal/catch_result_builder.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Created by Phil on 28/5/2014. - * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#include "catch_result_builder.h" -#include "catch_context.h" -#include "catch_interfaces_config.h" -#include "catch_interfaces_runner.h" -#include "catch_interfaces_capture.h" -#include "catch_interfaces_registry_hub.h" -#include "catch_matchers_string.h" -#include "catch_debugger.h" - -#include - -namespace Catch { - - CopyableStream::CopyableStream( CopyableStream const& other ) { - oss << other.oss.str(); - } - CopyableStream& CopyableStream::operator=( CopyableStream const& other ) { - oss.str(std::string()); - oss << other.oss.str(); - return *this; - } - - - ResultBuilder::ResultBuilder( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, - m_data( ResultWas::Unknown, LazyExpression( false ) ) - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); - } - - ResultBuilder::~ResultBuilder() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if ( m_guardException ) { - stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - captureResult( ResultWas::ThrewException ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } -#endif - } - - ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { - m_data.resultType = result; - return *this; - } - ResultBuilder& ResultBuilder::setResultType( bool result ) { - m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; - return *this; - } - - void ResultBuilder::endExpression( DecomposedExpression const& expr ) { - // Flip bool results if FalseTest flag is set - if( isFalseTest( m_assertionInfo.resultDisposition ) ) { - m_data.negate( expr.isBinaryExpression() ); - } - - getResultCapture().assertionRun(); - - if(getCurrentContext().getConfig()->includeSuccessfulResults() - || m_data.resultType != ResultWas::Ok) { - AssertionResult result = build( expr ); - handleResult( result ); - } - else - getResultCapture().assertionPassed(); - } - - void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - stream().oss << Catch::translateActiveException(); - captureResult( ResultWas::ThrewException ); - } - - void ResultBuilder::captureResult( ResultWas::OfType resultType ) { - setResultType( resultType ); - captureExpression(); - } -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { - if( expectedMessage.empty() ) - captureExpectedException( Matchers::Impl::MatchAllOf() ); - else - captureExpectedException( Matchers::Equals( expectedMessage ) ); - } - - - void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase const& matcher ) { - - assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); - AssertionResultData data = m_data; - data.resultType = ResultWas::Ok; - data.reconstructedExpression = m_assertionInfo.capturedExpression.c_str(); - - std::string actualMessage = Catch::translateActiveException(); - if( !matcher.match( actualMessage ) ) { - data.resultType = ResultWas::ExpressionFailed; - data.reconstructedExpression = std::move(actualMessage); - } - AssertionResult result( m_assertionInfo, data ); - handleResult( result ); - } -#endif // CATCH_CONFIG_DISABLE_MATCHERS - void ResultBuilder::captureExpression() { - AssertionResult result = build(); - handleResult( result ); - } - - void ResultBuilder::handleResult( AssertionResult const& result ) - { - getResultCapture().assertionEnded( result ); - - if( !result.isOk() ) { - if( getCurrentContext().getConfig()->shouldDebugBreak() ) - m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) - m_shouldThrow = true; - } - } - - void ResultBuilder::react() { -#if defined(CATCH_CONFIG_FAST_COMPILE) - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the throw statement - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); - } -#endif - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } - - bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } - bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } - - AssertionResult ResultBuilder::build() const - { - return build( *this ); - } - - // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, - // a temporary DecomposedExpression, which in turn holds references to - // operands, possibly temporary as well. - // It should immediately be passed to handleResult; if the expression - // needs to be reported, its string expansion must be composed before - // the temporaries are destroyed. - AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const { - assert( m_data.resultType != ResultWas::Unknown ); - AssertionResultData data = m_data; - - if(m_usedStream) - data.message = s_stream().oss.str(); - data.decomposedExpression = &expr; // for lazy reconstruction - return AssertionResult( m_assertionInfo, data ); - } - - void ResultBuilder::reconstructExpression( std::string& dest ) const { - dest = m_assertionInfo.capturedExpression.c_str(); - } - - void ResultBuilder::setExceptionGuard() { - m_guardException = true; - } - void ResultBuilder::unsetExceptionGuard() { - m_guardException = false; - } - - CopyableStream& ResultBuilder::stream() { - if( !m_usedStream ) { - m_usedStream = true; - s_stream().oss.str(""); - } - return s_stream(); - } - - CopyableStream& ResultBuilder::s_stream() { - static CopyableStream s; - return s; - } - - -} // end namespace Catch diff --git a/include/internal/catch_result_builder.h b/include/internal/catch_result_builder.h deleted file mode 100644 index 6d3a9efc..00000000 --- a/include/internal/catch_result_builder.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Created by Phil on 28/5/2014. - * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED -#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED - -#include "catch_assertionresult.h" -#include "catch_decomposer.h" - -#include "catch_result_type.h" -#include "catch_common.h" -#include "catch_matchers.hpp" - -#include - -namespace Catch { - - template class ExpressionLhs; - - struct CopyableStream { - CopyableStream() = default; - CopyableStream( CopyableStream const& other ); - CopyableStream& operator=( CopyableStream const& other ); - - std::ostringstream oss; - }; - - class ResultBuilder : public DecomposedExpression { - public: - ResultBuilder( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition); - ~ResultBuilder(); - - template - ExpressionLhs operator <= ( T const& operand ); - ExpressionLhs operator <= ( bool value ); - - template - ResultBuilder& operator << ( T const& value ) { - stream().oss << value; - return *this; - } - - ResultBuilder& setResultType( ResultWas::OfType result ); - ResultBuilder& setResultType( bool result ); - - void endExpression( DecomposedExpression const& expr ); - - void reconstructExpression( std::string& dest ) const override; - - AssertionResult build() const; - AssertionResult build( DecomposedExpression const& expr ) const; - - void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); - void captureResult( ResultWas::OfType resultType ); - void captureExpression(); -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - void captureExpectedException( std::string const& expectedMessage ); - void captureExpectedException( Matchers::Impl::MatcherBase const& matcher ); -#endif // CATCH_CONFIG_DISABLE_MATCHERS - void handleResult( AssertionResult const& result ); - void react(); - bool shouldDebugBreak() const; - bool allowThrows() const; - - template - void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); - - void setExceptionGuard(); - void unsetExceptionGuard(); - - private: - AssertionInfo m_assertionInfo; - AssertionResultData m_data; - - CopyableStream& stream(); - static CopyableStream& s_stream(); - - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_guardException = false; - bool m_usedStream = false; - }; - -} // namespace Catch - -// Include after due to circular dependency: -#include "catch_expression_lhs.hpp" - -namespace Catch { - - template - ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { - return ExpressionLhs( *this, operand ); - } - - inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { - return ExpressionLhs( *this, value ); - } - - template - void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, - char const* matcherString ) { - MatchExpression expr( arg, matcher, matcherString ); - setResultType( matcher.match( arg ) ); - endExpression( expr ); - } - - -} // namespace Catch - -#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED diff --git a/include/internal/catch_run_context.hpp b/include/internal/catch_run_context.hpp index a356e3bf..d5ad4558 100644 --- a/include/internal/catch_run_context.hpp +++ b/include/internal/catch_run_context.hpp @@ -19,7 +19,7 @@ #include "catch_test_spec.hpp" #include "catch_test_case_tracker.hpp" #include "catch_timer.h" -#include "catch_result_builder.h" +#include "catch_assertionhandler.h" #include "catch_fatal_condition.h" #include diff --git a/include/reporters/catch_reporter_bases.cpp b/include/reporters/catch_reporter_bases.cpp index 6457af35..1db7868c 100644 --- a/include/reporters/catch_reporter_bases.cpp +++ b/include/reporters/catch_reporter_bases.cpp @@ -18,10 +18,7 @@ namespace Catch { void prepareExpandedExpression(AssertionResult& result) { - if (result.isOk()) - result.discardDecomposedExpression(); - else - result.expandDecomposedExpression(); + result.getExpandedExpression(); } // Because formatting using c++ streams is stateful, drop down to C is required From dc1df297e3f1d03a36bc7c39cde33b47c8b942a5 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 09:29:44 +0100 Subject: [PATCH 15/20] Suppressed some warnings - signed/ unsigned mismatches - virtual destructor on ITransientExpression (even though not needed) --- include/internal/catch_decomposer.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h index 3182b84a..6889d873 100644 --- a/include/internal/catch_decomposer.h +++ b/include/internal/catch_decomposer.h @@ -14,12 +14,23 @@ #include +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#endif + namespace Catch { struct ITransientExpression { virtual auto isBinaryExpression() const -> bool = 0; virtual auto getResult() const -> bool = 0; virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + + // We don't actually need a virtual destructore, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression() = default; }; void formatReconstructedExpression( std::ostream &os, std::string const& lhs, std::string const& op, std::string const& rhs ); @@ -180,4 +191,8 @@ namespace Catch { } // end namespace Catch +#ifdef _MSC_VER +#pragma warning(pop) +#endif + #endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED From 8382d99081d497947652b87f12cc0b10c2e4b0de Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 10:18:31 +0100 Subject: [PATCH 16/20] Workaround for GCC 4.8 "deleted ctor in aggregate" bug --- include/internal/catch_assertioninfo.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/internal/catch_assertioninfo.h b/include/internal/catch_assertioninfo.h index 21646b21..1ac304e1 100644 --- a/include/internal/catch_assertioninfo.h +++ b/include/internal/catch_assertioninfo.h @@ -21,6 +21,8 @@ namespace Catch { StringRef capturedExpression; ResultDisposition::Flags resultDisposition; + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate AssertionInfo() = delete; }; From 4b5ac4d3d93e78b6735cb787307ea44c4fc76a47 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 10:29:05 +0100 Subject: [PATCH 17/20] Actually do what the previous commit claimed to do! :-s --- include/internal/catch_assertioninfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/internal/catch_assertioninfo.h b/include/internal/catch_assertioninfo.h index 1ac304e1..5f136bf7 100644 --- a/include/internal/catch_assertioninfo.h +++ b/include/internal/catch_assertioninfo.h @@ -23,7 +23,7 @@ namespace Catch { // We want to delete this constructor but a compiler bug in 4.8 means // the struct is then treated as non-aggregate - AssertionInfo() = delete; + //AssertionInfo() = delete; }; } // end namespace Catch From 8d21b4a916031bfead5b51c3e5334a0bec2ad84e Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 10:51:50 +0100 Subject: [PATCH 18/20] Removed some unnecessary #includes - and don't #include "catch_debugger.h" in the header path when CATCH_CONFIG_FAST_COMPILE is defined --- include/internal/catch_assertionhandler.cpp | 1 + include/internal/catch_benchmark.cpp | 1 + include/internal/catch_capture.hpp | 7 ++----- include/internal/catch_interfaces_capture.h | 5 ++--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index 26f727a9..8ccd60f2 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -10,6 +10,7 @@ #include "catch_assertionresult.h" #include "catch_interfaces_capture.h" #include "catch_interfaces_runner.h" +#include "catch_interfaces_config.h" #include "catch_context.h" #include "catch_debugger.h" #include "catch_interfaces_registry_hub.h" diff --git a/include/internal/catch_benchmark.cpp b/include/internal/catch_benchmark.cpp index 34af42a5..51a844f6 100644 --- a/include/internal/catch_benchmark.cpp +++ b/include/internal/catch_benchmark.cpp @@ -8,6 +8,7 @@ #include "catch_benchmark.h" #include "catch_capture.hpp" +#include "catch_interfaces_reporter.h" namespace Catch { diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 5332df35..8afcb74d 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -11,11 +11,6 @@ #include "catch_assertionhandler.h" #include "catch_message.h" #include "catch_interfaces_capture.h" -#include "catch_debugger.h" -#include "catch_common.h" -#include "catch_tostring.h" -#include "catch_interfaces_runner.h" -#include "catch_compiler_capabilities.h" #if defined(CATCH_CONFIG_FAST_COMPILE) @@ -39,6 +34,8 @@ #else // CATCH_CONFIG_FAST_COMPILE +#include "catch_debugger.h" + /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 4d8766dd..e8000154 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -9,9 +9,6 @@ #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include -#include "catch_result_type.h" -#include "catch_common.h" -#include "catch_interfaces_reporter.h" namespace Catch { @@ -23,6 +20,8 @@ namespace Catch { struct MessageInfo; class ScopedMessageBuilder; struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; struct IResultCapture { From b59e0ed48a4d94f9e595a5936434e9bad7834ece Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 11:36:33 +0100 Subject: [PATCH 19/20] Collapsed alternate capture macros now originals are redundant --- include/internal/catch_assertionhandler.cpp | 4 --- include/internal/catch_assertionhandler.h | 1 - include/internal/catch_capture.hpp | 35 +++++++++------------ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index 8ccd60f2..ea4f75af 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -125,10 +125,6 @@ namespace Catch { throw Catch::TestFailureException(); } - void AssertionHandler::useActiveException( ResultDisposition::Flags resultDisposition ) { - m_assertionInfo.resultDisposition = resultDisposition; - useActiveException(); - } void AssertionHandler::useActiveException() { handle( ResultWas::ThrewException, Catch::translateActiveException().c_str() ); } diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index 21a09875..a1b1777a 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -62,7 +62,6 @@ namespace Catch { auto allowThrows() const -> bool; void reactWithDebugBreak() const; void reactWithoutDebugBreak() const; - void useActiveException( ResultDisposition::Flags resultDisposition ); void useActiveException(); void setExceptionGuard(); void unsetExceptionGuard(); diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 8afcb74d..257d057f 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -18,9 +18,7 @@ // We can speedup compilation significantly by breaking into debugger lower in // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER // macro in each assertion -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - resultBuilder.react(); -#define INTERNAL_CATCH_REACT2( handler ) \ +#define INTERNAL_CATCH_REACT( handler ) \ handler.reactWithDebugBreak(); /////////////////////////////////////////////////////////////////////////////// @@ -29,8 +27,7 @@ // This can potentially cause false negative, if the test code catches // the exception before it propagates back up to the runner. #define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer, disposition ) capturer.unsetExceptionGuard(); -#define INTERNAL_CATCH_CATCH2( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); #else // CATCH_CONFIG_FAST_COMPILE @@ -41,16 +38,12 @@ // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( resultBuilder ) \ - if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - resultBuilder.react(); -#define INTERNAL_CATCH_REACT2( handler ) \ +#define INTERNAL_CATCH_REACT( handler ) \ if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ handler.reactWithoutDebugBreak(); #define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer, disposition ) catch(...) { capturer.useActiveException( disposition ); } -#define INTERNAL_CATCH_CATCH2( capturer ) catch(...) { capturer.useActiveException(); } +#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } #endif @@ -62,8 +55,8 @@ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH2( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. @@ -88,7 +81,7 @@ catch( ... ) { \ catchAssertionHandler.useActiveException(); \ } \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// @@ -105,7 +98,7 @@ } \ else \ catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// @@ -125,7 +118,7 @@ } \ else \ catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) @@ -134,7 +127,7 @@ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str().c_str() ); \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// @@ -148,8 +141,8 @@ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ - } INTERNAL_CATCH_CATCH2( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// @@ -166,7 +159,7 @@ } \ else \ catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) @@ -187,7 +180,7 @@ } \ else \ catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT2( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( Catch::alwaysFalse() ) #endif // CATCH_CONFIG_DISABLE_MATCHERS From ee9b19efd3737afc93e14023cc0b4a9fd2a21b7c Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 9 Aug 2017 12:10:14 +0100 Subject: [PATCH 20/20] Moved matcher-based capture macros into their own file - this file excluded from the CATCH_CONFIG_DISABLE_MATCHERS path. - matchers are always compiled in to the impl file - _THROWS_WITH macros are still available with matchers disabled - but only the ones that take a string - tests that use matchers have #ifdefs, so the whole SelfTest project can compile with matchers disable. --- CMakeLists.txt | 2 + include/catch.hpp | 12 ++- include/internal/catch_assertionhandler.cpp | 10 +-- include/internal/catch_assertionhandler.h | 4 - include/internal/catch_capture.hpp | 34 +------- include/internal/catch_capture_matchers.cpp | 23 ++++++ include/internal/catch_capture_matchers.h | 87 +++++++++++++++++++++ include/internal/catch_decomposer.h | 34 -------- include/internal/catch_matchers.cpp | 4 - include/internal/catch_matchers.hpp | 4 - include/internal/catch_matchers_string.cpp | 4 - include/internal/catch_matchers_string.h | 4 - include/internal/catch_matchers_vector.h | 5 -- projects/SelfTest/CompilationTests.cpp | 2 + projects/SelfTest/ExceptionTests.cpp | 4 + projects/SelfTest/MatchersTests.cpp | 4 + projects/SelfTest/TagAliasTests.cpp | 5 +- projects/SelfTest/TestMain.cpp | 6 ++ 18 files changed, 143 insertions(+), 105 deletions(-) create mode 100644 include/internal/catch_capture_matchers.cpp create mode 100644 include/internal/catch_capture_matchers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 94f06f40..4e8c8734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_assertioninfo.h ${HEADER_DIR}/internal/catch_assertionresult.h ${HEADER_DIR}/internal/catch_capture.hpp + ${HEADER_DIR}/internal/catch_capture_matchers.h ${HEADER_DIR}/internal/catch_clara.h ${HEADER_DIR}/internal/catch_commandline.hpp ${HEADER_DIR}/internal/catch_common.h @@ -201,6 +202,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_assertionhandler.cpp ${HEADER_DIR}/internal/catch_assertionresult.cpp ${HEADER_DIR}/internal/catch_benchmark.cpp + ${HEADER_DIR}/internal/catch_capture_matchers.cpp ${HEADER_DIR}/internal/catch_commandline.cpp ${HEADER_DIR}/internal/catch_common.cpp ${HEADER_DIR}/internal/catch_config.cpp diff --git a/include/catch.hpp b/include/catch.hpp index 58d8c9d5..a2fd8bb2 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -41,6 +41,10 @@ #include "internal/catch_compiler_capabilities.h" #include "internal/catch_interfaces_tag_alias_registry.h" +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +#include "internal/catch_capture_matchers.h" +#endif + // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections #include "internal/catch_test_case_info.h" @@ -72,8 +76,8 @@ #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #endif// CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) @@ -86,8 +90,8 @@ #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) @@ -134,8 +138,8 @@ #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) @@ -148,8 +152,8 @@ #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #endif // CATCH_CONFIG_DISABLE_MATCHERS #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp index ea4f75af..9e7c8453 100644 --- a/include/internal/catch_assertionhandler.cpp +++ b/include/internal/catch_assertionhandler.cpp @@ -14,7 +14,7 @@ #include "catch_context.h" #include "catch_debugger.h" #include "catch_interfaces_registry_hub.h" -#include "catch_matchers_string.h" +#include "catch_capture_matchers.h" #include @@ -138,12 +138,8 @@ namespace Catch { m_inExceptionGuard = false; } - using StringMatcher = Matchers::Impl::MatcherBase; - - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { - MatchExpr expr( Catch::translateActiveException(), matcher, matcherString ); - handler.handle( expr ); - } + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); } diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h index a1b1777a..9fdbee4f 100644 --- a/include/internal/catch_assertionhandler.h +++ b/include/internal/catch_assertionhandler.h @@ -10,7 +10,6 @@ #include "catch_decomposer.h" #include "catch_assertioninfo.h" -#include "catch_matchers_string.h" // !TBD: for exception matchers namespace Catch { @@ -67,9 +66,6 @@ namespace Catch { void unsetExceptionGuard(); }; - using StringMatcher = Matchers::Impl::MatcherBase; - - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); } // namespace Catch diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp index 257d057f..2f631bd3 100644 --- a/include/internal/catch_capture.hpp +++ b/include/internal/catch_capture.hpp @@ -134,18 +134,8 @@ #define INTERNAL_CATCH_INFO( macroName, log ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) - /////////////////////////////////////////////////////////////////////////////// +// Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #matcher, resultDisposition ); \ @@ -163,26 +153,4 @@ } while( Catch::alwaysFalse() ) -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #exceptionType ", " #matcher, resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ - } \ - catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ - } \ - catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ - } \ - else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - - #endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED diff --git a/include/internal/catch_capture_matchers.cpp b/include/internal/catch_capture_matchers.cpp new file mode 100644 index 00000000..8c30a154 --- /dev/null +++ b/include/internal/catch_capture_matchers.cpp @@ -0,0 +1,23 @@ +/* + * Created by Phil on 9/8/2017. + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#include "catch_capture_matchers.h" +#include "catch_interfaces_registry_hub.h" + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + MatchExpr expr( Catch::translateActiveException(), matcher, matcherString ); + handler.handle( expr ); + } + +} // namespace Catch diff --git a/include/internal/catch_capture_matchers.h b/include/internal/catch_capture_matchers.h new file mode 100644 index 00000000..e3e43568 --- /dev/null +++ b/include/internal/catch_capture_matchers.h @@ -0,0 +1,87 @@ +/* + * Created by Phil on 9/8/2017 + * Copyright 2017 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED + +#include "catch_capture.hpp" +#include "catch_matchers.hpp" +#include "catch_matchers_string.h" + +namespace Catch { + + template + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + bool m_result; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ), + m_result( matcher.match( arg ) ) + {} + + auto isBinaryExpression() const -> bool override { return true; } + auto getResult() const -> bool override { return m_result; } + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString.c_str(); + else + os << matcherAsString; + } + }; + + using StringMatcher = Matchers::Impl::MatcherBase; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + + template + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + return MatchExpr( arg, matcher, matcherString ); + } + +} // namespace Catch + + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ + INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::alwaysFalse() ) + + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, #__VA_ARGS__ ", " #exceptionType ", " #matcher, resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__ ); \ + catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.useActiveException(); \ + } \ + else \ + catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( Catch::alwaysFalse() ) + +#endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h index 6889d873..e1c2f217 100644 --- a/include/internal/catch_decomposer.h +++ b/include/internal/catch_decomposer.h @@ -10,7 +10,6 @@ #include "catch_tostring.h" #include "catch_stringref.h" -#include "catch_matchers.hpp" // !TBD: for exception matchers - move this #include @@ -156,39 +155,6 @@ namespace Catch { } }; - // !TBD: this is just here temporarily - template - class MatchExpr : public ITransientExpression { - ArgT const& m_arg; - MatcherT m_matcher; - StringRef m_matcherString; - bool m_result; - public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), - m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) - {} - - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } - - void streamReconstructedExpression( std::ostream &os ) const override { - auto matcherAsString = m_matcher.toString(); - os << Catch::Detail::stringify( m_arg ) << ' '; - if( matcherAsString == Detail::unprintableString ) - os << m_matcherString.c_str(); - else - os << matcherAsString; - } - }; - - template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); - } - } // end namespace Catch #ifdef _MSC_VER diff --git a/include/internal/catch_matchers.cpp b/include/internal/catch_matchers.cpp index 76d0332c..38ae8c77 100644 --- a/include/internal/catch_matchers.cpp +++ b/include/internal/catch_matchers.cpp @@ -5,8 +5,6 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - #include "catch_matchers.hpp" namespace Catch { @@ -26,5 +24,3 @@ using namespace Matchers; using Matchers::Impl::MatcherBase; } // namespace Catch - -#endif // CATCH_CONFIG_DISABLE_MATCHERS \ No newline at end of file diff --git a/include/internal/catch_matchers.hpp b/include/internal/catch_matchers.hpp index c120bbf3..5a3f0818 100644 --- a/include/internal/catch_matchers.hpp +++ b/include/internal/catch_matchers.hpp @@ -8,8 +8,6 @@ #ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - #include "catch_common.h" #include @@ -182,6 +180,4 @@ using Matchers::Impl::MatcherBase; } // namespace Catch -#endif // CATCH_CONFIG_DISABLE_MATCHERS - #endif // TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED diff --git a/include/internal/catch_matchers_string.cpp b/include/internal/catch_matchers_string.cpp index 2f899e8d..2f8ffdb8 100644 --- a/include/internal/catch_matchers_string.cpp +++ b/include/internal/catch_matchers_string.cpp @@ -6,8 +6,6 @@ * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - #include "catch_matchers_string.h" #include "catch_string_manip.h" @@ -94,5 +92,3 @@ namespace Matchers { } // namespace Matchers } // namespace Catch - -#endif // CATCH_CONFIG_DISABLE_MATCHERS diff --git a/include/internal/catch_matchers_string.h b/include/internal/catch_matchers_string.h index 27e5b4cc..eca35789 100644 --- a/include/internal/catch_matchers_string.h +++ b/include/internal/catch_matchers_string.h @@ -8,8 +8,6 @@ #ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED #define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - #include "catch_matchers.hpp" #include @@ -68,6 +66,4 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -#endif // CATCH_CONFIG_DISABLE_MATCHERS - #endif // TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED diff --git a/include/internal/catch_matchers_vector.h b/include/internal/catch_matchers_vector.h index a2f5cb6c..4bf39d70 100644 --- a/include/internal/catch_matchers_vector.h +++ b/include/internal/catch_matchers_vector.h @@ -8,9 +8,6 @@ #ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - - #include "catch_matchers.hpp" namespace Catch { @@ -115,6 +112,4 @@ namespace Matchers { } // namespace Matchers } // namespace Catch -#endif // CATCH_CONFIG_DISABLE_MATCHERS - #endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED diff --git a/projects/SelfTest/CompilationTests.cpp b/projects/SelfTest/CompilationTests.cpp index e6c31f65..4dd260f8 100644 --- a/projects/SelfTest/CompilationTests.cpp +++ b/projects/SelfTest/CompilationTests.cpp @@ -43,7 +43,9 @@ bool templated_tests(T t) { REQUIRE_THROWS(throws_int(true)); CHECK_THROWS_AS(throws_int(true), int); REQUIRE_NOTHROW(throws_int(false)); +#ifndef CATCH_CONFIG_DISABLE_MATCHERS REQUIRE_THAT("aaa", Catch::EndsWith("aaa")); +#endif return true; } diff --git a/projects/SelfTest/ExceptionTests.cpp b/projects/SelfTest/ExceptionTests.cpp index 2ec64c71..566065e6 100644 --- a/projects/SelfTest/ExceptionTests.cpp +++ b/projects/SelfTest/ExceptionTests.cpp @@ -181,6 +181,8 @@ TEST_CASE( "Unexpected exceptions can be translated", "[.][failing][!throws]" ) throw double( 3.14 ); } +#ifndef CATCH_CONFIG_DISABLE_MATCHERS + TEST_CASE( "Exception messages can be tested for", "[!throws]" ) { using namespace Catch::Matchers; SECTION( "exact match" ) @@ -195,6 +197,8 @@ TEST_CASE( "Exception messages can be tested for", "[!throws]" ) { } } +#endif + TEST_CASE( "Mismatching exception messages failing the test", "[.][failing][!throws]" ) { REQUIRE_THROWS_WITH( thisThrows(), "expected exception" ); REQUIRE_THROWS_WITH( thisThrows(), "should fail" ); diff --git a/projects/SelfTest/MatchersTests.cpp b/projects/SelfTest/MatchersTests.cpp index 814577e9..52a49230 100644 --- a/projects/SelfTest/MatchersTests.cpp +++ b/projects/SelfTest/MatchersTests.cpp @@ -8,6 +8,8 @@ #include "catch.hpp" +#ifndef CATCH_CONFIG_DISABLE_MATCHERS + inline const char* testStringForMatching() { return "this string contains 'abc' as a substring"; @@ -223,3 +225,5 @@ TEST_CASE("Exception matchers that fail", "[matchers][exceptions][!throws][.fail REQUIRE_THROWS_MATCHES(throws(4), SpecialException, ExceptionMatcher{ 1 }); } } + +#endif // CATCH_CONFIG_DISABLE_MATCHERS diff --git a/projects/SelfTest/TagAliasTests.cpp b/projects/SelfTest/TagAliasTests.cpp index 840601e7..b533c454 100644 --- a/projects/SelfTest/TagAliasTests.cpp +++ b/projects/SelfTest/TagAliasTests.cpp @@ -11,8 +11,6 @@ TEST_CASE( "Tag alias can be registered against tag patterns" ) { - using namespace Catch::Matchers; - Catch::TagAliasRegistry registry; registry.add( "[@zzz]", "[one][two]", Catch::SourceLineInfo( "file", 2 ) ); @@ -24,11 +22,14 @@ TEST_CASE( "Tag alias can be registered against tag patterns" ) { FAIL( "expected exception" ); } catch( std::exception& ex ) { +#ifndef CATCH_CONFIG_DISABLE_MATCHERS std::string what = ex.what(); + using namespace Catch::Matchers; CHECK_THAT( what, Contains( "[@zzz]" ) ); CHECK_THAT( what, Contains( "file" ) ); CHECK_THAT( what, Contains( "2" ) ); CHECK_THAT( what, Contains( "10" ) ); +#endif } } diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index aad1f036..c3b1f29b 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -47,7 +47,9 @@ inline Catch::TestCase fakeTestCase( const char* name, const char* desc = "" ){ TEST_CASE( "Process can be configured on command line", "[config][command-line]" ) { +#ifndef CATCH_CONFIG_DISABLE_MATCHERS using namespace Catch::Matchers; +#endif Catch::ConfigData config; auto cli = Catch::makeCommandLineParser(config); @@ -153,7 +155,9 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" auto result = cli.parse({"test", "-x", "oops"}); CHECK(!result); +#ifndef CATCH_CONFIG_DISABLE_MATCHERS REQUIRE_THAT(result.errorMessage(), Contains("convert") && Contains("oops")); +#endif } } @@ -225,7 +229,9 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" SECTION( "error" ) { auto result = cli.parse({"test", "--use-colour", "wrong"}); CHECK( !result ); +#ifndef CATCH_CONFIG_DISABLE_MATCHERS CHECK_THAT( result.errorMessage(), Contains( "colour mode must be one of" ) ); +#endif } } }