catch_message.cpp
1 2 // Copyright Catch2 Authors 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE.txt or copy at 5 // https://www.boost.org/LICENSE_1_0.txt) 6 7 // SPDX-License-Identifier: BSL-1.0 8 #include <catch2/catch_message.hpp> 9 #include <catch2/interfaces/catch_interfaces_capture.hpp> 10 #include <catch2/internal/catch_uncaught_exceptions.hpp> 11 #include <catch2/internal/catch_enforce.hpp> 12 #include <catch2/internal/catch_move_and_forward.hpp> 13 14 #include <cassert> 15 #include <stack> 16 17 namespace Catch { 18 19 //////////////////////////////////////////////////////////////////////////// 20 21 22 ScopedMessage::ScopedMessage( MessageBuilder&& builder ): 23 m_info( CATCH_MOVE(builder.m_info) ) { 24 m_info.message = builder.m_stream.str(); 25 getResultCapture().pushScopedMessage( m_info ); 26 } 27 28 ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept: 29 m_info( CATCH_MOVE( old.m_info ) ) { 30 old.m_moved = true; 31 } 32 33 ScopedMessage::~ScopedMessage() { 34 if ( !uncaught_exceptions() && !m_moved ){ 35 getResultCapture().popScopedMessage(m_info); 36 } 37 } 38 39 40 Capturer::Capturer( StringRef macroName, 41 SourceLineInfo const& lineInfo, 42 ResultWas::OfType resultType, 43 StringRef names ): 44 m_resultCapture( getResultCapture() ) { 45 auto trimmed = [&] (size_t start, size_t end) { 46 while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { 47 ++start; 48 } 49 while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { 50 --end; 51 } 52 return names.substr(start, end - start + 1); 53 }; 54 auto skipq = [&] (size_t start, char quote) { 55 for (auto i = start + 1; i < names.size() ; ++i) { 56 if (names[i] == quote) 57 return i; 58 if (names[i] == '\\') 59 ++i; 60 } 61 CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); 62 }; 63 64 size_t start = 0; 65 std::stack<char> openings; 66 for (size_t pos = 0; pos < names.size(); ++pos) { 67 char c = names[pos]; 68 switch (c) { 69 case '[': 70 case '{': 71 case '(': 72 // It is basically impossible to disambiguate between 73 // comparison and start of template args in this context 74 // case '<': 75 openings.push(c); 76 break; 77 case ']': 78 case '}': 79 case ')': 80 // case '>': 81 openings.pop(); 82 break; 83 case '"': 84 case '\'': 85 pos = skipq(pos, c); 86 break; 87 case ',': 88 if (start != pos && openings.empty()) { 89 m_messages.emplace_back(macroName, lineInfo, resultType); 90 m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); 91 m_messages.back().message += " := "; 92 start = pos; 93 } 94 } 95 } 96 assert(openings.empty() && "Mismatched openings"); 97 m_messages.emplace_back(macroName, lineInfo, resultType); 98 m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); 99 m_messages.back().message += " := "; 100 } 101 Capturer::~Capturer() { 102 if ( !uncaught_exceptions() ){ 103 assert( m_captured == m_messages.size() ); 104 for( size_t i = 0; i < m_captured; ++i ) 105 m_resultCapture.popScopedMessage( m_messages[i] ); 106 } 107 } 108 109 void Capturer::captureValue( size_t index, std::string const& value ) { 110 assert( index < m_messages.size() ); 111 m_messages[index].message += value; 112 m_resultCapture.pushScopedMessage( m_messages[index] ); 113 m_captured++; 114 } 115 116 } // end namespace Catch