/* * 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