1 /* 2 * Created by Phil Nash on 1/2/2013. 3 * Copyright 2013 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 9 #include "catch_message.h" 10 #include "catch_interfaces_capture.h" 11 #include "catch_uncaught_exceptions.h" 12 #include "catch_enforce.h" 13 14 #include <cassert> 15 #include <stack> 16 17 namespace Catch { 18 MessageInfo(StringRef const & _macroName,SourceLineInfo const & _lineInfo,ResultWas::OfType _type)19 MessageInfo::MessageInfo( StringRef const& _macroName, 20 SourceLineInfo const& _lineInfo, 21 ResultWas::OfType _type ) 22 : macroName( _macroName ), 23 lineInfo( _lineInfo ), 24 type( _type ), 25 sequence( ++globalCount ) 26 {} 27 operator ==(MessageInfo const & other) const28 bool MessageInfo::operator==( MessageInfo const& other ) const { 29 return sequence == other.sequence; 30 } 31 operator <(MessageInfo const & other) const32 bool MessageInfo::operator<( MessageInfo const& other ) const { 33 return sequence < other.sequence; 34 } 35 36 // This may need protecting if threading support is added 37 unsigned int MessageInfo::globalCount = 0; 38 39 40 //////////////////////////////////////////////////////////////////////////// 41 MessageBuilder(StringRef const & macroName,SourceLineInfo const & lineInfo,ResultWas::OfType type)42 Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, 43 SourceLineInfo const& lineInfo, 44 ResultWas::OfType type ) 45 :m_info(macroName, lineInfo, type) {} 46 47 //////////////////////////////////////////////////////////////////////////// 48 49 ScopedMessage(MessageBuilder const & builder)50 ScopedMessage::ScopedMessage( MessageBuilder const& builder ) 51 : m_info( builder.m_info ), m_moved() 52 { 53 m_info.message = builder.m_stream.str(); 54 getResultCapture().pushScopedMessage( m_info ); 55 } 56 ScopedMessage(ScopedMessage && old)57 ScopedMessage::ScopedMessage( ScopedMessage&& old ) 58 : m_info( old.m_info ), m_moved() 59 { 60 old.m_moved = true; 61 } 62 ~ScopedMessage()63 ScopedMessage::~ScopedMessage() { 64 if ( !uncaught_exceptions() && !m_moved ){ 65 getResultCapture().popScopedMessage(m_info); 66 } 67 } 68 69 Capturer(StringRef macroName,SourceLineInfo const & lineInfo,ResultWas::OfType resultType,StringRef names)70 Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { 71 auto trimmed = [&] (size_t start, size_t end) { 72 while (names[start] == ',' || isspace(names[start])) { 73 ++start; 74 } 75 while (names[end] == ',' || isspace(names[end])) { 76 --end; 77 } 78 return names.substr(start, end - start + 1); 79 }; 80 auto skipq = [&] (size_t start, char quote) { 81 for (auto i = start + 1; i < names.size() ; ++i) { 82 if (names[i] == quote) 83 return i; 84 if (names[i] == '\\') 85 ++i; 86 } 87 CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); 88 }; 89 90 size_t start = 0; 91 std::stack<char> openings; 92 for (size_t pos = 0; pos < names.size(); ++pos) { 93 char c = names[pos]; 94 switch (c) { 95 case '[': 96 case '{': 97 case '(': 98 // It is basically impossible to disambiguate between 99 // comparison and start of template args in this context 100 // case '<': 101 openings.push(c); 102 break; 103 case ']': 104 case '}': 105 case ')': 106 // case '>': 107 openings.pop(); 108 break; 109 case '"': 110 case '\'': 111 pos = skipq(pos, c); 112 break; 113 case ',': 114 if (start != pos && openings.empty()) { 115 m_messages.emplace_back(macroName, lineInfo, resultType); 116 m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); 117 m_messages.back().message += " := "; 118 start = pos; 119 } 120 } 121 } 122 assert(openings.empty() && "Mismatched openings"); 123 m_messages.emplace_back(macroName, lineInfo, resultType); 124 m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); 125 m_messages.back().message += " := "; 126 } ~Capturer()127 Capturer::~Capturer() { 128 if ( !uncaught_exceptions() ){ 129 assert( m_captured == m_messages.size() ); 130 for( size_t i = 0; i < m_captured; ++i ) 131 m_resultCapture.popScopedMessage( m_messages[i] ); 132 } 133 } 134 captureValue(size_t index,std::string const & value)135 void Capturer::captureValue( size_t index, std::string const& value ) { 136 assert( index < m_messages.size() ); 137 m_messages[index].message += value; 138 m_resultCapture.pushScopedMessage( m_messages[index] ); 139 m_captured++; 140 } 141 142 } // end namespace Catch 143