/ externals / catch / src / catch2 / catch_message.cpp
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