mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	v3.10.0
This commit is contained in:
		| @@ -34,7 +34,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) | ||||
| endif() | ||||
|  | ||||
| project(Catch2 | ||||
|   VERSION 3.9.1 # CML version placeholder, don't delete | ||||
|   VERSION 3.10.0 # CML version placeholder, don't delete | ||||
|   LANGUAGES CXX | ||||
|   HOMEPAGE_URL "https://github.com/catchorg/Catch2" | ||||
|   DESCRIPTION "A modern, C++-native, unit test framework." | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| # Release notes | ||||
| **Contents**<br> | ||||
| [3.10.0](#3100)<br> | ||||
| [3.9.1](#391)<br> | ||||
| [3.9.0](#390)<br> | ||||
| [3.8.1](#381)<br> | ||||
| @@ -69,6 +70,19 @@ | ||||
| [Even Older versions](#even-older-versions)<br> | ||||
|  | ||||
|  | ||||
| ## 3.10.0 | ||||
|  | ||||
| ### Fixes | ||||
| * pkg-config files will take `DESTDIR` env var into account when selecting install destination (#3006, #3019) | ||||
| * Changed `filter` to store the provided predicate by value (#3002, #3005) | ||||
|   * This is done to avoid dangling-by-default behaviour when `filter` is used inside `GENERATE_COPY`/`GENERATE_REF`. | ||||
|  | ||||
| ### Improvements | ||||
| * Escaping XML and JSON output is faster when the strings do not need escaping. | ||||
|   * The improvement starts at about 3x throughput, up to 10x for long strings. | ||||
| * Message macros (`INFO`, `CAPTURE`, `WARN`, `SUCCEED`, etc) are now thread safe. | ||||
|  | ||||
|  | ||||
| ## 3.9.1 | ||||
|  | ||||
| ### Fixes | ||||
|   | ||||
| @@ -44,6 +44,8 @@ they are assertion macro + an if). | ||||
|  | ||||
| ## Assertion-like message macros and spawned threads | ||||
|  | ||||
| > Assertion-like messages were made thread safe in Catch2 3.10.0 | ||||
|  | ||||
| Similarly to assertion macros, not all assertion-like message macros can | ||||
| be used from spawned thread. | ||||
|  | ||||
| @@ -55,6 +57,8 @@ thus can be used from any thread. | ||||
|  | ||||
| ## Message macros and spawned threads | ||||
|  | ||||
| > Message macros were made thread safe in Catch2 3.10.0 | ||||
|  | ||||
| Macros that add extra messages to following assertion, such as `INFO` | ||||
| or `CAPTURE`, are all thread safe and can be used in any thread. Note | ||||
| that these messages are per-thread, and thus `INFO` inside a user-spawned | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|  | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| //  Catch v3.9.1 | ||||
| //  Generated: 2025-08-09 00:29:21.552225 | ||||
| //  Catch v3.10.0 | ||||
| //  Generated: 2025-08-24 16:18:04.775778 | ||||
| //  ---------------------------------------------------------- | ||||
| //  This file is an amalgamation of multiple different files. | ||||
| //  You probably shouldn't edit it directly. | ||||
| @@ -1057,8 +1057,9 @@ namespace Catch { | ||||
|     } | ||||
|     Capturer::~Capturer() { | ||||
|         assert( m_captured == m_messages.size() ); | ||||
|         for ( size_t i = 0; i < m_captured; ++i ) | ||||
|         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 ) { | ||||
| @@ -2278,7 +2279,7 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     Version const& libraryVersion() { | ||||
|         static Version version( 3, 9, 1, "", 0 ); | ||||
|         static Version version( 3, 10, 0, "", 0 ); | ||||
|         return version; | ||||
|     } | ||||
|  | ||||
| @@ -3514,7 +3515,7 @@ namespace { | ||||
| #endif // Windows/ ANSI/ None | ||||
|  | ||||
|  | ||||
| #if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ ) | ||||
| #if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ ) || defined(__FreeBSD__) | ||||
| #    define CATCH_INTERNAL_HAS_ISATTY | ||||
| #    include <unistd.h> | ||||
| #endif | ||||
| @@ -4458,6 +4459,33 @@ namespace Detail { | ||||
|  | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     namespace { | ||||
|         static bool needsEscape( char c ) { | ||||
|             return c == '"' || c == '\\' || c == '\b' || c == '\f' || | ||||
|                    c == '\n' || c == '\r' || c == '\t'; | ||||
|         } | ||||
|  | ||||
|         static Catch::StringRef makeEscapeStringRef( char c ) { | ||||
|             if ( c == '"' ) { | ||||
|                 return "\\\""_sr; | ||||
|             } else if ( c == '\\' ) { | ||||
|                 return "\\\\"_sr; | ||||
|             } else if ( c == '\b' ) { | ||||
|                 return "\\b"_sr; | ||||
|             } else if ( c == '\f' ) { | ||||
|                 return "\\f"_sr; | ||||
|             } else if ( c == '\n' ) { | ||||
|                 return "\\n"_sr; | ||||
|             } else if ( c == '\r' ) { | ||||
|                 return "\\r"_sr; | ||||
|             } else if ( c == '\t' ) { | ||||
|                 return "\\t"_sr; | ||||
|             } | ||||
|             Catch::Detail::Unreachable(); | ||||
|         } | ||||
|     } // namespace | ||||
|  | ||||
|     void JsonUtils::indent( std::ostream& os, std::uint64_t level ) { | ||||
|         for ( std::uint64_t i = 0; i < level; ++i ) { | ||||
|             os << "  "; | ||||
| @@ -4567,30 +4595,19 @@ namespace Catch { | ||||
|  | ||||
|     void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) { | ||||
|         if ( quote ) { m_os << '"'; } | ||||
|         for (char c : value) { | ||||
|             // Escape list taken from https://www.json.org/json-en.html, | ||||
|             // string definition. | ||||
|             // Note that while forward slash _can_ be escaped, it does | ||||
|             // not have to be, if JSON is not further embedded somewhere | ||||
|             // where forward slash is meaningful. | ||||
|             if ( c == '"' ) { | ||||
|                 m_os << "\\\""; | ||||
|             } else if ( c == '\\' ) { | ||||
|                 m_os << "\\\\"; | ||||
|             } else if ( c == '\b' ) { | ||||
|                 m_os << "\\b"; | ||||
|             } else if ( c == '\f' ) { | ||||
|                 m_os << "\\f"; | ||||
|             } else if ( c == '\n' ) { | ||||
|                 m_os << "\\n"; | ||||
|             } else if ( c == '\r' ) { | ||||
|                 m_os << "\\r"; | ||||
|             } else if ( c == '\t' ) { | ||||
|                 m_os << "\\t"; | ||||
|             } else { | ||||
|                 m_os << c; | ||||
|         size_t current_start = 0; | ||||
|         for ( size_t i = 0; i < value.size(); ++i ) { | ||||
|             if ( needsEscape( value[i] ) ) { | ||||
|                 if ( current_start < i ) { | ||||
|                     m_os << value.substr( current_start, i - current_start ); | ||||
|                 } | ||||
|                 m_os << makeEscapeStringRef( value[i] ); | ||||
|                 current_start = i + 1; | ||||
|             } | ||||
|         } | ||||
|         if ( current_start < value.size() ) { | ||||
|             m_os << value.substr( current_start, value.size() - current_start ); | ||||
|         } | ||||
|         if ( quote ) { m_os << '"'; } | ||||
|     } | ||||
|  | ||||
| @@ -4787,17 +4804,18 @@ int main (int argc, char * argv[]) { | ||||
|  | ||||
| namespace Catch { | ||||
|  | ||||
|     MessageInfo::MessageInfo(   StringRef _macroName, | ||||
|                                 SourceLineInfo const& _lineInfo, | ||||
|                                 ResultWas::OfType _type ) | ||||
|     MessageInfo::MessageInfo( StringRef _macroName, | ||||
|                               SourceLineInfo const& _lineInfo, | ||||
|                               ResultWas::OfType _type ) | ||||
|     :   macroName( _macroName ), | ||||
|         lineInfo( _lineInfo ), | ||||
|         type( _type ), | ||||
|         sequence( ++globalCount ) | ||||
|     {} | ||||
|  | ||||
|     // This may need protecting if threading support is added | ||||
|     unsigned int MessageInfo::globalCount = 0; | ||||
|     // Messages are owned by their individual threads, so the counter should be thread-local as well. | ||||
|     // Alternative consideration: atomic, so threads don't share IDs and things are easier to debug. | ||||
|     thread_local unsigned int MessageInfo::globalCount = 0; | ||||
|  | ||||
| } // end namespace Catch | ||||
|  | ||||
| @@ -5556,8 +5574,10 @@ namespace Catch { | ||||
|         std::vector<Detail::unique_ptr<std::ostringstream>> m_streams; | ||||
|         std::vector<std::size_t> m_unused; | ||||
|         std::ostringstream m_referenceStream; // Used for copy state/ flags from | ||||
|         Detail::Mutex m_mutex; | ||||
|  | ||||
|         auto add() -> std::size_t { | ||||
|             Detail::LockGuard _( m_mutex ); | ||||
|             if( m_unused.empty() ) { | ||||
|                 m_streams.push_back( Detail::make_unique<std::ostringstream>() ); | ||||
|                 return m_streams.size()-1; | ||||
| @@ -5569,9 +5589,13 @@ namespace Catch { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void release( std::size_t index ) { | ||||
|             m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state | ||||
|             m_unused.push_back(index); | ||||
|         void release( std::size_t index, std::ostream* originalPtr ) { | ||||
|             assert( originalPtr ); | ||||
|             originalPtr->copyfmt( m_referenceStream );  // Restore initial flags and other state | ||||
|  | ||||
|             Detail::LockGuard _( m_mutex ); | ||||
|             assert( originalPtr == m_streams[index].get() && "Mismatch between release index and stream ptr" ); | ||||
|             m_unused.push_back( index ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -5583,7 +5607,7 @@ namespace Catch { | ||||
|     ReusableStringStream::~ReusableStringStream() { | ||||
|         static_cast<std::ostringstream*>( m_oss )->str(""); | ||||
|         m_oss->clear(); | ||||
|         Singleton<StringStreams>::getMutable().release( m_index ); | ||||
|         Singleton<StringStreams>::getMutable().release( m_index, m_oss ); | ||||
|     } | ||||
|  | ||||
|     std::string ReusableStringStream::str() const { | ||||
| @@ -5750,9 +5774,6 @@ namespace Catch { | ||||
|         // This also implies that messages are owned by their respective | ||||
|         // threads, and should not be shared across different threads. | ||||
|         // | ||||
|         // For simplicity, we disallow messages in multi-threaded contexts, | ||||
|         // but in the future we can enable them under this logic. | ||||
|         // | ||||
|         // This implies that various pieces of metadata referring to last | ||||
|         // assertion result/source location/message handling, etc | ||||
|         // should also be thread local. For now we just use naked globals | ||||
| @@ -5761,15 +5782,27 @@ namespace Catch { | ||||
|  | ||||
|         // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE | ||||
|         static thread_local bool g_lastAssertionPassed = false; | ||||
|         // Should we clear message scopes before sending off the messages to | ||||
|         // reporter? Set in `assertionPassedFastPath` to avoid doing the full | ||||
|         // clear there for performance reasons. | ||||
|         static thread_local bool g_clearMessageScopes = false; | ||||
|  | ||||
|         // This is the source location for last encountered macro. It is | ||||
|         // used to provide the users with more precise location of error | ||||
|         // when an unexpected exception/fatal error happens. | ||||
|         static thread_local SourceLineInfo g_lastKnownLineInfo("DummyLocation", static_cast<size_t>(-1)); | ||||
|     } | ||||
|  | ||||
|         // Should we clear message scopes before sending off the messages to | ||||
|         // reporter? Set in `assertionPassedFastPath` to avoid doing the full | ||||
|         // clear there for performance reasons. | ||||
|         static thread_local bool g_clearMessageScopes = false; | ||||
|  | ||||
|         CATCH_INTERNAL_START_WARNINGS_SUPPRESSION | ||||
|         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS | ||||
|         // Actual messages to be provided to the reporter | ||||
|         static thread_local std::vector<MessageInfo> g_messages; | ||||
|  | ||||
|         // Owners for the UNSCOPED_X information macro | ||||
|         static thread_local std::vector<ScopedMessage> g_messageScopes; | ||||
|         CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION | ||||
|  | ||||
|     } // namespace Detail | ||||
|  | ||||
|     RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) | ||||
|     :   m_runInfo(_config->name()), | ||||
| @@ -5905,20 +5938,21 @@ namespace Catch { | ||||
|             Detail::g_lastAssertionPassed = true; | ||||
|         } | ||||
|  | ||||
|         if ( Detail::g_clearMessageScopes ) { | ||||
|             Detail::g_messageScopes.clear(); | ||||
|             Detail::g_clearMessageScopes = false; | ||||
|         } | ||||
|  | ||||
|         // From here, we are touching shared state and need mutex. | ||||
|         Detail::LockGuard lock( m_assertionMutex ); | ||||
|         { | ||||
|             if ( Detail::g_clearMessageScopes ) { | ||||
|                 m_messageScopes.clear(); | ||||
|                 Detail::g_clearMessageScopes = false; | ||||
|             } | ||||
|             auto _ = scopedDeactivate( *m_outputRedirect ); | ||||
|             updateTotalsFromAtomics(); | ||||
|             m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ); | ||||
|             m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) ); | ||||
|         } | ||||
|  | ||||
|         if ( result.getResultType() != ResultWas::Warning ) { | ||||
|             m_messageScopes.clear(); | ||||
|             Detail::g_messageScopes.clear(); | ||||
|         } | ||||
|  | ||||
|         // Reset working state. assertion info will be reset after | ||||
| @@ -6051,8 +6085,8 @@ namespace Catch { | ||||
|         m_reporter->benchmarkFailed( error ); | ||||
|     } | ||||
|  | ||||
|     void RunContext::pushScopedMessage(MessageInfo const & message) { | ||||
|         m_messages.push_back(message); | ||||
|     void RunContext::pushScopedMessage( MessageInfo const& message ) { | ||||
|         Detail::g_messages.push_back( message ); | ||||
|     } | ||||
|  | ||||
|     void RunContext::popScopedMessage( MessageInfo const& message ) { | ||||
| @@ -6061,16 +6095,16 @@ namespace Catch { | ||||
|         //       messages than low single digits, so the optimization is tiny, | ||||
|         //       and we would have to hand-write the loop to avoid terrible | ||||
|         //       codegen of reverse iterators in debug mode. | ||||
|         m_messages.erase( | ||||
|             std::find_if( m_messages.begin(), | ||||
|                           m_messages.end(), | ||||
|         Detail::g_messages.erase( | ||||
|             std::find_if( Detail::g_messages.begin(), | ||||
|                           Detail::g_messages.end(), | ||||
|                           [id = message.sequence]( MessageInfo const& msg ) { | ||||
|                               return msg.sequence == id; | ||||
|                           } ) ); | ||||
|     } | ||||
|  | ||||
|     void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { | ||||
|         m_messageScopes.emplace_back( CATCH_MOVE(builder) ); | ||||
|         Detail::g_messageScopes.emplace_back( CATCH_MOVE(builder) ); | ||||
|     } | ||||
|  | ||||
|     std::string RunContext::getCurrentTestName() const { | ||||
| @@ -6229,10 +6263,10 @@ namespace Catch { | ||||
|  | ||||
|         m_testCaseTracker->close(); | ||||
|         handleUnfinishedSections(); | ||||
|         m_messageScopes.clear(); | ||||
|         Detail::g_messageScopes.clear(); | ||||
|         // TBD: At this point, m_messages should be empty. Do we want to | ||||
|         //      assert that this is true, or keep the defensive clear call? | ||||
|         m_messages.clear(); | ||||
|         Detail::g_messages.clear(); | ||||
|  | ||||
|         SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); | ||||
|         m_reporter->sectionEnded(testCaseSectionStats); | ||||
| @@ -7971,7 +8005,7 @@ namespace { | ||||
|  | ||||
|     void hexEscapeChar(std::ostream& os, unsigned char c) { | ||||
|         std::ios_base::fmtflags f(os.flags()); | ||||
|         os << "\\x" | ||||
|         os << "\\x"_sr | ||||
|             << std::uppercase << std::hex << std::setfill('0') << std::setw(2) | ||||
|             << static_cast<int>(c); | ||||
|         os.flags(f); | ||||
| @@ -7990,95 +8024,111 @@ namespace { | ||||
|     void XmlEncode::encodeTo( std::ostream& os ) const { | ||||
|         // Apostrophe escaping not necessary if we always use " to write attributes | ||||
|         // (see: http://www.w3.org/TR/xml/#syntax) | ||||
|         size_t last_start = 0; | ||||
|         auto write_to = [&]( size_t idx ) { | ||||
|             if ( last_start < idx ) { | ||||
|                 os << m_str.substr( last_start, idx - last_start ); | ||||
|             } | ||||
|             last_start = idx + 1; | ||||
|         }; | ||||
|  | ||||
|         for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { | ||||
|             unsigned char c = static_cast<unsigned char>(m_str[idx]); | ||||
|             switch (c) { | ||||
|             case '<':   os << "<"; break; | ||||
|             case '&':   os << "&"; break; | ||||
|         for ( std::size_t idx = 0; idx < m_str.size(); ++idx ) { | ||||
|             unsigned char c = static_cast<unsigned char>( m_str[idx] ); | ||||
|             switch ( c ) { | ||||
|             case '<': | ||||
|                 write_to( idx ); | ||||
|                 os << "<"_sr; | ||||
|                 break; | ||||
|             case '&': | ||||
|                 write_to( idx ); | ||||
|                 os << "&"_sr; | ||||
|                 break; | ||||
|  | ||||
|             case '>': | ||||
|                 // See: http://www.w3.org/TR/xml/#syntax | ||||
|                 if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') | ||||
|                     os << ">"; | ||||
|                 else | ||||
|                     os << c; | ||||
|                 if ( idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']' ) { | ||||
|                     write_to( idx ); | ||||
|                     os << ">"_sr; | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|             case '\"': | ||||
|                 if (m_forWhat == ForAttributes) | ||||
|                     os << """; | ||||
|                 else | ||||
|                     os << c; | ||||
|                 if ( m_forWhat == ForAttributes ) { | ||||
|                     write_to( idx ); | ||||
|                     os << """_sr; | ||||
|                 } | ||||
|                 break; | ||||
|  | ||||
|             default: | ||||
|                 // Check for control characters and invalid utf-8 | ||||
|  | ||||
|                 // Escape control characters in standard ascii | ||||
|                 // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 | ||||
|                 if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { | ||||
|                     hexEscapeChar(os, c); | ||||
|                 // see | ||||
|                 // http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 | ||||
|                 if ( c < 0x09 || ( c > 0x0D && c < 0x20 ) || c == 0x7F ) { | ||||
|                     write_to( idx ); | ||||
|                     hexEscapeChar( os, c ); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 // Plain ASCII: Write it to stream | ||||
|                 if (c < 0x7F) { | ||||
|                     os << c; | ||||
|                 if ( c < 0x7F ) { | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 // UTF-8 territory | ||||
|                 // Check if the encoding is valid and if it is not, hex escape bytes. | ||||
|                 // Important: We do not check the exact decoded values for validity, only the encoding format | ||||
|                 // First check that this bytes is a valid lead byte: | ||||
|                 // This means that it is not encoded as 1111 1XXX | ||||
|                 // Check if the encoding is valid and if it is not, hex escape | ||||
|                 // bytes. Important: We do not check the exact decoded values for | ||||
|                 // validity, only the encoding format First check that this bytes is | ||||
|                 // a valid lead byte: This means that it is not encoded as 1111 1XXX | ||||
|                 // Or as 10XX XXXX | ||||
|                 if (c <  0xC0 || | ||||
|                     c >= 0xF8) { | ||||
|                     hexEscapeChar(os, c); | ||||
|                 if ( c < 0xC0 || c >= 0xF8 ) { | ||||
|                     write_to( idx ); | ||||
|                     hexEscapeChar( os, c ); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 auto encBytes = trailingBytes(c); | ||||
|                 // Are there enough bytes left to avoid accessing out-of-bounds memory? | ||||
|                 if (idx + encBytes - 1 >= m_str.size()) { | ||||
|                     hexEscapeChar(os, c); | ||||
|                 auto encBytes = trailingBytes( c ); | ||||
|                 // Are there enough bytes left to avoid accessing out-of-bounds | ||||
|                 // memory? | ||||
|                 if ( idx + encBytes - 1 >= m_str.size() ) { | ||||
|                     write_to( idx ); | ||||
|                     hexEscapeChar( os, c ); | ||||
|                     break; | ||||
|                 } | ||||
|                 // The header is valid, check data | ||||
|                 // The next encBytes bytes must together be a valid utf-8 | ||||
|                 // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) | ||||
|                 // This means: bitpattern 10XX XXXX and the extracted value is sane | ||||
|                 // (ish) | ||||
|                 bool valid = true; | ||||
|                 uint32_t value = headerValue(c); | ||||
|                 for (std::size_t n = 1; n < encBytes; ++n) { | ||||
|                     unsigned char nc = static_cast<unsigned char>(m_str[idx + n]); | ||||
|                     valid &= ((nc & 0xC0) == 0x80); | ||||
|                     value = (value << 6) | (nc & 0x3F); | ||||
|                 uint32_t value = headerValue( c ); | ||||
|                 for ( std::size_t n = 1; n < encBytes; ++n ) { | ||||
|                     unsigned char nc = static_cast<unsigned char>( m_str[idx + n] ); | ||||
|                     valid &= ( ( nc & 0xC0 ) == 0x80 ); | ||||
|                     value = ( value << 6 ) | ( nc & 0x3F ); | ||||
|                 } | ||||
|  | ||||
|                 if ( | ||||
|                     // Wrong bit pattern of following bytes | ||||
|                     (!valid) || | ||||
|                     ( !valid ) || | ||||
|                     // Overlong encodings | ||||
|                     (value < 0x80) || | ||||
|                     (0x80 <= value && value < 0x800   && encBytes > 2) || | ||||
|                     (0x800 < value && value < 0x10000 && encBytes > 3) || | ||||
|                     ( value < 0x80 ) || | ||||
|                     ( 0x80 <= value && value < 0x800 && encBytes > 2 ) || | ||||
|                     ( 0x800 < value && value < 0x10000 && encBytes > 3 ) || | ||||
|                     // Encoded value out of range | ||||
|                     (value >= 0x110000) | ||||
|                     ) { | ||||
|                     hexEscapeChar(os, c); | ||||
|                     ( value >= 0x110000 ) ) { | ||||
|                     write_to( idx ); | ||||
|                     hexEscapeChar( os, c ); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 // If we got here, this is in fact a valid(ish) utf-8 sequence | ||||
|                 for (std::size_t n = 0; n < encBytes; ++n) { | ||||
|                     os << m_str[idx + n]; | ||||
|                 } | ||||
|                 idx += encBytes - 1; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         write_to( m_str.size() ); | ||||
|     } | ||||
|  | ||||
|     std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|  | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| //  Catch v3.9.1 | ||||
| //  Generated: 2025-08-09 00:29:20.303175 | ||||
| //  Catch v3.10.0 | ||||
| //  Generated: 2025-08-24 16:18:04.055916 | ||||
| //  ---------------------------------------------------------- | ||||
| //  This file is an amalgamation of multiple different files. | ||||
| //  You probably shouldn't edit it directly. | ||||
| @@ -3972,7 +3972,7 @@ namespace Catch { | ||||
|             return sequence < other.sequence; | ||||
|         } | ||||
|     private: | ||||
|         static unsigned int globalCount; | ||||
|         static thread_local unsigned int globalCount; | ||||
|     }; | ||||
|  | ||||
| } // end namespace Catch | ||||
| @@ -7466,8 +7466,8 @@ namespace Catch { | ||||
| #define CATCH_VERSION_MACROS_HPP_INCLUDED | ||||
|  | ||||
| #define CATCH_VERSION_MAJOR 3 | ||||
| #define CATCH_VERSION_MINOR 9 | ||||
| #define CATCH_VERSION_PATCH 1 | ||||
| #define CATCH_VERSION_MINOR 10 | ||||
| #define CATCH_VERSION_PATCH 0 | ||||
|  | ||||
| #endif // CATCH_VERSION_MACROS_HPP_INCLUDED | ||||
|  | ||||
| @@ -10773,9 +10773,6 @@ namespace Catch { | ||||
|         Totals m_totals; | ||||
|         Detail::AtomicCounts m_atomicAssertionCount; | ||||
|         IEventListenerPtr m_reporter; | ||||
|         std::vector<MessageInfo> m_messages; | ||||
|         // Owners for the UNSCOPED_X information macro | ||||
|         std::vector<ScopedMessage> m_messageScopes; | ||||
|         std::vector<SectionEndInfo> m_unfinishedSections; | ||||
|         std::vector<ITracker*> m_activeSections; | ||||
|         TrackerContext m_trackerContext; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| project( | ||||
|   'catch2', | ||||
|   'cpp', | ||||
|   version: '3.9.1', # CML version placeholder, don't delete | ||||
|   version: '3.10.0', # CML version placeholder, don't delete | ||||
|   license: 'BSL-1.0', | ||||
|   meson_version: '>=0.54.1', | ||||
| ) | ||||
|   | ||||
| @@ -36,7 +36,7 @@ namespace Catch { | ||||
|     } | ||||
|  | ||||
|     Version const& libraryVersion() { | ||||
|         static Version version( 3, 9, 1, "", 0 ); | ||||
|         static Version version( 3, 10, 0, "", 0 ); | ||||
|         return version; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| #define CATCH_VERSION_MACROS_HPP_INCLUDED | ||||
|  | ||||
| #define CATCH_VERSION_MAJOR 3 | ||||
| #define CATCH_VERSION_MINOR 9 | ||||
| #define CATCH_VERSION_PATCH 1 | ||||
| #define CATCH_VERSION_MINOR 10 | ||||
| #define CATCH_VERSION_PATCH 0 | ||||
|  | ||||
| #endif // CATCH_VERSION_MACROS_HPP_INCLUDED | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Martin Hořeňovský
					Martin Hořeňovský