diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38d2b47e61..6d381d8de4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,7 +31,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
- VERSION 3.3.1 # CML version placeholder, don't delete
+ VERSION 3.3.2 # 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/matchers.md b/docs/matchers.md
index d2a2f3c17d..14c1589821 100644
--- a/docs/matchers.md
+++ b/docs/matchers.md
@@ -151,7 +151,7 @@ are:
> `WithinRel` matcher was introduced in Catch2 2.10.0
-> `IsNaN` matcher was introduced in Catch2 X.Y.Z.
+> `IsNaN` matcher was introduced in Catch2 3.3.2.
The first three serve to compare two floating pointe numbers. For more
details about how they work, read [the docs on comparing floating point
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 3c46cb5732..1fa37da432 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -2,6 +2,7 @@
# Release notes
**Contents**
+[3.3.2](#332)
[3.3.1](#331)
[3.3.0](#330)
[3.2.1](#321)
@@ -56,6 +57,29 @@
+## 3.3.2
+
+### Improvements
+* Further reduced allocations
+ * The compact, console, TAP and XML reporters perform less allocations in various cases
+ * Removed 1 allocation per entered `SECTION`/`TEST_CASE`.
+ * Removed 2 allocations per test case exit, if stdout/stderr is captured
+* Improved performance
+ * Section tracking is 10%-25% faster than in v3.3.0
+ * Assertion handling is 5%-10% faster than in v3.3.0
+ * Test case registration is 1%-2% faster than in v3.3.0
+ * Tiny speedup for registering listeners
+ * Tiny speedup for `CAPTURE`, `TEST_CASE_METHOD`, `METHOD_AS_TEST_CASE`, and `TEMPLATE_LIST_TEST_*` macros.
+* `Contains`, `RangeEquals` and `UnorderedRangeEquals` matchers now support ranges with iterator + sentinel pair
+* Added `IsNaN` matcher
+ * Unlike `REQUIRE(isnan(x))`, `REQUIRE_THAT(x, IsNaN())` shows you the value of `x`.
+* Suppressed `declared_but_not_referenced` warning for NVHPC (#2637)
+
+### Fixes
+* Fixed performance regression in section tracking introduced in v3.3.1
+ * Extreme cases would cause the tracking to run about 4x slower than in 3.3.0
+
+
## 3.3.1
### Improvements
@@ -65,7 +89,6 @@
* The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s
-
## 3.3.0
### Improvements
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index 0e12bd1438..a81b1b6ae5 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.3.1
-// Generated: 2023-01-29 22:55:05.183536
+// Catch v3.3.2
+// Generated: 2023-02-26 10:28:48.270752
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -469,16 +469,15 @@ namespace Catch {
}
std::string AssertionResult::getExpressionInMacro() const {
- std::string expr;
- if( m_info.macroName.empty() )
- expr = static_cast(m_info.capturedExpression);
- else {
- expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
- expr += m_info.macroName;
- expr += "( ";
- expr += m_info.capturedExpression;
- expr += " )";
+ if ( m_info.macroName.empty() ) {
+ return static_cast( m_info.capturedExpression );
}
+ std::string expr;
+ expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
+ expr += m_info.macroName;
+ expr += "( ";
+ expr += m_info.capturedExpression;
+ expr += " )";
return expr;
}
@@ -2022,7 +2021,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 3, 1, "", 0 );
+ static Version version( 3, 3, 2, "", 0 );
return version;
}
@@ -2198,13 +2197,13 @@ namespace Catch {
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
- std::string const& _stdOut,
- std::string const& _stdErr,
+ std::string&& _stdOut,
+ std::string&& _stdErr,
bool _aborting )
: testInfo( &_testInfo ),
totals( _totals ),
- stdOut( _stdOut ),
- stdErr( _stdErr ),
+ stdOut( CATCH_MOVE(_stdOut) ),
+ stdErr( CATCH_MOVE(_stdErr) ),
aborting( _aborting )
{}
@@ -4997,7 +4996,7 @@ namespace Catch {
{}
~GeneratorTracker() override;
- static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef nameAndLocation ) {
+ static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) {
GeneratorTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
@@ -5139,13 +5138,8 @@ namespace Catch {
Totals RunContext::runTest(TestCaseHandle const& testCase) {
const Totals prevTotals = m_totals;
- std::string redirectedCout;
- std::string redirectedCerr;
-
auto const& testInfo = testCase.getTestCaseInfo();
-
m_reporter->testCaseStarting(testInfo);
-
m_activeTestCase = &testCase;
@@ -5187,6 +5181,8 @@ namespace Catch {
seedRng( *m_config );
uint64_t testRuns = 0;
+ std::string redirectedCout;
+ std::string redirectedCerr;
do {
m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
@@ -5200,7 +5196,7 @@ namespace Catch {
redirectedCerr += oneRunCerr;
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
- auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting());
+ auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
++testRuns;
@@ -5215,8 +5211,8 @@ namespace Catch {
m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals,
- redirectedCout,
- redirectedCerr,
+ CATCH_MOVE(redirectedCout),
+ CATCH_MOVE(redirectedCerr),
aborting()));
m_activeTestCase = nullptr;
@@ -5605,10 +5601,11 @@ namespace Catch {
void RunContext::handleIncomplete(
AssertionInfo const& info
) {
+ using namespace std::string_literals;
m_lastAssertionInfo = info;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
- data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+ data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
}
@@ -5663,7 +5660,7 @@ namespace Catch {
Section::Section( SourceLineInfo const& _lineInfo,
StringRef _name,
const char* const ):
- m_info( { "invalid", static_cast(-1) }, "" ),
+ m_info( { "invalid", static_cast( -1 ) }, std::string{} ),
m_sectionIncluded(
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
// We delay initialization the SectionInfo member until we know
@@ -5900,10 +5897,6 @@ namespace Catch {
: StringRef( rawChars, std::strlen(rawChars) )
{}
- auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
- return m_size == other.m_size
- && (std::memcmp( m_start, other.m_start, m_size ) == 0);
- }
bool StringRef::operator<(StringRef rhs) const noexcept {
if (m_size < rhs.m_size) {
@@ -6195,12 +6188,17 @@ namespace TestCaseTracking {
m_children.push_back( CATCH_MOVE(child) );
}
- ITracker* ITracker::findChild( NameAndLocationRef nameAndLocation ) {
+ ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
auto it = std::find_if(
m_children.begin(),
m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ) {
- return tracker->nameAndLocation() == nameAndLocation;
+ auto const& tnameAndLoc = tracker->nameAndLocation();
+ if ( tnameAndLoc.location.line !=
+ nameAndLocation.location.line ) {
+ return false;
+ }
+ return tnameAndLoc == nameAndLocation;
} );
return ( it != m_children.end() ) ? it->get() : nullptr;
}
@@ -6208,10 +6206,6 @@ namespace TestCaseTracking {
bool ITracker::isSectionTracker() const { return false; }
bool ITracker::isGeneratorTracker() const { return false; }
- bool ITracker::isSuccessfullyCompleted() const {
- return m_runState == CompletedSuccessfully;
- }
-
bool ITracker::isOpen() const {
return m_runState != NotStarted && !isComplete();
}
@@ -6238,16 +6232,6 @@ namespace TestCaseTracking {
return *m_rootTracker;
}
- void TrackerContext::endRun() {
- m_rootTracker.reset();
- m_currentTracker = nullptr;
- m_runState = NotStarted;
- }
-
- void TrackerContext::startCycle() {
- m_currentTracker = m_rootTracker.get();
- m_runState = Executing;
- }
void TrackerContext::completeCycle() {
m_runState = CompletedCycle;
}
@@ -6255,9 +6239,6 @@ namespace TestCaseTracking {
bool TrackerContext::completedCycle() const {
return m_runState == CompletedCycle;
}
- ITracker& TrackerContext::currentTracker() {
- return *m_currentTracker;
- }
void TrackerContext::setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker;
}
@@ -6326,7 +6307,7 @@ namespace TestCaseTracking {
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
- m_trimmed_name(trim(ITracker::nameAndLocation().name))
+ m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
{
if( parent ) {
while ( !parent->isSectionTracker() ) {
@@ -6351,7 +6332,7 @@ namespace TestCaseTracking {
bool SectionTracker::isSectionTracker() const { return true; }
- SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation ) {
+ SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
SectionTracker* tracker;
ITracker& currentTracker = ctx.currentTracker();
@@ -6395,10 +6376,6 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
- std::vector const& SectionTracker::getFilters() const {
- return m_filters;
- }
-
StringRef SectionTracker::trimmedName() const {
return m_trimmed_name;
}
@@ -6697,10 +6674,8 @@ namespace Catch {
token.erase(token.begin());
if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(".", m_substring));
- m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring));
} else {
m_currentFilter.m_required.emplace_back(Detail::make_unique(".", m_substring));
- m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring));
}
}
if (m_exclusion) {
@@ -7643,7 +7618,19 @@ WithinRelMatcher WithinRel(float target) {
}
-} // namespace Matchers
+
+bool IsNaNMatcher::match( double const& matchee ) const {
+ return std::isnan( matchee );
+}
+
+std::string IsNaNMatcher::describe() const {
+ using namespace std::string_literals;
+ return "is NaN"s;
+}
+
+IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
+
+ } // namespace Matchers
} // namespace Catch
@@ -8080,7 +8067,7 @@ class AssertionPrinter {
private:
std::ostream& stream;
AssertionResult const& result;
- std::vector messages;
+ std::vector const& messages;
std::vector::const_iterator itMessage;
bool printInfoMessages;
ColourImpl* colourImpl;
@@ -8174,7 +8161,6 @@ class ConsoleAssertionPrinter {
stats(_stats),
result(_stats.assertionResult),
colour(Colour::None),
- message(result.getMessage()),
messages(_stats.infoMessages),
colourImpl(colourImpl_),
printInfoMessages(_printInfoMessages) {
@@ -8183,10 +8169,10 @@ class ConsoleAssertionPrinter {
colour = Colour::Success;
passOrFail = "PASSED"_sr;
//if( result.hasMessage() )
- if (_stats.infoMessages.size() == 1)
- messageLabel = "with message";
- if (_stats.infoMessages.size() > 1)
- messageLabel = "with messages";
+ if (messages.size() == 1)
+ messageLabel = "with message"_sr;
+ if (messages.size() > 1)
+ messageLabel = "with messages"_sr;
break;
case ResultWas::ExpressionFailed:
if (result.isOk()) {
@@ -8196,51 +8182,57 @@ class ConsoleAssertionPrinter {
colour = Colour::Error;
passOrFail = "FAILED"_sr;
}
- if (_stats.infoMessages.size() == 1)
- messageLabel = "with message";
- if (_stats.infoMessages.size() > 1)
- messageLabel = "with messages";
+ if (messages.size() == 1)
+ messageLabel = "with message"_sr;
+ if (messages.size() > 1)
+ messageLabel = "with messages"_sr;
break;
case ResultWas::ThrewException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
- messageLabel = "due to unexpected exception with ";
- if (_stats.infoMessages.size() == 1)
- messageLabel += "message";
- if (_stats.infoMessages.size() > 1)
- messageLabel += "messages";
+ // todo switch
+ switch (messages.size()) { case 0:
+ messageLabel = "due to unexpected exception with "_sr;
+ break;
+ case 1:
+ messageLabel = "due to unexpected exception with message"_sr;
+ break;
+ default:
+ messageLabel = "due to unexpected exception with messages"_sr;
+ break;
+ }
break;
case ResultWas::FatalErrorCondition:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
- messageLabel = "due to a fatal error condition";
+ messageLabel = "due to a fatal error condition"_sr;
break;
case ResultWas::DidntThrowException:
colour = Colour::Error;
passOrFail = "FAILED"_sr;
- messageLabel = "because no exception was thrown where one was expected";
+ messageLabel = "because no exception was thrown where one was expected"_sr;
break;
case ResultWas::Info:
- messageLabel = "info";
+ messageLabel = "info"_sr;
break;
case ResultWas::Warning:
- messageLabel = "warning";
+ messageLabel = "warning"_sr;
break;
case ResultWas::ExplicitFailure:
passOrFail = "FAILED"_sr;
colour = Colour::Error;
- if (_stats.infoMessages.size() == 1)
- messageLabel = "explicitly with message";
- if (_stats.infoMessages.size() > 1)
- messageLabel = "explicitly with messages";
+ if (messages.size() == 1)
+ messageLabel = "explicitly with message"_sr;
+ if (messages.size() > 1)
+ messageLabel = "explicitly with messages"_sr;
break;
case ResultWas::ExplicitSkip:
colour = Colour::Skip;
passOrFail = "SKIPPED"_sr;
- if (_stats.infoMessages.size() == 1)
- messageLabel = "explicitly with message";
- if (_stats.infoMessages.size() > 1)
- messageLabel = "explicitly with messages";
+ if (messages.size() == 1)
+ messageLabel = "explicitly with message"_sr;
+ if (messages.size() > 1)
+ messageLabel = "explicitly with messages"_sr;
break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
@@ -8304,9 +8296,8 @@ class ConsoleAssertionPrinter {
AssertionResult const& result;
Colour::Code colour;
StringRef passOrFail;
- std::string messageLabel;
- std::string message;
- std::vector messages;
+ StringRef messageLabel;
+ std::vector const& messages;
ColourImpl* colourImpl;
bool printInfoMessages;
};
@@ -10133,7 +10124,7 @@ namespace Catch {
private:
std::ostream& stream;
AssertionResult const& result;
- std::vector messages;
+ std::vector const& messages;
std::vector::const_iterator itMessage;
bool printInfoMessages;
std::size_t counter;
@@ -10396,7 +10387,7 @@ namespace Catch {
void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" )
- .writeAttribute( "name"_sr, trim( testInfo.name ) )
+ .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
.writeAttribute( "tags"_sr, testInfo.tagsAsString() );
writeSourceInfo( testInfo.lineInfo );
@@ -10410,7 +10401,7 @@ namespace Catch {
StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" )
- .writeAttribute( "name"_sr, trim( sectionInfo.name ) );
+ .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
writeSourceInfo( sectionInfo.lineInfo );
m_xml.ensureTagClosed();
}
@@ -10524,11 +10515,10 @@ namespace Catch {
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
-
if( !testCaseStats.stdOut.empty() )
- m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );
+ m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
if( !testCaseStats.stdErr.empty() )
- m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );
+ m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
m_xml.endElement();
}
diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp
index 88f2dd912c..321cec5dac 100644
--- a/extras/catch_amalgamated.hpp
+++ b/extras/catch_amalgamated.hpp
@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.3.1
-// Generated: 2023-01-29 22:55:03.856079
+// Catch v3.3.2
+// Generated: 2023-02-26 10:28:46.785908
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -95,6 +95,8 @@ namespace Catch {
#include
#include
+#include
+
namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view)
@@ -131,7 +133,10 @@ namespace Catch {
}
public: // operators
- auto operator == ( StringRef other ) const noexcept -> bool;
+ auto operator == ( StringRef other ) const noexcept -> bool {
+ return m_size == other.m_size
+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
+ }
auto operator != (StringRef other) const noexcept -> bool {
return !(*this == other);
}
@@ -352,7 +357,7 @@ namespace Catch {
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -371,6 +376,12 @@ namespace Catch {
#endif
+#if defined(__NVCOMPILER)
+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
+#endif
+
#if defined(__CUDACC__) && !defined(__clang__)
# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
// New pragmas introduced in CUDA 11.5+
@@ -1434,8 +1445,8 @@ namespace Catch {
struct TestCaseStats {
TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals,
- std::string const& _stdOut,
- std::string const& _stdErr,
+ std::string&& _stdOut,
+ std::string&& _stdErr,
bool _aborting );
TestCaseInfo const * testInfo;
@@ -4518,7 +4529,10 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
- Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+ Catch::Capturer varName( macroName##_catch_sr, \
+ CATCH_INTERNAL_LINEINFO, \
+ Catch::ResultWas::Info, \
+ #__VA_ARGS__##_catch_sr ); \
varName.captureValues( 0, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
@@ -5904,9 +5918,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
- #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
+ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else
- #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
+ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
@@ -6233,7 +6247,13 @@ struct AutoReg : Detail::NonCopyable {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
- namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+ namespace { \
+ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
+ Catch::makeTestInvoker( &QualifiedMethod ), \
+ CATCH_INTERNAL_LINEINFO, \
+ "&" #QualifiedMethod##_catch_sr, \
+ Catch::NameAndTags{ __VA_ARGS__ } ); \
+ } /* NOLINT */ \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
///////////////////////////////////////////////////////////////////////////////
@@ -6245,7 +6265,11 @@ struct AutoReg : Detail::NonCopyable {
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \
}; \
- const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
+ Catch::makeTestInvoker( &TestName::test ), \
+ CATCH_INTERNAL_LINEINFO, \
+ #ClassName##_catch_sr, \
+ Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
@@ -6878,7 +6902,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests() { \
size_t index = 0; \
using expander = size_t[]; \
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
} \
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
@@ -7013,7 +7037,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests(){\
size_t index = 0;\
using expander = size_t[];\
- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
@@ -7402,7 +7426,7 @@ namespace Catch {
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7754,16 +7778,19 @@ namespace Detail {
} // namespace Generators
} // namespace Catch
+#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
+#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
+
#define GENERATE( ... ) \
- Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \
- Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \
- Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
CATCH_INTERNAL_LINEINFO, \
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
@@ -8919,6 +8946,139 @@ namespace Detail {
#endif // CATCH_GETENV_HPP_INCLUDED
+#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
+#define CATCH_IS_PERMUTATION_HPP_INCLUDED
+
+#include
+#include
+
+namespace Catch {
+ namespace Detail {
+
+ template
+ ForwardIter find_sentinel( ForwardIter start,
+ Sentinel sentinel,
+ T const& value,
+ Comparator cmp ) {
+ while ( start != sentinel ) {
+ if ( cmp( *start, value ) ) { break; }
+ ++start;
+ }
+ return start;
+ }
+
+ template
+ std::ptrdiff_t count_sentinel( ForwardIter start,
+ Sentinel sentinel,
+ T const& value,
+ Comparator cmp ) {
+ std::ptrdiff_t count = 0;
+ while ( start != sentinel ) {
+ if ( cmp( *start, value ) ) { ++count; }
+ ++start;
+ }
+ return count;
+ }
+
+ template
+ std::enable_if_t::value,
+ std::ptrdiff_t>
+ sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
+ std::ptrdiff_t dist = 0;
+ while ( iter != sentinel ) {
+ ++iter;
+ ++dist;
+ }
+ return dist;
+ }
+
+ template
+ std::ptrdiff_t sentinel_distance( ForwardIter first,
+ ForwardIter last ) {
+ return std::distance( first, last );
+ }
+
+ template
+ bool check_element_counts( ForwardIter1 first_1,
+ const Sentinel1 end_1,
+ ForwardIter2 first_2,
+ const Sentinel2 end_2,
+ Comparator cmp ) {
+ auto cursor = first_1;
+ while ( cursor != end_1 ) {
+ if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
+ cursor ) {
+ // we haven't checked this element yet
+ const auto count_in_range_2 =
+ count_sentinel( first_2, end_2, *cursor, cmp );
+ // Not a single instance in 2nd range, so it cannot be a
+ // permutation of 1st range
+ if ( count_in_range_2 == 0 ) { return false; }
+
+ const auto count_in_range_1 =
+ count_sentinel( cursor, end_1, *cursor, cmp );
+ if ( count_in_range_1 != count_in_range_2 ) {
+ return false;
+ }
+ }
+
+ ++cursor;
+ }
+
+ return true;
+ }
+
+ template
+ bool is_permutation( ForwardIter1 first_1,
+ const Sentinel1 end_1,
+ ForwardIter2 first_2,
+ const Sentinel2 end_2,
+ Comparator cmp ) {
+ // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
+ // TODO: Comparator has to be "both sides", e.g. a == b => b == a
+ // This skips shared prefix of the two ranges
+ while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
+ ++first_1;
+ ++first_2;
+ }
+
+ // We need to handle case where at least one of the ranges has no more elements
+ if (first_1 == end_1 || first_2 == end_2) {
+ return first_1 == end_1 && first_2 == end_2;
+ }
+
+ // pair counting is n**2, so we pay linear walk to compare the sizes first
+ auto dist_1 = sentinel_distance( first_1, end_1 );
+ auto dist_2 = sentinel_distance( first_2, end_2 );
+
+ if (dist_1 != dist_2) { return false; }
+
+ // Since we do not try to handle stronger iterators pair (e.g.
+ // bidir) optimally, the only thing left to do is to check counts in
+ // the remaining ranges.
+ return check_element_counts( first_1, end_1, first_2, end_2, cmp );
+ }
+
+ } // namespace Detail
+} // namespace Catch
+
+#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
+
+
#ifndef CATCH_ISTREAM_HPP_INCLUDED
#define CATCH_ISTREAM_HPP_INCLUDED
@@ -9199,8 +9359,12 @@ namespace TestCaseTracking {
NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
- return lhs.name == rhs.name
- && lhs.location == rhs.location;
+ // This is a very cheap check that should have a very high hit rate.
+ // If we get to SourceLineInfo::operator==, we will redo it, but the
+ // cost of repeating is trivial at that point (we will be paying
+ // multiple strcmp/memcmps at that point).
+ if ( lhs.location.line != rhs.location.line ) { return false; }
+ return lhs.name == rhs.name && lhs.location == rhs.location;
}
friend bool operator!=(NameAndLocation const& lhs,
NameAndLocation const& rhs) {
@@ -9224,11 +9388,16 @@ namespace TestCaseTracking {
name( name_ ), location( location_ ) {}
friend bool operator==( NameAndLocation const& lhs,
- NameAndLocationRef rhs ) {
+ NameAndLocationRef const& rhs ) {
+ // This is a very cheap check that should have a very high hit rate.
+ // If we get to SourceLineInfo::operator==, we will redo it, but the
+ // cost of repeating is trivial at that point (we will be paying
+ // multiple strcmp/memcmps at that point).
+ if ( lhs.location.line != rhs.location.line ) { return false; }
return StringRef( lhs.name ) == rhs.name &&
lhs.location == rhs.location;
}
- friend bool operator==( NameAndLocationRef lhs,
+ friend bool operator==( NameAndLocationRef const& lhs,
NameAndLocation const& rhs ) {
return rhs == lhs;
}
@@ -9280,7 +9449,9 @@ namespace TestCaseTracking {
//! Returns true if tracker run to completion (successfully or not)
virtual bool isComplete() const = 0;
//! Returns true if tracker run to completion succesfully
- bool isSuccessfullyCompleted() const;
+ bool isSuccessfullyCompleted() const {
+ return m_runState == CompletedSuccessfully;
+ }
//! Returns true if tracker has started but hasn't been completed
bool isOpen() const;
//! Returns true iff tracker has started
@@ -9298,7 +9469,7 @@ namespace TestCaseTracking {
*
* Returns nullptr if not found.
*/
- ITracker* findChild( NameAndLocationRef nameAndLocation );
+ ITracker* findChild( NameAndLocationRef const& nameAndLocation );
//! Have any children been added?
bool hasChildren() const {
return !m_children.empty();
@@ -9339,13 +9510,15 @@ namespace TestCaseTracking {
public:
ITracker& startRun();
- void endRun();
- void startCycle();
+ void startCycle() {
+ m_currentTracker = m_rootTracker.get();
+ m_runState = Executing;
+ }
void completeCycle();
bool completedCycle() const;
- ITracker& currentTracker();
+ ITracker& currentTracker() { return *m_currentTracker; }
void setCurrentTracker( ITracker* tracker );
};
@@ -9371,7 +9544,11 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase {
std::vector m_filters;
- std::string m_trimmed_name;
+ // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
+ // Currently it allocates owns the name, so this is safe. If it is later refactored
+ // to not own the name, the name still has to outlive the `ITracker` parent, so
+ // this should still be safe.
+ StringRef m_trimmed_name;
public:
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
@@ -9379,14 +9556,14 @@ namespace TestCaseTracking {
bool isComplete() const override;
- static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation );
+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
void tryOpen();
void addInitialFilters( std::vector const& filters );
void addNextFilters( std::vector const& filters );
//! Returns filters active in this tracker
- std::vector const& getFilters() const;
+ std::vector const& getFilters() const { return m_filters; }
//! Returns whitespace-trimmed name of the tracked section
StringRef trimmedName() const;
};
@@ -10960,13 +11137,11 @@ namespace Catch {
}
template
- bool match(RangeLike&& rng) const {
- using std::begin; using std::end;
-
- return end(rng) != std::find_if(begin(rng), end(rng),
- [&](auto const& elem) {
- return m_eq(elem, m_desired);
- });
+ bool match( RangeLike&& rng ) const {
+ for ( auto&& elem : rng ) {
+ if ( m_eq( elem, m_desired ) ) { return true; }
+ }
+ return false;
}
};
@@ -11018,7 +11193,7 @@ namespace Catch {
/**
* Creates a matcher that checks whether a range contains a specific element.
*
- * Uses `eq` to do the comparisons
+ * Uses `eq` to do the comparisons, the element is provided on the rhs
*/
template
ContainsElementMatcher Contains(T&& elem, Equality&& eq) {
@@ -11107,6 +11282,11 @@ namespace Matchers {
double m_margin;
};
+ //! Creates a matcher that accepts numbers within certain range of target
+ WithinAbsMatcher WithinAbs( double target, double margin );
+
+
+
class WithinUlpsMatcher final : public MatcherBase {
public:
WithinUlpsMatcher( double target,
@@ -11120,6 +11300,13 @@ namespace Matchers {
Detail::FloatingPointKind m_type;
};
+ //! Creates a matcher that accepts doubles within certain ULP range of target
+ WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
+ //! Creates a matcher that accepts floats within certain ULP range of target
+ WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
+
+
+
// Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of
@@ -11136,13 +11323,6 @@ namespace Matchers {
double m_epsilon;
};
- //! Creates a matcher that accepts doubles within certain ULP range of target
- WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
- //! Creates a matcher that accepts floats within certain ULP range of target
- WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
- //! Creates a matcher that accepts numbers within certain range of target
- WithinAbsMatcher WithinAbs(double target, double margin);
-
//! Creates a matcher that accepts doubles within certain relative range of target
WithinRelMatcher WithinRel(double target, double eps);
//! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
@@ -11152,6 +11332,17 @@ namespace Matchers {
//! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
WithinRelMatcher WithinRel(float target);
+
+
+ class IsNaNMatcher final : public MatcherBase {
+ public:
+ IsNaNMatcher() = default;
+ bool match( double const& matchee ) const override;
+ std::string describe() const override;
+ };
+
+ IsNaNMatcher IsNaN();
+
} // namespace Matchers
} // namespace Catch
@@ -11370,6 +11561,7 @@ namespace Catch {
#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
+
#include
#include
@@ -11394,13 +11586,19 @@ namespace Catch {
template
bool match( RangeLike&& rng ) const {
- using std::begin;
- using std::end;
- return std::equal( begin(m_desired),
- end(m_desired),
- begin(rng),
- end(rng),
- m_predicate );
+ auto rng_start = begin( rng );
+ const auto rng_end = end( rng );
+ auto target_start = begin( m_desired );
+ const auto target_end = end( m_desired );
+
+ while (rng_start != rng_end && target_start != target_end) {
+ if (!m_predicate(*rng_start, *target_start)) {
+ return false;
+ }
+ ++rng_start;
+ ++target_start;
+ }
+ return rng_start == rng_end && target_start == target_end;
}
std::string describe() const override {
@@ -11428,11 +11626,11 @@ namespace Catch {
bool match( RangeLike&& rng ) const {
using std::begin;
using std::end;
- return std::is_permutation( begin( m_desired ),
- end( m_desired ),
- begin( rng ),
- end( rng ),
- m_predicate );
+ return Catch::Detail::is_permutation( begin( m_desired ),
+ end( m_desired ),
+ begin( rng ),
+ end( rng ),
+ m_predicate );
}
std::string describe() const override {
@@ -12549,7 +12747,7 @@ namespace Catch {
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace { \
Catch::ListenerRegistrar INTERNAL_CATCH_UNIQUE_NAME( \
- catch_internal_RegistrarFor )( #listenerType ); \
+ catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
} \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
diff --git a/meson.build b/meson.build
index 5555ee4008..1faca35f7a 100644
--- a/meson.build
+++ b/meson.build
@@ -8,7 +8,7 @@
project(
'catch2',
'cpp',
- version: '3.3.1', # CML version placeholder, don't delete
+ version: '3.3.2', # CML version placeholder, don't delete
license: 'BSL-1.0',
meson_version: '>=0.50.0',
)
diff --git a/src/catch2/catch_version.cpp b/src/catch2/catch_version.cpp
index d797a3b12e..19cab91b3d 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, 3, 1, "", 0 );
+ static Version version( 3, 3, 2, "", 0 );
return version;
}
diff --git a/src/catch2/catch_version_macros.hpp b/src/catch2/catch_version_macros.hpp
index 75075dd5ce..9ece850511 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 3
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED