/ externals / catch / src / catch2 / internal / catch_jsonwriter.cpp
catch_jsonwriter.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/internal/catch_enforce.hpp>
  9  #include <catch2/internal/catch_jsonwriter.hpp>
 10  
 11  namespace Catch {
 12      void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
 13          for ( std::uint64_t i = 0; i < level; ++i ) {
 14              os << "  ";
 15          }
 16      }
 17      void JsonUtils::appendCommaNewline( std::ostream& os,
 18                                          bool& should_comma,
 19                                          std::uint64_t level ) {
 20          if ( should_comma ) { os << ','; }
 21          should_comma = true;
 22          os << '\n';
 23          indent( os, level );
 24      }
 25  
 26      JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
 27          JsonObjectWriter{ os, 0 } {}
 28  
 29      JsonObjectWriter::JsonObjectWriter( std::ostream& os,
 30                                          std::uint64_t indent_level ):
 31          m_os{ os }, m_indent_level{ indent_level } {
 32          m_os << '{';
 33      }
 34      JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ):
 35          m_os{ source.m_os },
 36          m_indent_level{ source.m_indent_level },
 37          m_should_comma{ source.m_should_comma },
 38          m_active{ source.m_active } {
 39          source.m_active = false;
 40      }
 41  
 42      JsonObjectWriter::~JsonObjectWriter() {
 43          if ( !m_active ) { return; }
 44  
 45          m_os << '\n';
 46          JsonUtils::indent( m_os, m_indent_level );
 47          m_os << '}';
 48      }
 49  
 50      JsonValueWriter JsonObjectWriter::write( StringRef key ) {
 51          JsonUtils::appendCommaNewline(
 52              m_os, m_should_comma, m_indent_level + 1 );
 53  
 54          m_os << '"' << key << "\": ";
 55          return JsonValueWriter{ m_os, m_indent_level + 1 };
 56      }
 57  
 58      JsonArrayWriter::JsonArrayWriter( std::ostream& os ):
 59          JsonArrayWriter{ os, 0 } {}
 60      JsonArrayWriter::JsonArrayWriter( std::ostream& os,
 61                                        std::uint64_t indent_level ):
 62          m_os{ os }, m_indent_level{ indent_level } {
 63          m_os << '[';
 64      }
 65      JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ):
 66          m_os{ source.m_os },
 67          m_indent_level{ source.m_indent_level },
 68          m_should_comma{ source.m_should_comma },
 69          m_active{ source.m_active } {
 70          source.m_active = false;
 71      }
 72      JsonArrayWriter::~JsonArrayWriter() {
 73          if ( !m_active ) { return; }
 74  
 75          m_os << '\n';
 76          JsonUtils::indent( m_os, m_indent_level );
 77          m_os << ']';
 78      }
 79  
 80      JsonObjectWriter JsonArrayWriter::writeObject() {
 81          JsonUtils::appendCommaNewline(
 82              m_os, m_should_comma, m_indent_level + 1 );
 83          return JsonObjectWriter{ m_os, m_indent_level + 1 };
 84      }
 85  
 86      JsonArrayWriter JsonArrayWriter::writeArray() {
 87          JsonUtils::appendCommaNewline(
 88              m_os, m_should_comma, m_indent_level + 1 );
 89          return JsonArrayWriter{ m_os, m_indent_level + 1 };
 90      }
 91  
 92      JsonArrayWriter& JsonArrayWriter::write( bool value ) {
 93          return writeImpl( value );
 94      }
 95  
 96      JsonValueWriter::JsonValueWriter( std::ostream& os ):
 97          JsonValueWriter{ os, 0 } {}
 98  
 99      JsonValueWriter::JsonValueWriter( std::ostream& os,
100                                        std::uint64_t indent_level ):
101          m_os{ os }, m_indent_level{ indent_level } {}
102  
103      JsonObjectWriter JsonValueWriter::writeObject() && {
104          return JsonObjectWriter{ m_os, m_indent_level };
105      }
106  
107      JsonArrayWriter JsonValueWriter::writeArray() && {
108          return JsonArrayWriter{ m_os, m_indent_level };
109      }
110  
111      void JsonValueWriter::write( Catch::StringRef value ) && {
112          writeImpl( value, true );
113      }
114  
115      void JsonValueWriter::write( bool value ) && {
116          writeImpl( value ? "true"_sr : "false"_sr, false );
117      }
118  
119      void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
120          if ( quote ) { m_os << '"'; }
121          for (char c : value) {
122              // Escape list taken from https://www.json.org/json-en.html,
123              // string definition.
124              // Note that while forward slash _can_ be escaped, it does
125              // not have to be, if JSON is not further embedded somewhere
126              // where forward slash is meaningful.
127              if ( c == '"' ) {
128                  m_os << "\\\"";
129              } else if ( c == '\\' ) {
130                  m_os << "\\\\";
131              } else if ( c == '\b' ) {
132                  m_os << "\\b";
133              } else if ( c == '\f' ) {
134                  m_os << "\\f";
135              } else if ( c == '\n' ) {
136                  m_os << "\\n";
137              } else if ( c == '\r' ) {
138                  m_os << "\\r";
139              } else if ( c == '\t' ) {
140                  m_os << "\\t";
141              } else {
142                  m_os << c;
143              }
144          }
145          if ( quote ) { m_os << '"'; }
146      }
147  
148  } // namespace Catch