This commit is contained in:
Martin Hořeňovský 2023-02-27 15:12:35 +01:00
parent 6fbb3f0723
commit 3f0283de7a
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
8 changed files with 369 additions and 158 deletions

View File

@ -31,7 +31,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif() endif()
project(Catch2 project(Catch2
VERSION 3.3.1 # CML version placeholder, don't delete VERSION 3.3.2 # CML version placeholder, don't delete
LANGUAGES CXX LANGUAGES CXX
# HOMEPAGE_URL is not supported until CMake version 3.12, which # HOMEPAGE_URL is not supported until CMake version 3.12, which
# we do not target yet. # we do not target yet.

View File

@ -151,7 +151,7 @@ are:
> `WithinRel` matcher was introduced in Catch2 2.10.0 > `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 The first three serve to compare two floating pointe numbers. For more
details about how they work, read [the docs on comparing floating point details about how they work, read [the docs on comparing floating point

View File

@ -2,6 +2,7 @@
# Release notes # Release notes
**Contents**<br> **Contents**<br>
[3.3.2](#332)<br>
[3.3.1](#331)<br> [3.3.1](#331)<br>
[3.3.0](#330)<br> [3.3.0](#330)<br>
[3.2.1](#321)<br> [3.2.1](#321)<br>
@ -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 ## 3.3.1
### Improvements ### Improvements
@ -65,7 +89,6 @@
* The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s * The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s
## 3.3.0 ## 3.3.0
### Improvements ### Improvements

View File

@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
// Catch v3.3.1 // Catch v3.3.2
// Generated: 2023-01-29 22:55:05.183536 // Generated: 2023-02-26 10:28:48.270752
// ---------------------------------------------------------- // ----------------------------------------------------------
// This file is an amalgamation of multiple different files. // This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly. // You probably shouldn't edit it directly.
@ -469,16 +469,15 @@ namespace Catch {
} }
std::string AssertionResult::getExpressionInMacro() const { std::string AssertionResult::getExpressionInMacro() const {
if ( m_info.macroName.empty() ) {
return static_cast<std::string>( m_info.capturedExpression );
}
std::string expr; std::string expr;
if( m_info.macroName.empty() )
expr = static_cast<std::string>(m_info.capturedExpression);
else {
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
expr += m_info.macroName; expr += m_info.macroName;
expr += "( "; expr += "( ";
expr += m_info.capturedExpression; expr += m_info.capturedExpression;
expr += " )"; expr += " )";
}
return expr; return expr;
} }
@ -2022,7 +2021,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 3, 3, 1, "", 0 ); static Version version( 3, 3, 2, "", 0 );
return version; return version;
} }
@ -2198,13 +2197,13 @@ namespace Catch {
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals, Totals const& _totals,
std::string const& _stdOut, std::string&& _stdOut,
std::string const& _stdErr, std::string&& _stdErr,
bool _aborting ) bool _aborting )
: testInfo( &_testInfo ), : testInfo( &_testInfo ),
totals( _totals ), totals( _totals ),
stdOut( _stdOut ), stdOut( CATCH_MOVE(_stdOut) ),
stdErr( _stdErr ), stdErr( CATCH_MOVE(_stdErr) ),
aborting( _aborting ) aborting( _aborting )
{} {}
@ -4997,7 +4996,7 @@ namespace Catch {
{} {}
~GeneratorTracker() override; ~GeneratorTracker() override;
static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef nameAndLocation ) { static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) {
GeneratorTracker* tracker; GeneratorTracker* tracker;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
@ -5139,13 +5138,8 @@ namespace Catch {
Totals RunContext::runTest(TestCaseHandle const& testCase) { Totals RunContext::runTest(TestCaseHandle const& testCase) {
const Totals prevTotals = m_totals; const Totals prevTotals = m_totals;
std::string redirectedCout;
std::string redirectedCerr;
auto const& testInfo = testCase.getTestCaseInfo(); auto const& testInfo = testCase.getTestCaseInfo();
m_reporter->testCaseStarting(testInfo); m_reporter->testCaseStarting(testInfo);
m_activeTestCase = &testCase; m_activeTestCase = &testCase;
@ -5187,6 +5181,8 @@ namespace Catch {
seedRng( *m_config ); seedRng( *m_config );
uint64_t testRuns = 0; uint64_t testRuns = 0;
std::string redirectedCout;
std::string redirectedCerr;
do { do {
m_trackerContext.startCycle(); m_trackerContext.startCycle();
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
@ -5200,7 +5196,7 @@ namespace Catch {
redirectedCerr += oneRunCerr; redirectedCerr += oneRunCerr;
const auto singleRunTotals = m_totals.delta(beforeRunTotals); 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); m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
++testRuns; ++testRuns;
@ -5215,8 +5211,8 @@ namespace Catch {
m_totals.testCases += deltaTotals.testCases; m_totals.testCases += deltaTotals.testCases;
m_reporter->testCaseEnded(TestCaseStats(testInfo, m_reporter->testCaseEnded(TestCaseStats(testInfo,
deltaTotals, deltaTotals,
redirectedCout, CATCH_MOVE(redirectedCout),
redirectedCerr, CATCH_MOVE(redirectedCerr),
aborting())); aborting()));
m_activeTestCase = nullptr; m_activeTestCase = nullptr;
@ -5605,10 +5601,11 @@ namespace Catch {
void RunContext::handleIncomplete( void RunContext::handleIncomplete(
AssertionInfo const& info AssertionInfo const& info
) { ) {
using namespace std::string_literals;
m_lastAssertionInfo = info; m_lastAssertionInfo = info;
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); 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 ) }; AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult ); assertionEnded( assertionResult );
} }
@ -5663,7 +5660,7 @@ namespace Catch {
Section::Section( SourceLineInfo const& _lineInfo, Section::Section( SourceLineInfo const& _lineInfo,
StringRef _name, StringRef _name,
const char* const ): const char* const ):
m_info( { "invalid", static_cast<std::size_t>(-1) }, "" ), m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
m_sectionIncluded( m_sectionIncluded(
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) { getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
// We delay initialization the SectionInfo member until we know // We delay initialization the SectionInfo member until we know
@ -5900,10 +5897,6 @@ namespace Catch {
: StringRef( rawChars, std::strlen(rawChars) ) : 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 { bool StringRef::operator<(StringRef rhs) const noexcept {
if (m_size < rhs.m_size) { if (m_size < rhs.m_size) {
@ -6195,12 +6188,17 @@ namespace TestCaseTracking {
m_children.push_back( CATCH_MOVE(child) ); m_children.push_back( CATCH_MOVE(child) );
} }
ITracker* ITracker::findChild( NameAndLocationRef nameAndLocation ) { ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
auto it = std::find_if( auto it = std::find_if(
m_children.begin(), m_children.begin(),
m_children.end(), m_children.end(),
[&nameAndLocation]( ITrackerPtr const& tracker ) { [&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; return ( it != m_children.end() ) ? it->get() : nullptr;
} }
@ -6208,10 +6206,6 @@ namespace TestCaseTracking {
bool ITracker::isSectionTracker() const { return false; } bool ITracker::isSectionTracker() const { return false; }
bool ITracker::isGeneratorTracker() const { return false; } bool ITracker::isGeneratorTracker() const { return false; }
bool ITracker::isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully;
}
bool ITracker::isOpen() const { bool ITracker::isOpen() const {
return m_runState != NotStarted && !isComplete(); return m_runState != NotStarted && !isComplete();
} }
@ -6238,16 +6232,6 @@ namespace TestCaseTracking {
return *m_rootTracker; 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() { void TrackerContext::completeCycle() {
m_runState = CompletedCycle; m_runState = CompletedCycle;
} }
@ -6255,9 +6239,6 @@ namespace TestCaseTracking {
bool TrackerContext::completedCycle() const { bool TrackerContext::completedCycle() const {
return m_runState == CompletedCycle; return m_runState == CompletedCycle;
} }
ITracker& TrackerContext::currentTracker() {
return *m_currentTracker;
}
void TrackerContext::setCurrentTracker( ITracker* tracker ) { void TrackerContext::setCurrentTracker( ITracker* tracker ) {
m_currentTracker = tracker; m_currentTracker = tracker;
} }
@ -6326,7 +6307,7 @@ namespace TestCaseTracking {
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(ITracker::nameAndLocation().name)) m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
{ {
if( parent ) { if( parent ) {
while ( !parent->isSectionTracker() ) { while ( !parent->isSectionTracker() ) {
@ -6351,7 +6332,7 @@ namespace TestCaseTracking {
bool SectionTracker::isSectionTracker() const { return true; } bool SectionTracker::isSectionTracker() const { return true; }
SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation ) { SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
SectionTracker* tracker; SectionTracker* tracker;
ITracker& currentTracker = ctx.currentTracker(); ITracker& currentTracker = ctx.currentTracker();
@ -6395,10 +6376,6 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
} }
std::vector<StringRef> const& SectionTracker::getFilters() const {
return m_filters;
}
StringRef SectionTracker::trimmedName() const { StringRef SectionTracker::trimmedName() const {
return m_trimmed_name; return m_trimmed_name;
} }
@ -6697,10 +6674,8 @@ namespace Catch {
token.erase(token.begin()); token.erase(token.begin());
if (m_exclusion) { if (m_exclusion) {
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring)); m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
} else { } else {
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring)); m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
} }
} }
if (m_exclusion) { 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 } // namespace Catch
@ -8080,7 +8067,7 @@ private:
private: private:
std::ostream& stream; std::ostream& stream;
AssertionResult const& result; AssertionResult const& result;
std::vector<MessageInfo> messages; std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage; std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages; bool printInfoMessages;
ColourImpl* colourImpl; ColourImpl* colourImpl;
@ -8174,7 +8161,6 @@ public:
stats(_stats), stats(_stats),
result(_stats.assertionResult), result(_stats.assertionResult),
colour(Colour::None), colour(Colour::None),
message(result.getMessage()),
messages(_stats.infoMessages), messages(_stats.infoMessages),
colourImpl(colourImpl_), colourImpl(colourImpl_),
printInfoMessages(_printInfoMessages) { printInfoMessages(_printInfoMessages) {
@ -8183,10 +8169,10 @@ public:
colour = Colour::Success; colour = Colour::Success;
passOrFail = "PASSED"_sr; passOrFail = "PASSED"_sr;
//if( result.hasMessage() ) //if( result.hasMessage() )
if (_stats.infoMessages.size() == 1) if (messages.size() == 1)
messageLabel = "with message"; messageLabel = "with message"_sr;
if (_stats.infoMessages.size() > 1) if (messages.size() > 1)
messageLabel = "with messages"; messageLabel = "with messages"_sr;
break; break;
case ResultWas::ExpressionFailed: case ResultWas::ExpressionFailed:
if (result.isOk()) { if (result.isOk()) {
@ -8196,51 +8182,57 @@ public:
colour = Colour::Error; colour = Colour::Error;
passOrFail = "FAILED"_sr; passOrFail = "FAILED"_sr;
} }
if (_stats.infoMessages.size() == 1) if (messages.size() == 1)
messageLabel = "with message"; messageLabel = "with message"_sr;
if (_stats.infoMessages.size() > 1) if (messages.size() > 1)
messageLabel = "with messages"; messageLabel = "with messages"_sr;
break; break;
case ResultWas::ThrewException: case ResultWas::ThrewException:
colour = Colour::Error; colour = Colour::Error;
passOrFail = "FAILED"_sr; passOrFail = "FAILED"_sr;
messageLabel = "due to unexpected exception with "; // todo switch
if (_stats.infoMessages.size() == 1) switch (messages.size()) { case 0:
messageLabel += "message"; messageLabel = "due to unexpected exception with "_sr;
if (_stats.infoMessages.size() > 1) break;
messageLabel += "messages"; case 1:
messageLabel = "due to unexpected exception with message"_sr;
break;
default:
messageLabel = "due to unexpected exception with messages"_sr;
break;
}
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
colour = Colour::Error; colour = Colour::Error;
passOrFail = "FAILED"_sr; passOrFail = "FAILED"_sr;
messageLabel = "due to a fatal error condition"; messageLabel = "due to a fatal error condition"_sr;
break; break;
case ResultWas::DidntThrowException: case ResultWas::DidntThrowException:
colour = Colour::Error; colour = Colour::Error;
passOrFail = "FAILED"_sr; 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; break;
case ResultWas::Info: case ResultWas::Info:
messageLabel = "info"; messageLabel = "info"_sr;
break; break;
case ResultWas::Warning: case ResultWas::Warning:
messageLabel = "warning"; messageLabel = "warning"_sr;
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
passOrFail = "FAILED"_sr; passOrFail = "FAILED"_sr;
colour = Colour::Error; colour = Colour::Error;
if (_stats.infoMessages.size() == 1) if (messages.size() == 1)
messageLabel = "explicitly with message"; messageLabel = "explicitly with message"_sr;
if (_stats.infoMessages.size() > 1) if (messages.size() > 1)
messageLabel = "explicitly with messages"; messageLabel = "explicitly with messages"_sr;
break; break;
case ResultWas::ExplicitSkip: case ResultWas::ExplicitSkip:
colour = Colour::Skip; colour = Colour::Skip;
passOrFail = "SKIPPED"_sr; passOrFail = "SKIPPED"_sr;
if (_stats.infoMessages.size() == 1) if (messages.size() == 1)
messageLabel = "explicitly with message"; messageLabel = "explicitly with message"_sr;
if (_stats.infoMessages.size() > 1) if (messages.size() > 1)
messageLabel = "explicitly with messages"; messageLabel = "explicitly with messages"_sr;
break; break;
// These cases are here to prevent compiler warnings // These cases are here to prevent compiler warnings
case ResultWas::Unknown: case ResultWas::Unknown:
@ -8304,9 +8296,8 @@ private:
AssertionResult const& result; AssertionResult const& result;
Colour::Code colour; Colour::Code colour;
StringRef passOrFail; StringRef passOrFail;
std::string messageLabel; StringRef messageLabel;
std::string message; std::vector<MessageInfo> const& messages;
std::vector<MessageInfo> messages;
ColourImpl* colourImpl; ColourImpl* colourImpl;
bool printInfoMessages; bool printInfoMessages;
}; };
@ -10133,7 +10124,7 @@ namespace Catch {
private: private:
std::ostream& stream; std::ostream& stream;
AssertionResult const& result; AssertionResult const& result;
std::vector<MessageInfo> messages; std::vector<MessageInfo> const& messages;
std::vector<MessageInfo>::const_iterator itMessage; std::vector<MessageInfo>::const_iterator itMessage;
bool printInfoMessages; bool printInfoMessages;
std::size_t counter; std::size_t counter;
@ -10396,7 +10387,7 @@ namespace Catch {
void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
StreamingReporterBase::testCaseStarting(testInfo); StreamingReporterBase::testCaseStarting(testInfo);
m_xml.startElement( "TestCase" ) m_xml.startElement( "TestCase" )
.writeAttribute( "name"_sr, trim( testInfo.name ) ) .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
.writeAttribute( "tags"_sr, testInfo.tagsAsString() ); .writeAttribute( "tags"_sr, testInfo.tagsAsString() );
writeSourceInfo( testInfo.lineInfo ); writeSourceInfo( testInfo.lineInfo );
@ -10410,7 +10401,7 @@ namespace Catch {
StreamingReporterBase::sectionStarting( sectionInfo ); StreamingReporterBase::sectionStarting( sectionInfo );
if( m_sectionDepth++ > 0 ) { if( m_sectionDepth++ > 0 ) {
m_xml.startElement( "Section" ) m_xml.startElement( "Section" )
.writeAttribute( "name"_sr, trim( sectionInfo.name ) ); .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
writeSourceInfo( sectionInfo.lineInfo ); writeSourceInfo( sectionInfo.lineInfo );
m_xml.ensureTagClosed(); m_xml.ensureTagClosed();
} }
@ -10524,11 +10515,10 @@ namespace Catch {
if ( m_config->showDurations() == ShowDurations::Always ) if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() ); e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
if( !testCaseStats.stdOut.empty() ) 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() ) 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(); m_xml.endElement();
} }

View File

@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
// Catch v3.3.1 // Catch v3.3.2
// Generated: 2023-01-29 22:55:03.856079 // Generated: 2023-02-26 10:28:46.785908
// ---------------------------------------------------------- // ----------------------------------------------------------
// This file is an amalgamation of multiple different files. // This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly. // You probably shouldn't edit it directly.
@ -95,6 +95,8 @@ namespace Catch {
#include <iosfwd> #include <iosfwd>
#include <cassert> #include <cassert>
#include <cstring>
namespace Catch { namespace Catch {
/// A non-owning string class (similar to the forthcoming std::string_view) /// A non-owning string class (similar to the forthcoming std::string_view)
@ -131,7 +133,10 @@ namespace Catch {
} }
public: // operators 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 { auto operator != (StringRef other) const noexcept -> bool {
return !(*this == other); return !(*this == other);
} }
@ -352,7 +357,7 @@ namespace Catch {
// Only GCC compiler should be used in this block, so other compilers trying to // Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored. // 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_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@ -371,6 +376,12 @@ namespace Catch {
#endif #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__) #if defined(__CUDACC__) && !defined(__clang__)
# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ # ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
// New pragmas introduced in CUDA 11.5+ // New pragmas introduced in CUDA 11.5+
@ -1434,8 +1445,8 @@ namespace Catch {
struct TestCaseStats { struct TestCaseStats {
TestCaseStats( TestCaseInfo const& _testInfo, TestCaseStats( TestCaseInfo const& _testInfo,
Totals const& _totals, Totals const& _totals,
std::string const& _stdOut, std::string&& _stdOut,
std::string const& _stdErr, std::string&& _stdErr,
bool _aborting ); bool _aborting );
TestCaseInfo const * testInfo; TestCaseInfo const * testInfo;
@ -4518,7 +4529,10 @@ namespace Catch {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ #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__ ) varName.captureValues( 0, __VA_ARGS__ )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -5904,9 +5918,9 @@ namespace Catch {
#if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else #else
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif #endif
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #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_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_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 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -6245,7 +6265,11 @@ struct AutoReg : Detail::NonCopyable {
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
void test(); \ 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 \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test() void TestName::test()
@ -6878,7 +6902,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests() { \ void reg_tests() { \
size_t index = 0; \ size_t index = 0; \
using expander = size_t[]; \ using expander = size_t[]; \
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), 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<Types> ), 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 ) = [](){ \ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
@ -7013,7 +7037,7 @@ struct AutoReg : Detail::NonCopyable {
void reg_tests(){\ void reg_tests(){\
size_t index = 0;\ size_t index = 0;\
using expander = size_t[];\ using expander = size_t[];\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::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<Types>::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 ) = [](){\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
@ -7402,7 +7426,7 @@ namespace Catch {
#define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3 #define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_PATCH 1 #define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED #endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@ -7754,16 +7778,19 @@ namespace Detail {
} // namespace Generators } // namespace Generators
} // namespace Catch } // 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( ... ) \ #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, \ CATCH_INTERNAL_LINEINFO, \
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_COPY( ... ) \ #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, \ CATCH_INTERNAL_LINEINFO, \
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
#define GENERATE_REF( ... ) \ #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, \ CATCH_INTERNAL_LINEINFO, \
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
@ -8919,6 +8946,139 @@ namespace Detail {
#endif // CATCH_GETENV_HPP_INCLUDED #endif // CATCH_GETENV_HPP_INCLUDED
#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
#define CATCH_IS_PERMUTATION_HPP_INCLUDED
#include <algorithm>
#include <iterator>
namespace Catch {
namespace Detail {
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
ForwardIter find_sentinel( ForwardIter start,
Sentinel sentinel,
T const& value,
Comparator cmp ) {
while ( start != sentinel ) {
if ( cmp( *start, value ) ) { break; }
++start;
}
return start;
}
template <typename ForwardIter,
typename Sentinel,
typename T,
typename Comparator>
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 <typename ForwardIter, typename Sentinel>
std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
std::ptrdiff_t>
sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
std::ptrdiff_t dist = 0;
while ( iter != sentinel ) {
++iter;
++dist;
}
return dist;
}
template <typename ForwardIter>
std::ptrdiff_t sentinel_distance( ForwardIter first,
ForwardIter last ) {
return std::distance( first, last );
}
template <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
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 <typename ForwardIter1,
typename Sentinel1,
typename ForwardIter2,
typename Sentinel2,
typename Comparator>
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 #ifndef CATCH_ISTREAM_HPP_INCLUDED
#define CATCH_ISTREAM_HPP_INCLUDED #define CATCH_ISTREAM_HPP_INCLUDED
@ -9199,8 +9359,12 @@ namespace TestCaseTracking {
NameAndLocation( std::string&& _name, SourceLineInfo const& _location ); NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
return lhs.name == rhs.name // This is a very cheap check that should have a very high hit rate.
&& lhs.location == rhs.location; // 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, friend bool operator!=(NameAndLocation const& lhs,
NameAndLocation const& rhs) { NameAndLocation const& rhs) {
@ -9224,11 +9388,16 @@ namespace TestCaseTracking {
name( name_ ), location( location_ ) {} name( name_ ), location( location_ ) {}
friend bool operator==( NameAndLocation const& lhs, 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 && return StringRef( lhs.name ) == rhs.name &&
lhs.location == rhs.location; lhs.location == rhs.location;
} }
friend bool operator==( NameAndLocationRef lhs, friend bool operator==( NameAndLocationRef const& lhs,
NameAndLocation const& rhs ) { NameAndLocation const& rhs ) {
return rhs == lhs; return rhs == lhs;
} }
@ -9280,7 +9449,9 @@ namespace TestCaseTracking {
//! Returns true if tracker run to completion (successfully or not) //! Returns true if tracker run to completion (successfully or not)
virtual bool isComplete() const = 0; virtual bool isComplete() const = 0;
//! Returns true if tracker run to completion succesfully //! 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 //! Returns true if tracker has started but hasn't been completed
bool isOpen() const; bool isOpen() const;
//! Returns true iff tracker has started //! Returns true iff tracker has started
@ -9298,7 +9469,7 @@ namespace TestCaseTracking {
* *
* Returns nullptr if not found. * Returns nullptr if not found.
*/ */
ITracker* findChild( NameAndLocationRef nameAndLocation ); ITracker* findChild( NameAndLocationRef const& nameAndLocation );
//! Have any children been added? //! Have any children been added?
bool hasChildren() const { bool hasChildren() const {
return !m_children.empty(); return !m_children.empty();
@ -9339,13 +9510,15 @@ namespace TestCaseTracking {
public: public:
ITracker& startRun(); ITracker& startRun();
void endRun();
void startCycle(); void startCycle() {
m_currentTracker = m_rootTracker.get();
m_runState = Executing;
}
void completeCycle(); void completeCycle();
bool completedCycle() const; bool completedCycle() const;
ITracker& currentTracker(); ITracker& currentTracker() { return *m_currentTracker; }
void setCurrentTracker( ITracker* tracker ); void setCurrentTracker( ITracker* tracker );
}; };
@ -9371,7 +9544,11 @@ namespace TestCaseTracking {
class SectionTracker : public TrackerBase { class SectionTracker : public TrackerBase {
std::vector<StringRef> m_filters; std::vector<StringRef> 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: public:
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ); SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
@ -9379,14 +9556,14 @@ namespace TestCaseTracking {
bool isComplete() const override; bool isComplete() const override;
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef nameAndLocation ); static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
void tryOpen(); void tryOpen();
void addInitialFilters( std::vector<std::string> const& filters ); void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<StringRef> const& filters ); void addNextFilters( std::vector<StringRef> const& filters );
//! Returns filters active in this tracker //! Returns filters active in this tracker
std::vector<StringRef> const& getFilters() const; std::vector<StringRef> const& getFilters() const { return m_filters; }
//! Returns whitespace-trimmed name of the tracked section //! Returns whitespace-trimmed name of the tracked section
StringRef trimmedName() const; StringRef trimmedName() const;
}; };
@ -10960,13 +11137,11 @@ namespace Catch {
} }
template <typename RangeLike> template <typename RangeLike>
bool match(RangeLike&& rng) const { bool match( RangeLike&& rng ) const {
using std::begin; using std::end; for ( auto&& elem : rng ) {
if ( m_eq( elem, m_desired ) ) { return true; }
return end(rng) != std::find_if(begin(rng), end(rng), }
[&](auto const& elem) { return false;
return m_eq(elem, m_desired);
});
} }
}; };
@ -11018,7 +11193,7 @@ namespace Catch {
/** /**
* Creates a matcher that checks whether a range contains a specific element. * 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 <typename T, typename Equality> template <typename T, typename Equality>
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) { ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
@ -11107,6 +11282,11 @@ namespace Matchers {
double m_margin; 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<double> { class WithinUlpsMatcher final : public MatcherBase<double> {
public: public:
WithinUlpsMatcher( double target, WithinUlpsMatcher( double target,
@ -11120,6 +11300,13 @@ namespace Matchers {
Detail::FloatingPointKind m_type; 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 // Given IEEE-754 format for floats and doubles, we can assume
// that float -> double promotion is lossless. Given this, we can // that float -> double promotion is lossless. Given this, we can
// assume that if we do the standard relative comparison of // assume that if we do the standard relative comparison of
@ -11136,13 +11323,6 @@ namespace Matchers {
double m_epsilon; 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 //! Creates a matcher that accepts doubles within certain relative range of target
WithinRelMatcher WithinRel(double target, double eps); WithinRelMatcher WithinRel(double target, double eps);
//! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target //! 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 //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
WithinRelMatcher WithinRel(float target); WithinRelMatcher WithinRel(float target);
class IsNaNMatcher final : public MatcherBase<double> {
public:
IsNaNMatcher() = default;
bool match( double const& matchee ) const override;
std::string describe() const override;
};
IsNaNMatcher IsNaN();
} // namespace Matchers } // namespace Matchers
} // namespace Catch } // namespace Catch
@ -11370,6 +11561,7 @@ namespace Catch {
#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED #ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED #define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
@ -11394,13 +11586,19 @@ namespace Catch {
template <typename RangeLike> template <typename RangeLike>
bool match( RangeLike&& rng ) const { bool match( RangeLike&& rng ) const {
using std::begin; auto rng_start = begin( rng );
using std::end; const auto rng_end = end( rng );
return std::equal( begin(m_desired), auto target_start = begin( m_desired );
end(m_desired), const auto target_end = end( m_desired );
begin(rng),
end(rng), while (rng_start != rng_end && target_start != target_end) {
m_predicate ); 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 { std::string describe() const override {
@ -11428,7 +11626,7 @@ namespace Catch {
bool match( RangeLike&& rng ) const { bool match( RangeLike&& rng ) const {
using std::begin; using std::begin;
using std::end; using std::end;
return std::is_permutation( begin( m_desired ), return Catch::Detail::is_permutation( begin( m_desired ),
end( m_desired ), end( m_desired ),
begin( rng ), begin( rng ),
end( rng ), end( rng ),
@ -12549,7 +12747,7 @@ namespace Catch {
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
namespace { \ namespace { \
Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \ Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
catch_internal_RegistrarFor )( #listenerType ); \ catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
} \ } \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION

View File

@ -8,7 +8,7 @@
project( project(
'catch2', 'catch2',
'cpp', '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', license: 'BSL-1.0',
meson_version: '>=0.50.0', meson_version: '>=0.50.0',
) )

View File

@ -36,7 +36,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 3, 3, 1, "", 0 ); static Version version( 3, 3, 2, "", 0 );
return version; return version;
} }

View File

@ -10,6 +10,6 @@
#define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3 #define CATCH_VERSION_MINOR 3
#define CATCH_VERSION_PATCH 1 #define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED #endif // CATCH_VERSION_MACROS_HPP_INCLUDED