catch_message.cpp 3.8 KB

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