Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/include/internal/catch_assertionhandler.cpp
blob: fe8e32a04d40603bbe550e7e6f32a18ccee945c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 *  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 <iostream> // !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( 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, resultData };
        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);
        }
    }
    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();
    }

    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();

        handle( data, nullptr );
    }

} // namespace Catch