143 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  *  Created by Phil Nash on 1/2/2013.
 | |
|  *  Copyright 2013 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_message.h"
 | |
| #include "catch_interfaces_capture.h"
 | |
| #include "catch_uncaught_exceptions.h"
 | |
| #include "catch_enforce.h"
 | |
| 
 | |
| #include <cassert>
 | |
| #include <stack>
 | |
| 
 | |
| namespace Catch {
 | |
| 
 | |
|     MessageInfo::MessageInfo(   StringRef const& _macroName,
 | |
|                                 SourceLineInfo const& _lineInfo,
 | |
|                                 ResultWas::OfType _type )
 | |
|     :   macroName( _macroName ),
 | |
|         lineInfo( _lineInfo ),
 | |
|         type( _type ),
 | |
|         sequence( ++globalCount )
 | |
|     {}
 | |
| 
 | |
|     bool MessageInfo::operator==( MessageInfo const& other ) const {
 | |
|         return sequence == other.sequence;
 | |
|     }
 | |
| 
 | |
|     bool MessageInfo::operator<( MessageInfo const& other ) const {
 | |
|         return sequence < other.sequence;
 | |
|     }
 | |
| 
 | |
|     // This may need protecting if threading support is added
 | |
|     unsigned int MessageInfo::globalCount = 0;
 | |
| 
 | |
| 
 | |
|     ////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
|     Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
 | |
|                                            SourceLineInfo const& lineInfo,
 | |
|                                            ResultWas::OfType type )
 | |
|         :m_info(macroName, lineInfo, type) {}
 | |
| 
 | |
|     ////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 
 | |
|     ScopedMessage::ScopedMessage( MessageBuilder const& builder )
 | |
|     : m_info( builder.m_info ), m_moved()
 | |
|     {
 | |
|         m_info.message = builder.m_stream.str();
 | |
|         getResultCapture().pushScopedMessage( m_info );
 | |
|     }
 | |
| 
 | |
|     ScopedMessage::ScopedMessage( ScopedMessage&& old )
 | |
|     : m_info( old.m_info ), m_moved()
 | |
|     {
 | |
|         old.m_moved = true;
 | |
|     }
 | |
| 
 | |
|     ScopedMessage::~ScopedMessage() {
 | |
|         if ( !uncaught_exceptions() && !m_moved ){
 | |
|             getResultCapture().popScopedMessage(m_info);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
 | |
|         auto trimmed = [&] (size_t start, size_t end) {
 | |
|             while (names[start] == ',' || isspace(names[start])) {
 | |
|                 ++start;
 | |
|             }
 | |
|             while (names[end] == ',' || isspace(names[end])) {
 | |
|                 --end;
 | |
|             }
 | |
|             return names.substr(start, end - start + 1);
 | |
|         };
 | |
|         auto skipq = [&] (size_t start, char quote) {
 | |
|             for (auto i = start + 1; i < names.size() ; ++i) {
 | |
|                 if (names[i] == quote)
 | |
|                     return i;
 | |
|                 if (names[i] == '\\')
 | |
|                     ++i;
 | |
|             }
 | |
|             CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
 | |
|         };
 | |
| 
 | |
|         size_t start = 0;
 | |
|         std::stack<char> openings;
 | |
|         for (size_t pos = 0; pos < names.size(); ++pos) {
 | |
|             char c = names[pos];
 | |
|             switch (c) {
 | |
|             case '[':
 | |
|             case '{':
 | |
|             case '(':
 | |
|             // It is basically impossible to disambiguate between
 | |
|             // comparison and start of template args in this context
 | |
| //            case '<':
 | |
|                 openings.push(c);
 | |
|                 break;
 | |
|             case ']':
 | |
|             case '}':
 | |
|             case ')':
 | |
| //           case '>':
 | |
|                 openings.pop();
 | |
|                 break;
 | |
|             case '"':
 | |
|             case '\'':
 | |
|                 pos = skipq(pos, c);
 | |
|                 break;
 | |
|             case ',':
 | |
|                 if (start != pos && openings.empty()) {
 | |
|                     m_messages.emplace_back(macroName, lineInfo, resultType);
 | |
|                     m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
 | |
|                     m_messages.back().message += " := ";
 | |
|                     start = pos;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         assert(openings.empty() && "Mismatched openings");
 | |
|         m_messages.emplace_back(macroName, lineInfo, resultType);
 | |
|         m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
 | |
|         m_messages.back().message += " := ";
 | |
|     }
 | |
|     Capturer::~Capturer() {
 | |
|         if ( !uncaught_exceptions() ){
 | |
|             assert( m_captured == m_messages.size() );
 | |
|             for( size_t i = 0; i < m_captured; ++i  )
 | |
|                 m_resultCapture.popScopedMessage( m_messages[i] );
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void Capturer::captureValue( size_t index, std::string const& value ) {
 | |
|         assert( index < m_messages.size() );
 | |
|         m_messages[index].message += value;
 | |
|         m_resultCapture.pushScopedMessage( m_messages[index] );
 | |
|         m_captured++;
 | |
|     }
 | |
| 
 | |
| } // end namespace Catch
 |