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

summaryrefslogtreecommitdiffhomepage
path: root/include/internal/catch_assertionhandler.cpp
blob: a71a2dc26702c30462eb66ef5f699caf54c9da9c (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
129
130
131
132
133
134
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 <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( 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