diff --git a/CMakeLists.txt b/CMakeLists.txt index 20e4036e..b4dd2b52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif() project(Catch2 - VERSION 3.5.0 # CML version placeholder, don't delete + VERSION 3.5.1 # CML version placeholder, don't delete LANGUAGES CXX # HOMEPAGE_URL is not supported until CMake version 3.12, which # we do not target yet. diff --git a/docs/release-notes.md b/docs/release-notes.md index 9751f2ce..0449ed0e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[3.5.1](#351)
[3.5.0](#350)
[3.4.0](#340)
[3.3.2](#332)
@@ -58,6 +59,17 @@ [Even Older versions](#even-older-versions)
+## 3.5.1 + +### Improvements +* Significantly improved performance of the CLI parsing. + * This includes the cost of preparing the CLI parser, so Catch2's binaries start much faster. + +### Miscellaneous +* Added support for Bazel modules (#2781) +* Added CMake option to disable the build reproducibility settings (#2785) +* Added `log` library linking to the Meson build (#2784) + ## 3.5.0 diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp index cfc38a46..30e2d9f2 100644 --- a/extras/catch_amalgamated.cpp +++ b/extras/catch_amalgamated.cpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.5.0 -// Generated: 2023-12-11 00:51:07.662625 +// Catch v3.5.1 +// Generated: 2023-12-31 15:10:55.864983 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -2273,7 +2273,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 5, 0, "", 0 ); + static Version version( 3, 5, 1, "", 0 ); return version; } @@ -2415,9 +2415,7 @@ namespace Catch { -#include #include -#include namespace Catch { @@ -2627,13 +2625,29 @@ namespace { ; } - std::string normaliseOpt( std::string const& optName ) { -#ifdef CATCH_PLATFORM_WINDOWS - if ( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else + Catch::StringRef normaliseOpt( Catch::StringRef optName ) { + if ( optName[0] == '-' +#if defined(CATCH_PLATFORM_WINDOWS) + || optName[0] == '/' #endif - return optName; + ) { + return optName.substr( 1, optName.size() ); + } + + return optName; + } + + static size_t find_first_separator(Catch::StringRef sr) { + auto is_separator = []( char c ) { + return c == ' ' || c == ':' || c == '='; + }; + size_t pos = 0; + while (pos < sr.size()) { + if (is_separator(sr[pos])) { return pos; } + ++pos; + } + + return Catch::StringRef::npos; } } // namespace @@ -2651,23 +2665,23 @@ namespace Catch { } if ( it != itEnd ) { - auto const& next = *it; + StringRef next = *it; if ( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if ( delimiterPos != std::string::npos ) { + auto delimiterPos = find_first_separator(next); + if ( delimiterPos != StringRef::npos ) { m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); m_tokenBuffer.push_back( { TokenType::Argument, - next.substr( delimiterPos + 1 ) } ); + next.substr( delimiterPos + 1, next.size() ) } ); } else { if ( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; + // Combined short args, e.g. "-ab" for "-a -b" for ( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; m_tokenBuffer.push_back( - { TokenType::Option, opt } ); + { TokenType::Option, + next.substr( i, 1 ) } ); } } else { m_tokenBuffer.push_back( @@ -2727,12 +2741,12 @@ namespace Catch { size_t ParserBase::cardinality() const { return 1; } InternalParseResult ParserBase::parse( Args const& args ) const { - return parse( args.exeName(), TokenStream( args ) ); + return parse( static_cast(args.exeName()), TokenStream( args ) ); } ParseState::ParseState( ParseResultType type, - TokenStream const& remainingTokens ): - m_type( type ), m_remainingTokens( remainingTokens ) {} + TokenStream remainingTokens ): + m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {} ParserResult BoundFlagRef::setFlag( bool flag ) { m_ref = flag; @@ -2750,34 +2764,34 @@ namespace Catch { } // namespace Detail Detail::InternalParseResult Arg::parse(std::string const&, - Detail::TokenStream const& tokens) const { + Detail::TokenStream tokens) const { auto validationResult = validate(); if (!validationResult) return Detail::InternalParseResult(validationResult); - auto remainingTokens = tokens; - auto const& token = *remainingTokens; + auto token = *tokens; if (token.type != Detail::TokenType::Argument) return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::NoMatch, remainingTokens)); + ParseResultType::NoMatch, CATCH_MOVE(tokens))); assert(!m_ref->isFlag()); auto valueRef = static_cast(m_ref.get()); - auto result = valueRef->setValue(remainingTokens->token); - if (!result) - return Detail::InternalParseResult(result); + auto result = valueRef->setValue(static_cast(token.token)); + if ( !result ) + return Detail::InternalParseResult( result ); else - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::Matched, ++remainingTokens)); + return Detail::InternalParseResult::ok( + Detail::ParseState( ParseResultType::Matched, + CATCH_MOVE( ++tokens ) ) ); } Opt::Opt(bool& ref) : ParserRefImpl(std::make_shared(ref)) {} - std::vector Opt::getHelpColumns() const { - std::ostringstream oss; + Detail::HelpColumns Opt::getHelpColumns() const { + ReusableStringStream oss; bool first = true; for (auto const& opt : m_optNames) { if (first) @@ -2788,10 +2802,10 @@ namespace Catch { } if (!m_hint.empty()) oss << " <" << m_hint << '>'; - return { { oss.str(), m_description } }; + return { oss.str(), m_description }; } - bool Opt::isMatch(std::string const& optToken) const { + bool Opt::isMatch(StringRef optToken) const { auto normalisedToken = normaliseOpt(optToken); for (auto const& name : m_optNames) { if (normaliseOpt(name) == normalisedToken) @@ -2801,15 +2815,14 @@ namespace Catch { } Detail::InternalParseResult Opt::parse(std::string const&, - Detail::TokenStream const& tokens) const { + Detail::TokenStream tokens) const { auto validationResult = validate(); if (!validationResult) return Detail::InternalParseResult(validationResult); - auto remainingTokens = tokens; - if (remainingTokens && - remainingTokens->type == Detail::TokenType::Option) { - auto const& token = *remainingTokens; + if (tokens && + tokens->type == Detail::TokenType::Option) { + auto const& token = *tokens; if (isMatch(token.token)) { if (m_ref->isFlag()) { auto flagRef = @@ -2821,35 +2834,35 @@ namespace Catch { if (result.value() == ParseResultType::ShortCircuitAll) return Detail::InternalParseResult::ok(Detail::ParseState( - result.value(), remainingTokens)); + result.value(), CATCH_MOVE(tokens))); } else { auto valueRef = static_cast( m_ref.get()); - ++remainingTokens; - if (!remainingTokens) + ++tokens; + if (!tokens) return Detail::InternalParseResult::runtimeError( "Expected argument following " + token.token); - auto const& argToken = *remainingTokens; + auto const& argToken = *tokens; if (argToken.type != Detail::TokenType::Argument) return Detail::InternalParseResult::runtimeError( "Expected argument following " + token.token); - const auto result = valueRef->setValue(argToken.token); + const auto result = valueRef->setValue(static_cast(argToken.token)); if (!result) return Detail::InternalParseResult(result); if (result.value() == ParseResultType::ShortCircuitAll) return Detail::InternalParseResult::ok(Detail::ParseState( - result.value(), remainingTokens)); + result.value(), CATCH_MOVE(tokens))); } return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::Matched, ++remainingTokens)); + ParseResultType::Matched, CATCH_MOVE(++tokens))); } } return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, remainingTokens)); + Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens))); } Detail::Result Opt::validate() const { @@ -2881,9 +2894,9 @@ namespace Catch { Detail::InternalParseResult ExeName::parse(std::string const&, - Detail::TokenStream const& tokens) const { + Detail::TokenStream tokens) const { return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, tokens)); + Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens))); } ParserResult ExeName::set(std::string const& newName) { @@ -2913,9 +2926,9 @@ namespace Catch { std::vector Parser::getHelpColumns() const { std::vector cols; + cols.reserve( m_options.size() ); for ( auto const& o : m_options ) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); + cols.push_back(o.getHelpColumns()); } return cols; } @@ -2953,12 +2966,12 @@ namespace Catch { optWidth = ( std::min )( optWidth, consoleWidth / 2 ); - for ( auto const& cols : rows ) { - auto row = TextFlow::Column( cols.left ) + for ( auto& cols : rows ) { + auto row = TextFlow::Column( CATCH_MOVE(cols.left) ) .width( optWidth ) .indent( 2 ) + TextFlow::Spacer( 4 ) + - TextFlow::Column( cols.right ) + TextFlow::Column( static_cast(cols.descriptions) ) .width( consoleWidth - 7 - optWidth ); os << row << '\n'; } @@ -2980,7 +2993,7 @@ namespace Catch { Detail::InternalParseResult Parser::parse( std::string const& exeName, - Detail::TokenStream const& tokens ) const { + Detail::TokenStream tokens ) const { struct ParserInfo { ParserBase const* parser = nullptr; @@ -2998,7 +3011,7 @@ namespace Catch { m_exeName.set( exeName ); auto result = Detail::InternalParseResult::ok( - Detail::ParseState( ParseResultType::NoMatch, tokens ) ); + Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) ); while ( result.value().remainingTokens() ) { bool tokenParsed = false; @@ -3006,7 +3019,7 @@ namespace Catch { if ( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { result = parseInfo.parser->parse( - exeName, result.value().remainingTokens() ); + exeName, CATCH_MOVE(result).value().remainingTokens() ); if ( !result ) return result; if ( result.value().type() != @@ -3032,7 +3045,7 @@ namespace Catch { Args::Args(int argc, char const* const* argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {} - Args::Args(std::initializer_list args) : + Args::Args(std::initializer_list args) : m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {} @@ -3338,8 +3351,8 @@ namespace Catch { ( "split the tests to execute into this many groups" ) | Opt( setShardIndex, "shard index" ) ["--shard-index"] - ( "index of the group of tests to execute (see --shard-count)" ) | - Opt( config.allowZeroTests ) + ( "index of the group of tests to execute (see --shard-count)" ) + | Opt( config.allowZeroTests ) ["--allow-running-no-tests"] ( "Treat 'No tests run' as a success" ) | Arg( config.testsOrTags, "test name|pattern|tags" ) @@ -4641,7 +4654,6 @@ Catch::LeakDetector::~LeakDetector() { - namespace Catch { namespace { @@ -6527,7 +6539,6 @@ namespace Catch { return sorted; } case TestRunOrder::Randomized: { - seedRng(config); using TestWithHash = std::pair; TestCaseInfoHasher h{ config.rngSeed() }; @@ -7390,23 +7401,36 @@ namespace Catch { return os; } - Columns Column::operator+( Column const& other ) { + Columns operator+(Column const& lhs, Column const& rhs) { Columns cols; - cols += *this; - cols += other; + cols += lhs; + cols += rhs; + return cols; + } + Columns operator+(Column&& lhs, Column&& rhs) { + Columns cols; + cols += CATCH_MOVE( lhs ); + cols += CATCH_MOVE( rhs ); return cols; } - Columns& Columns::operator+=( Column const& col ) { - m_columns.push_back( col ); - return *this; + Columns& operator+=(Columns& lhs, Column const& rhs) { + lhs.m_columns.push_back( rhs ); + return lhs; } - - Columns Columns::operator+( Column const& col ) { - Columns combined = *this; - combined += col; + Columns& operator+=(Columns& lhs, Column&& rhs) { + lhs.m_columns.push_back( CATCH_MOVE(rhs) ); + return lhs; + } + Columns operator+( Columns const& lhs, Column const& rhs ) { + auto combined( lhs ); + combined += rhs; return combined; } + Columns operator+( Columns&& lhs, Column&& rhs ) { + lhs += CATCH_MOVE( rhs ); + return CATCH_MOVE( lhs ); + } } // namespace TextFlow } // namespace Catch @@ -8881,11 +8905,10 @@ public: *this << RowBreak(); TextFlow::Columns headerCols; - auto spacer = TextFlow::Spacer(2); for (auto const& info : m_columnInfos) { assert(info.width > 2); headerCols += TextFlow::Column(info.name).width(info.width - 2); - headerCols += spacer; + headerCols += TextFlow::Spacer( 2 ); } m_os << headerCols << '\n'; diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp index bec588d4..4f075857 100644 --- a/extras/catch_amalgamated.hpp +++ b/extras/catch_amalgamated.hpp @@ -6,8 +6,8 @@ // SPDX-License-Identifier: BSL-1.0 -// Catch v3.5.0 -// Generated: 2023-12-11 00:51:06.770598 +// Catch v3.5.1 +// Generated: 2023-12-31 15:10:53.044176 // ---------------------------------------------------------- // This file is an amalgamation of multiple different files. // You probably shouldn't edit it directly. @@ -690,6 +690,8 @@ namespace Catch { using size_type = std::size_t; using const_iterator = const char*; + static constexpr size_type npos{ static_cast( -1 ) }; + private: static constexpr char const* const s_empty = ""; @@ -740,7 +742,7 @@ namespace Catch { } // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, start + size()). + // If start + length > size(), then the substring is [start, size()). // If start > size(), then the substring is empty. constexpr StringRef substr(size_type start, size_type length) const noexcept { if (start < m_size) { @@ -1969,12 +1971,12 @@ namespace Catch { template int warmup() { - return run_for_at_least(std::chrono::duration_cast(warmup_time), warmup_seed, &resolution) + return run_for_at_least(warmup_time, warmup_seed, &resolution) .iterations; } template EnvironmentEstimate estimate_clock_resolution(int iterations) { - auto r = run_for_at_least(std::chrono::duration_cast(clock_resolution_estimation_time), iterations, &resolution) + auto r = run_for_at_least(clock_resolution_estimation_time, iterations, &resolution) .result; return { FDuration(mean(r.data(), r.data() + r.size())), @@ -1996,7 +1998,7 @@ namespace Catch { }; time_clock(1); int iters = clock_cost_estimation_iterations; - auto&& r = run_for_at_least(std::chrono::duration_cast(clock_cost_estimation_time), iters, time_clock); + auto&& r = run_for_at_least(clock_cost_estimation_time, iters, time_clock); std::vector times; int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); times.reserve(static_cast(nsamples)); @@ -3639,141 +3641,6 @@ namespace Catch { #define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED - -#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED -#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED - - -#include -#include - -namespace Catch { - - enum class ColourMode : std::uint8_t; - class IStream; - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - BrightYellow = Bright | Yellow, - - // By intention - FileName = LightGrey, - Warning = BrightYellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - Skip = LightGrey, - - OriginalExpression = Cyan, - ReconstructedExpression = BrightYellow, - - SecondaryText = LightGrey, - Headers = White - }; - }; - - class ColourImpl { - protected: - //! The associated stream of this ColourImpl instance - IStream* m_stream; - public: - ColourImpl( IStream* stream ): m_stream( stream ) {} - - //! RAII wrapper around writing specific colour of text using specific - //! colour impl into a stream. - class ColourGuard { - ColourImpl const* m_colourImpl; - Colour::Code m_code; - bool m_engaged = false; - - public: - //! Does **not** engage the guard/start the colour - ColourGuard( Colour::Code code, - ColourImpl const* colour ); - - ColourGuard( ColourGuard const& rhs ) = delete; - ColourGuard& operator=( ColourGuard const& rhs ) = delete; - - ColourGuard( ColourGuard&& rhs ) noexcept; - ColourGuard& operator=( ColourGuard&& rhs ) noexcept; - - //! Removes colour _if_ the guard was engaged - ~ColourGuard(); - - /** - * Explicitly engages colour for given stream. - * - * The API based on operator<< should be preferred. - */ - ColourGuard& engage( std::ostream& stream ) &; - /** - * Explicitly engages colour for given stream. - * - * The API based on operator<< should be preferred. - */ - ColourGuard&& engage( std::ostream& stream ) &&; - - private: - //! Engages the guard and starts using colour - friend std::ostream& operator<<( std::ostream& lhs, - ColourGuard& guard ) { - guard.engageImpl( lhs ); - return lhs; - } - //! Engages the guard and starts using colour - friend std::ostream& operator<<( std::ostream& lhs, - ColourGuard&& guard) { - guard.engageImpl( lhs ); - return lhs; - } - - void engageImpl( std::ostream& stream ); - - }; - - virtual ~ColourImpl(); // = default - /** - * Creates a guard object for given colour and this colour impl - * - * **Important:** - * the guard starts disengaged, and has to be engaged explicitly. - */ - ColourGuard guardColour( Colour::Code colourCode ); - - private: - virtual void use( Colour::Code colourCode ) const = 0; - }; - - //! Provides ColourImpl based on global config and target compilation platform - Detail::unique_ptr makeColourImpl( ColourMode colourSelection, - IStream* stream ); - - //! Checks if specific colour impl has been compiled into the binary - bool isColourImplAvailable( ColourMode colourSelection ); - -} // end namespace Catch - -#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED - #include #include #include @@ -4387,17 +4254,16 @@ namespace Catch { enum class TokenType { Option, Argument }; struct Token { TokenType type; - std::string token; + StringRef token; }; // Abstracts iterators into args as a stream of tokens, with option // arguments uniformly handled class TokenStream { - using Iterator = std::vector::const_iterator; + using Iterator = std::vector::const_iterator; Iterator it; Iterator itEnd; std::vector m_tokenBuffer; - void loadBuffer(); public: @@ -4449,12 +4315,17 @@ namespace Catch { ResultType m_type; }; - template class ResultValueBase : public ResultBase { + template + class ResultValueBase : public ResultBase { public: - auto value() const -> T const& { + T const& value() const& { enforceOk(); return m_value; } + T&& value() && { + enforceOk(); + return CATCH_MOVE( m_value ); + } protected: ResultValueBase( ResultType type ): ResultBase( type ) {} @@ -4464,13 +4335,23 @@ namespace Catch { if ( m_type == ResultType::Ok ) new ( &m_value ) T( other.m_value ); } - - ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) { - new ( &m_value ) T( value ); + ResultValueBase( ResultValueBase&& other ): + ResultBase( other ) { + if ( m_type == ResultType::Ok ) + new ( &m_value ) T( CATCH_MOVE(other.m_value) ); } - auto operator=( ResultValueBase const& other ) - -> ResultValueBase& { + + ResultValueBase( ResultType, T const& value ): + ResultBase( ResultType::Ok ) { + new ( &m_value ) T( value ); + } + ResultValueBase( ResultType, T&& value ): + ResultBase( ResultType::Ok ) { + new ( &m_value ) T( CATCH_MOVE(value) ); + } + + ResultValueBase& operator=( ResultValueBase const& other ) { if ( m_type == ResultType::Ok ) m_value.~T(); ResultBase::operator=( other ); @@ -4478,6 +4359,14 @@ namespace Catch { new ( &m_value ) T( other.m_value ); return *this; } + ResultValueBase& operator=( ResultValueBase&& other ) { + if ( m_type == ResultType::Ok ) m_value.~T(); + ResultBase::operator=( other ); + if ( m_type == ResultType::Ok ) + new ( &m_value ) T( CATCH_MOVE(other.m_value) ); + return *this; + } + ~ResultValueBase() override { if ( m_type == ResultType::Ok ) @@ -4505,8 +4394,8 @@ namespace Catch { } template - static auto ok( U const& value ) -> BasicResult { - return { ResultType::Ok, value }; + static auto ok( U&& value ) -> BasicResult { + return { ResultType::Ok, CATCH_FORWARD(value) }; } static auto ok() -> BasicResult { return { ResultType::Ok }; } static auto logicError( std::string&& message ) @@ -4553,12 +4442,15 @@ namespace Catch { class ParseState { public: ParseState( ParseResultType type, - TokenStream const& remainingTokens ); + TokenStream remainingTokens ); ParseResultType type() const { return m_type; } - TokenStream const& remainingTokens() const { + TokenStream const& remainingTokens() const& { return m_remainingTokens; } + TokenStream&& remainingTokens() && { + return CATCH_MOVE( m_remainingTokens ); + } private: ParseResultType m_type; @@ -4571,7 +4463,7 @@ namespace Catch { struct HelpColumns { std::string left; - std::string right; + StringRef descriptions; }; template @@ -4731,7 +4623,7 @@ namespace Catch { virtual ~ParserBase() = default; virtual auto validate() const -> Result { return Result::ok(); } virtual auto parse( std::string const& exeName, - TokenStream const& tokens ) const + TokenStream tokens ) const -> InternalParseResult = 0; virtual size_t cardinality() const; @@ -4751,8 +4643,8 @@ namespace Catch { protected: Optionality m_optionality = Optionality::Optional; std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; + StringRef m_hint; + StringRef m_description; explicit ParserRefImpl( std::shared_ptr const& ref ): m_ref( ref ) {} @@ -4761,28 +4653,32 @@ namespace Catch { template ParserRefImpl( accept_many_t, LambdaT const& ref, - std::string const& hint ): + StringRef hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} template ::value>> - ParserRefImpl( T& ref, std::string const& hint ): + ParserRefImpl( T& ref, StringRef hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} template ::value>> - ParserRefImpl( LambdaT const& ref, std::string const& hint ): + ParserRefImpl( LambdaT const& ref, StringRef hint ): m_ref( std::make_shared>( ref ) ), m_hint( hint ) {} - auto operator()( std::string const& description ) -> DerivedT& { + DerivedT& operator()( StringRef description ) & { m_description = description; return static_cast( *this ); } + DerivedT&& operator()( StringRef description ) && { + m_description = description; + return static_cast( *this ); + } auto optional() -> DerivedT& { m_optionality = Optionality::Optional; @@ -4805,7 +4701,7 @@ namespace Catch { return 1; } - std::string const& hint() const { return m_hint; } + StringRef hint() const { return m_hint; } }; } // namespace detail @@ -4819,13 +4715,13 @@ namespace Catch { Detail::InternalParseResult parse(std::string const&, - Detail::TokenStream const& tokens) const override; + Detail::TokenStream tokens) const override; }; // A parser for options class Opt : public Detail::ParserRefImpl { protected: - std::vector m_optNames; + std::vector m_optNames; public: template @@ -4838,33 +4734,37 @@ namespace Catch { template ::value>> - Opt( LambdaT const& ref, std::string const& hint ): + Opt( LambdaT const& ref, StringRef hint ): ParserRefImpl( ref, hint ) {} template - Opt( accept_many_t, LambdaT const& ref, std::string const& hint ): + Opt( accept_many_t, LambdaT const& ref, StringRef hint ): ParserRefImpl( accept_many, ref, hint ) {} template ::value>> - Opt( T& ref, std::string const& hint ): + Opt( T& ref, StringRef hint ): ParserRefImpl( ref, hint ) {} - auto operator[](std::string const& optName) -> Opt& { + Opt& operator[]( StringRef optName ) & { m_optNames.push_back(optName); return *this; } + Opt&& operator[]( StringRef optName ) && { + m_optNames.push_back( optName ); + return CATCH_MOVE(*this); + } - std::vector getHelpColumns() const; + Detail::HelpColumns getHelpColumns() const; - bool isMatch(std::string const& optToken) const; + bool isMatch(StringRef optToken) const; using ParserBase::parse; Detail::InternalParseResult parse(std::string const&, - Detail::TokenStream const& tokens) const override; + Detail::TokenStream tokens) const override; Detail::Result validate() const override; }; @@ -4887,7 +4787,7 @@ namespace Catch { // handled specially Detail::InternalParseResult parse(std::string const&, - Detail::TokenStream const& tokens) const override; + Detail::TokenStream tokens) const override; std::string const& name() const { return *m_name; } Detail::ParserResult set(std::string const& newName); @@ -4912,16 +4812,26 @@ namespace Catch { return *this; } - auto operator|=(Opt const& opt) -> Parser& { - m_options.push_back(opt); - return *this; + friend Parser& operator|=( Parser& p, Opt const& opt ) { + p.m_options.push_back( opt ); + return p; + } + friend Parser& operator|=( Parser& p, Opt&& opt ) { + p.m_options.push_back( CATCH_MOVE(opt) ); + return p; } Parser& operator|=(Parser const& other); template - auto operator|(T const& other) const -> Parser { - return Parser(*this) |= other; + friend Parser operator|( Parser const& p, T&& rhs ) { + return Parser( p ) |= CATCH_FORWARD(rhs); + } + + template + friend Parser operator|( Parser&& p, T&& rhs ) { + p |= CATCH_FORWARD(rhs); + return CATCH_MOVE(p); } std::vector getHelpColumns() const; @@ -4939,21 +4849,23 @@ namespace Catch { using ParserBase::parse; Detail::InternalParseResult parse(std::string const& exeName, - Detail::TokenStream const& tokens) const override; + Detail::TokenStream tokens) const override; }; - // Transport for raw args (copied from main args, or supplied via - // init list for testing) + /** + * Wrapper over argc + argv, assumes that the inputs outlive it + */ class Args { friend Detail::TokenStream; - std::string m_exeName; - std::vector m_args; + StringRef m_exeName; + std::vector m_args; public: Args(int argc, char const* const* argv); - Args(std::initializer_list args); + // Helper constructor for testing + Args(std::initializer_list args); - std::string const& exeName() const { return m_exeName; } + StringRef exeName() const { return m_exeName; } }; @@ -6997,6 +6909,7 @@ namespace Catch { }; class ITestInvoker; + struct NameAndTags; enum class TestCaseProperties : uint8_t { None = 0, @@ -7233,7 +7146,7 @@ namespace Catch { #define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MINOR 5 -#define CATCH_VERSION_PATCH 0 +#define CATCH_VERSION_PATCH 1 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED @@ -8133,12 +8046,12 @@ class uniform_integer_distribution { using UnsignedIntegerType = Detail::make_unsigned_t; - // We store the left range bound converted to internal representation, - // because it will be used in computation in the () operator. + // Only the left bound is stored, and we store it converted to its + // unsigned image. This avoids having to do the conversions inside + // the operator(), at the cost of having to do the conversion in + // the a() getter. The right bound is only needed in the b() getter, + // so we recompute it there from other stored data. UnsignedIntegerType m_a; - // After initialization, right bound is only used for the b() getter, - // so we keep it in the original type. - IntegerType m_b; // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type. UnsignedIntegerType m_ab_distance; @@ -8151,11 +8064,10 @@ class uniform_integer_distribution { // distribution will be reused many times and this is an optimization. UnsignedIntegerType m_rejection_threshold = 0; - // Assumes m_b and m_a are already filled - UnsignedIntegerType computeDistance() const { - // This overflows and returns 0 if ua == 0 and ub == TYPE_MAX. + UnsignedIntegerType computeDistance(IntegerType a, IntegerType b) const { + // This overflows and returns 0 if a == 0 and b == TYPE_MAX. // We handle that later when generating the number. - return transposeTo(m_b) - m_a + 1; + return transposeTo(b) - transposeTo(a) + 1; } static UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) { @@ -8179,8 +8091,7 @@ public: uniform_integer_distribution( IntegerType a, IntegerType b ): m_a( transposeTo(a) ), - m_b( b ), - m_ab_distance( computeDistance() ), + m_ab_distance( computeDistance(a, b) ), m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) { assert( a <= b ); } @@ -8205,7 +8116,7 @@ public: } result_type a() const { return transposeBack(m_a); } - result_type b() const { return m_b; } + result_type b() const { return transposeBack(m_ab_distance + m_a - 1); } }; } // end namespace Catch @@ -9065,6 +8976,141 @@ namespace Catch { #endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED +#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED +#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED + + +#include +#include + +namespace Catch { + + enum class ColourMode : std::uint8_t; + class IStream; + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, + + // By intention + FileName = LightGrey, + Warning = BrightYellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + Skip = LightGrey, + + OriginalExpression = Cyan, + ReconstructedExpression = BrightYellow, + + SecondaryText = LightGrey, + Headers = White + }; + }; + + class ColourImpl { + protected: + //! The associated stream of this ColourImpl instance + IStream* m_stream; + public: + ColourImpl( IStream* stream ): m_stream( stream ) {} + + //! RAII wrapper around writing specific colour of text using specific + //! colour impl into a stream. + class ColourGuard { + ColourImpl const* m_colourImpl; + Colour::Code m_code; + bool m_engaged = false; + + public: + //! Does **not** engage the guard/start the colour + ColourGuard( Colour::Code code, + ColourImpl const* colour ); + + ColourGuard( ColourGuard const& rhs ) = delete; + ColourGuard& operator=( ColourGuard const& rhs ) = delete; + + ColourGuard( ColourGuard&& rhs ) noexcept; + ColourGuard& operator=( ColourGuard&& rhs ) noexcept; + + //! Removes colour _if_ the guard was engaged + ~ColourGuard(); + + /** + * Explicitly engages colour for given stream. + * + * The API based on operator<< should be preferred. + */ + ColourGuard& engage( std::ostream& stream ) &; + /** + * Explicitly engages colour for given stream. + * + * The API based on operator<< should be preferred. + */ + ColourGuard&& engage( std::ostream& stream ) &&; + + private: + //! Engages the guard and starts using colour + friend std::ostream& operator<<( std::ostream& lhs, + ColourGuard& guard ) { + guard.engageImpl( lhs ); + return lhs; + } + //! Engages the guard and starts using colour + friend std::ostream& operator<<( std::ostream& lhs, + ColourGuard&& guard) { + guard.engageImpl( lhs ); + return lhs; + } + + void engageImpl( std::ostream& stream ); + + }; + + virtual ~ColourImpl(); // = default + /** + * Creates a guard object for given colour and this colour impl + * + * **Important:** + * the guard starts disengaged, and has to be engaged explicitly. + */ + ColourGuard guardColour( Colour::Code colourCode ); + + private: + virtual void use( Colour::Code colourCode ) const = 0; + }; + + //! Provides ColourImpl based on global config and target compilation platform + Detail::unique_ptr makeColourImpl( ColourMode colourSelection, + IStream* stream ); + + //! Checks if specific colour impl has been compiled into the binary + bool isColourImplAvailable( ColourMode colourSelection ); + +} // end namespace Catch + +#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED + + #ifndef CATCH_CONSOLE_WIDTH_HPP_INCLUDED #define CATCH_CONSOLE_WIDTH_HPP_INCLUDED @@ -9340,7 +9386,6 @@ namespace Catch { #ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED #define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED - #include namespace Catch { @@ -10421,7 +10466,7 @@ namespace Catch { #ifndef CATCH_SHARDING_HPP_INCLUDED #define CATCH_SHARDING_HPP_INCLUDED - +#include #include #include @@ -10769,6 +10814,7 @@ namespace Catch { #ifndef CATCH_TEXTFLOW_HPP_INCLUDED #define CATCH_TEXTFLOW_HPP_INCLUDED + #include #include #include @@ -10797,7 +10843,7 @@ namespace Catch { public: /** - * Iterates "lines" in `Column` and return sthem + * Iterates "lines" in `Column` and returns them */ class const_iterator { friend Column; @@ -10851,20 +10897,35 @@ namespace Catch { using iterator = const_iterator; explicit Column( std::string const& text ): m_string( text ) {} + explicit Column( std::string&& text ): + m_string( CATCH_MOVE(text)) {} - Column& width( size_t newWidth ) { + Column& width( size_t newWidth ) & { assert( newWidth > 0 ); m_width = newWidth; return *this; } - Column& indent( size_t newIndent ) { + Column&& width( size_t newWidth ) && { + assert( newWidth > 0 ); + m_width = newWidth; + return CATCH_MOVE( *this ); + } + Column& indent( size_t newIndent ) & { m_indent = newIndent; return *this; } - Column& initialIndent( size_t newIndent ) { + Column&& indent( size_t newIndent ) && { + m_indent = newIndent; + return CATCH_MOVE( *this ); + } + Column& initialIndent( size_t newIndent ) & { m_initialIndent = newIndent; return *this; } + Column&& initialIndent( size_t newIndent ) && { + m_initialIndent = newIndent; + return CATCH_MOVE( *this ); + } size_t width() const { return m_width; } const_iterator begin() const { return const_iterator( *this ); } @@ -10873,7 +10934,8 @@ namespace Catch { friend std::ostream& operator<<( std::ostream& os, Column const& col ); - Columns operator+( Column const& other ); + friend Columns operator+( Column const& lhs, Column const& rhs ); + friend Columns operator+( Column&& lhs, Column&& rhs ); }; //! Creates a column that serves as an empty space of specific width @@ -10917,8 +10979,10 @@ namespace Catch { iterator begin() const { return iterator( *this ); } iterator end() const { return { *this, iterator::EndTag() }; } - Columns& operator+=( Column const& col ); - Columns operator+( Column const& col ); + friend Columns& operator+=( Columns& lhs, Column const& rhs ); + friend Columns& operator+=( Columns& lhs, Column&& rhs ); + friend Columns operator+( Columns const& lhs, Column const& rhs ); + friend Columns operator+( Columns&& lhs, Column&& rhs ); friend std::ostream& operator<<( std::ostream& os, Columns const& cols ); diff --git a/meson.build b/meson.build index 1c5b80a1..75cb4183 100644 --- a/meson.build +++ b/meson.build @@ -8,7 +8,7 @@ project( 'catch2', 'cpp', - version: '3.5.0', # CML version placeholder, don't delete + version: '3.5.1', # CML version placeholder, don't delete license: 'BSL-1.0', meson_version: '>=0.54.1', ) diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp index dbf8b4b2..c56fb806 100644 --- a/src/catch2/catch_version.cpp +++ b/src/catch2/catch_version.cpp @@ -36,7 +36,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 3, 5, 0, "", 0 ); + static Version version( 3, 5, 1, "", 0 ); return version; } diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp index fbe1188c..6f41667c 100644 --- a/src/catch2/catch_version_macros.hpp +++ b/src/catch2/catch_version_macros.hpp @@ -10,6 +10,6 @@ #define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MINOR 5 -#define CATCH_VERSION_PATCH 0 +#define CATCH_VERSION_PATCH 1 #endif // CATCH_VERSION_MACROS_HPP_INCLUDED