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