mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-25 06:46:10 +01:00
v3.5.3
This commit is contained in:
parent
b20b365fd2
commit
8ac8190e49
@ -33,7 +33,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(Catch2
|
project(Catch2
|
||||||
VERSION 3.5.2 # CML version placeholder, don't delete
|
VERSION 3.5.3 # 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.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
# Release notes
|
# Release notes
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
|
[3.5.3](#353)<br>
|
||||||
[3.5.2](#352)<br>
|
[3.5.2](#352)<br>
|
||||||
[3.5.1](#351)<br>
|
[3.5.1](#351)<br>
|
||||||
[3.5.0](#350)<br>
|
[3.5.0](#350)<br>
|
||||||
@ -60,6 +61,31 @@
|
|||||||
[Even Older versions](#even-older-versions)<br>
|
[Even Older versions](#even-older-versions)<br>
|
||||||
|
|
||||||
|
|
||||||
|
## 3.5.3
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed OOB access when computing filename tag (from the `-#` flag) for file without extension (#2798)
|
||||||
|
* Fixed the linking against `log` on Android to be `PRIVATE` (#2815)
|
||||||
|
* Fixed `Wuseless-cast` in benchmarking internals (#2823)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Restored compatibility with VS2017 (#2792, #2822)
|
||||||
|
* The baseline for Catch2 is still C++14 with some reasonable workarounds for specific compilers, so if VS2017 starts acting up again, the support will be dropped again.
|
||||||
|
* Suppressed clang-tidy's `bugprone-chained-comparison` in assertions (#2801)
|
||||||
|
* Improved the static analysis mode to evaluate arguments to `TEST_CASE` and `SECTION` (#2817)
|
||||||
|
* Clang-tidy should no longer warn about runtime arguments to these macros being unused in static analysis mode.
|
||||||
|
* Clang-tidy can warn on issues involved arguments to these macros.
|
||||||
|
* Added support for literal-zero detectors based on `consteval` constructors
|
||||||
|
* This is required for compiling `REQUIRE((a <=> b) == 0)` against MSVC's stdlib.
|
||||||
|
* Sadly, MSVC still cannot compile this assertion as it does not implement C++20 correctly.
|
||||||
|
* You can use `clang-cl` with MSVC's stdlib instead.
|
||||||
|
* If for some godforsaken reasons you want to understand this better, read the two relevant commits: [`dc51386b9fd61f99ea9c660d01867e6ad489b403`](https://github.com/catchorg/Catch2/commit/dc51386b9fd61f99ea9c660d01867e6ad489b403), and [`0787132fc82a75e3fb255aa9484ca1dc1eff2a30`](https://github.com/catchorg/Catch2/commit/0787132fc82a75e3fb255aa9484ca1dc1eff2a30).
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* Disabled tests for FP random generator reproducibility on non-SSE2 x86 targets (#2796)
|
||||||
|
* Modified the in-tree Conan recipe to support Conan 2 (#2805)
|
||||||
|
|
||||||
|
|
||||||
## 3.5.2
|
## 3.5.2
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
// Catch v3.5.2
|
// Catch v3.5.3
|
||||||
// Generated: 2024-01-15 14:06:36.675713
|
// Generated: 2024-03-01 22:05:56.038084
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// 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.
|
||||||
@ -101,8 +101,8 @@ namespace Catch {
|
|||||||
FDuration mean = FDuration(0);
|
FDuration mean = FDuration(0);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto it = first; it < last; ++it, ++i) {
|
for (auto it = first; it < last; ++it, ++i) {
|
||||||
samples.push_back(FDuration(*it));
|
samples.push_back(*it);
|
||||||
mean += FDuration(*it);
|
mean += *it;
|
||||||
}
|
}
|
||||||
mean /= i;
|
mean /= i;
|
||||||
|
|
||||||
@ -558,7 +558,7 @@ bool marginComparison(double lhs, double rhs, double margin) {
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
Approx::Approx ( double value )
|
Approx::Approx ( double value )
|
||||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100. ),
|
: m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
|
||||||
m_margin( 0.0 ),
|
m_margin( 0.0 ),
|
||||||
m_scale( 0.0 ),
|
m_scale( 0.0 ),
|
||||||
m_value( value )
|
m_value( value )
|
||||||
@ -1038,6 +1038,7 @@ namespace Catch {
|
|||||||
m_messages.back().message += " := ";
|
m_messages.back().message += " := ";
|
||||||
start = pos;
|
start = pos;
|
||||||
}
|
}
|
||||||
|
default:; // noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(openings.empty() && "Mismatched openings");
|
assert(openings.empty() && "Mismatched openings");
|
||||||
@ -1581,8 +1582,10 @@ namespace Catch {
|
|||||||
while (lastDot > 0 && filename[lastDot - 1] != '.') {
|
while (lastDot > 0 && filename[lastDot - 1] != '.') {
|
||||||
--lastDot;
|
--lastDot;
|
||||||
}
|
}
|
||||||
--lastDot;
|
// In theory we could have filename without any extension in it
|
||||||
|
if ( lastDot == 0 ) { return StringRef(); }
|
||||||
|
|
||||||
|
--lastDot;
|
||||||
size_t nameStart = lastDot;
|
size_t nameStart = lastDot;
|
||||||
while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
|
while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
|
||||||
--nameStart;
|
--nameStart;
|
||||||
@ -1966,13 +1969,13 @@ namespace Detail {
|
|||||||
}
|
}
|
||||||
} // end unnamed namespace
|
} // end unnamed namespace
|
||||||
|
|
||||||
std::string convertIntoString(StringRef string, bool escape_invisibles) {
|
std::string convertIntoString(StringRef string, bool escapeInvisibles) {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
// This is enough for the "don't escape invisibles" case, and a good
|
// This is enough for the "don't escape invisibles" case, and a good
|
||||||
// lower bound on the "escape invisibles" case.
|
// lower bound on the "escape invisibles" case.
|
||||||
ret.reserve(string.size() + 2);
|
ret.reserve(string.size() + 2);
|
||||||
|
|
||||||
if (!escape_invisibles) {
|
if (!escapeInvisibles) {
|
||||||
ret += '"';
|
ret += '"';
|
||||||
ret += string;
|
ret += string;
|
||||||
ret += '"';
|
ret += '"';
|
||||||
@ -2050,7 +2053,7 @@ std::string StringMaker<char const*>::convert(char const* str) {
|
|||||||
return{ "{null string}" };
|
return{ "{null string}" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string StringMaker<char*>::convert(char* str) {
|
std::string StringMaker<char*>::convert(char* str) { // NOLINT(readability-non-const-parameter)
|
||||||
if (str) {
|
if (str) {
|
||||||
return Detail::convertIntoString( str );
|
return Detail::convertIntoString( str );
|
||||||
} else {
|
} else {
|
||||||
@ -2147,8 +2150,8 @@ std::string StringMaker<signed char>::convert(signed char value) {
|
|||||||
std::string StringMaker<char>::convert(char c) {
|
std::string StringMaker<char>::convert(char c) {
|
||||||
return ::Catch::Detail::stringify(static_cast<signed char>(c));
|
return ::Catch::Detail::stringify(static_cast<signed char>(c));
|
||||||
}
|
}
|
||||||
std::string StringMaker<unsigned char>::convert(unsigned char c) {
|
std::string StringMaker<unsigned char>::convert(unsigned char value) {
|
||||||
return ::Catch::Detail::stringify(static_cast<char>(c));
|
return ::Catch::Detail::stringify(static_cast<char>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
int StringMaker<float>::precision = 5;
|
int StringMaker<float>::precision = 5;
|
||||||
@ -2268,7 +2271,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 3, 5, 2, "", 0 );
|
static Version version( 3, 5, 3, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3092,7 +3095,7 @@ namespace Catch {
|
|||||||
line = trim(line);
|
line = trim(line);
|
||||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||||
if( !startsWith( line, '"' ) )
|
if( !startsWith( line, '"' ) )
|
||||||
line = '"' + line + '"';
|
line = '"' + CATCH_MOVE(line) + '"';
|
||||||
config.testsOrTags.push_back( line );
|
config.testsOrTags.push_back( line );
|
||||||
config.testsOrTags.emplace_back( "," );
|
config.testsOrTags.emplace_back( "," );
|
||||||
}
|
}
|
||||||
@ -3573,21 +3576,21 @@ namespace {
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode implSelection,
|
Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
|
||||||
IStream* stream ) {
|
IStream* stream ) {
|
||||||
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
||||||
if ( implSelection == ColourMode::Win32 ) {
|
if ( colourSelection == ColourMode::Win32 ) {
|
||||||
return Detail::make_unique<Win32ColourImpl>( stream );
|
return Detail::make_unique<Win32ColourImpl>( stream );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ( implSelection == ColourMode::ANSI ) {
|
if ( colourSelection == ColourMode::ANSI ) {
|
||||||
return Detail::make_unique<ANSIColourImpl>( stream );
|
return Detail::make_unique<ANSIColourImpl>( stream );
|
||||||
}
|
}
|
||||||
if ( implSelection == ColourMode::None ) {
|
if ( colourSelection == ColourMode::None ) {
|
||||||
return Detail::make_unique<NoColourImpl>( stream );
|
return Detail::make_unique<NoColourImpl>( stream );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( implSelection == ColourMode::PlatformDefault) {
|
if ( colourSelection == ColourMode::PlatformDefault) {
|
||||||
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
#if defined( CATCH_CONFIG_COLOUR_WIN32 )
|
||||||
if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
|
if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
|
||||||
return Detail::make_unique<Win32ColourImpl>( stream );
|
return Detail::make_unique<Win32ColourImpl>( stream );
|
||||||
@ -3599,7 +3602,7 @@ namespace Catch {
|
|||||||
return Detail::make_unique<NoColourImpl>( stream );
|
return Detail::make_unique<NoColourImpl>( stream );
|
||||||
}
|
}
|
||||||
|
|
||||||
CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(implSelection) );
|
CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(colourSelection) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isColourImplAvailable( ColourMode colourSelection ) {
|
bool isColourImplAvailable( ColourMode colourSelection ) {
|
||||||
@ -3807,7 +3810,12 @@ namespace Catch {
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
ITransientExpression::~ITransientExpression() = default;
|
void ITransientExpression::streamReconstructedExpression(
|
||||||
|
std::ostream& os ) const {
|
||||||
|
// We can't make this function pure virtual to keep ITransientExpression
|
||||||
|
// constexpr, so we write error message instead
|
||||||
|
os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
|
||||||
|
}
|
||||||
|
|
||||||
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
|
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
|
||||||
if( lhs.size() + rhs.size() < 40 &&
|
if( lhs.size() + rhs.size() < 40 &&
|
||||||
@ -4473,7 +4481,7 @@ namespace Catch {
|
|||||||
m_os{ os }, m_indent_level{ indent_level } {
|
m_os{ os }, m_indent_level{ indent_level } {
|
||||||
m_os << '{';
|
m_os << '{';
|
||||||
}
|
}
|
||||||
JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ):
|
JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept:
|
||||||
m_os{ source.m_os },
|
m_os{ source.m_os },
|
||||||
m_indent_level{ source.m_indent_level },
|
m_indent_level{ source.m_indent_level },
|
||||||
m_should_comma{ source.m_should_comma },
|
m_should_comma{ source.m_should_comma },
|
||||||
@ -4504,7 +4512,7 @@ namespace Catch {
|
|||||||
m_os{ os }, m_indent_level{ indent_level } {
|
m_os{ os }, m_indent_level{ indent_level } {
|
||||||
m_os << '[';
|
m_os << '[';
|
||||||
}
|
}
|
||||||
JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ):
|
JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept:
|
||||||
m_os{ source.m_os },
|
m_os{ source.m_os },
|
||||||
m_indent_level{ source.m_indent_level },
|
m_indent_level{ source.m_indent_level },
|
||||||
m_should_comma{ source.m_should_comma },
|
m_should_comma{ source.m_should_comma },
|
||||||
@ -5283,7 +5291,7 @@ namespace Catch {
|
|||||||
auto kv = splitKVPair( parts[i] );
|
auto kv = splitKVPair( parts[i] );
|
||||||
auto key = kv.key, value = kv.value;
|
auto key = kv.key, value = kv.value;
|
||||||
|
|
||||||
if ( key.empty() || value.empty() ) {
|
if ( key.empty() || value.empty() ) { // NOLINT(bugprone-branch-clone)
|
||||||
return {};
|
return {};
|
||||||
} else if ( key[0] == 'X' ) {
|
} else if ( key[0] == 'X' ) {
|
||||||
// This is a reporter-specific option, we don't check these
|
// This is a reporter-specific option, we don't check these
|
||||||
@ -6297,17 +6305,29 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
||||||
bool replaced = false;
|
|
||||||
std::size_t i = str.find( replaceThis );
|
std::size_t i = str.find( replaceThis );
|
||||||
while( i != std::string::npos ) {
|
if (i == std::string::npos) {
|
||||||
replaced = true;
|
return false;
|
||||||
str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
|
}
|
||||||
if( i < str.size()-withThis.size() )
|
std::size_t copyBegin = 0;
|
||||||
i = str.find( replaceThis, i+withThis.size() );
|
std::string origStr = CATCH_MOVE(str);
|
||||||
|
str.clear();
|
||||||
|
// There is at least one replacement, so reserve with the best guess
|
||||||
|
// we can make without actually counting the number of occurences.
|
||||||
|
str.reserve(origStr.size() - replaceThis.size() + withThis.size());
|
||||||
|
do {
|
||||||
|
str.append(origStr, copyBegin, i-copyBegin );
|
||||||
|
str += withThis;
|
||||||
|
copyBegin = i + replaceThis.size();
|
||||||
|
if( copyBegin < origStr.size() )
|
||||||
|
i = origStr.find( replaceThis, copyBegin );
|
||||||
else
|
else
|
||||||
i = std::string::npos;
|
i = std::string::npos;
|
||||||
|
} while( i != std::string::npos );
|
||||||
|
if ( copyBegin < origStr.size() ) {
|
||||||
|
str.append(origStr, copyBegin, origStr.size() );
|
||||||
}
|
}
|
||||||
return replaced;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
|
std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
|
||||||
@ -9099,8 +9119,8 @@ void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
|
|||||||
m_stream << '\n' << std::flush;
|
m_stream << '\n' << std::flush;
|
||||||
StreamingReporterBase::testRunEnded(_testRunStats);
|
StreamingReporterBase::testRunEnded(_testRunStats);
|
||||||
}
|
}
|
||||||
void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {
|
void ConsoleReporter::testRunStarting(TestRunInfo const& _testRunInfo) {
|
||||||
StreamingReporterBase::testRunStarting(_testInfo);
|
StreamingReporterBase::testRunStarting(_testRunInfo);
|
||||||
if ( m_config->testSpec().hasFilters() ) {
|
if ( m_config->testSpec().hasFilters() ) {
|
||||||
m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
|
m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
|
||||||
<< m_config->testSpec() << '\n';
|
<< m_config->testSpec() << '\n';
|
||||||
@ -9253,8 +9273,7 @@ namespace Catch {
|
|||||||
namespace {
|
namespace {
|
||||||
struct BySectionInfo {
|
struct BySectionInfo {
|
||||||
BySectionInfo( SectionInfo const& other ): m_other( other ) {}
|
BySectionInfo( SectionInfo const& other ): m_other( other ) {}
|
||||||
BySectionInfo( BySectionInfo const& other ):
|
BySectionInfo( BySectionInfo const& other ) = default;
|
||||||
m_other( other.m_other ) {}
|
|
||||||
bool operator()(
|
bool operator()(
|
||||||
Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
|
Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
|
||||||
node ) const {
|
node ) const {
|
||||||
@ -9879,8 +9898,8 @@ namespace Catch {
|
|||||||
return "Outputs listings as JSON. Test listing is Work-in-Progress!";
|
return "Outputs listings as JSON. Test listing is Work-in-Progress!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonReporter::testRunStarting( TestRunInfo const& testInfo ) {
|
void JsonReporter::testRunStarting( TestRunInfo const& runInfo ) {
|
||||||
StreamingReporterBase::testRunStarting( testInfo );
|
StreamingReporterBase::testRunStarting( runInfo );
|
||||||
endListing();
|
endListing();
|
||||||
|
|
||||||
assert( isInside( Writer::Object ) );
|
assert( isInside( Writer::Object ) );
|
||||||
@ -10178,7 +10197,7 @@ namespace Catch {
|
|||||||
|
|
||||||
static void normalizeNamespaceMarkers(std::string& str) {
|
static void normalizeNamespaceMarkers(std::string& str) {
|
||||||
std::size_t pos = str.find( "::" );
|
std::size_t pos = str.find( "::" );
|
||||||
while ( pos != str.npos ) {
|
while ( pos != std::string::npos ) {
|
||||||
str.replace( pos, 2, "." );
|
str.replace( pos, 2, "." );
|
||||||
pos += 1;
|
pos += 1;
|
||||||
pos = str.find( "::", pos );
|
pos = str.find( "::", pos );
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
// Catch v3.5.2
|
// Catch v3.5.3
|
||||||
// Generated: 2024-01-15 14:06:34.036475
|
// Generated: 2024-03-01 22:05:55.031514
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// 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.
|
||||||
@ -114,14 +114,14 @@
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
|
|
||||||
# define CATCH_CPP14_OR_GREATER
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
# define CATCH_CPP17_OR_GREATER
|
# define CATCH_CPP17_OR_GREATER
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||||
|
# define CATCH_CPP20_OR_GREATER
|
||||||
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 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
|
||||||
@ -762,8 +762,8 @@ namespace Catch {
|
|||||||
constexpr const_iterator end() const { return m_start + m_size; }
|
constexpr const_iterator end() const { return m_start + m_size; }
|
||||||
|
|
||||||
|
|
||||||
friend std::string& operator += (std::string& lhs, StringRef sr);
|
friend std::string& operator += (std::string& lhs, StringRef rhs);
|
||||||
friend std::ostream& operator << (std::ostream& os, StringRef sr);
|
friend std::ostream& operator << (std::ostream& os, StringRef str);
|
||||||
friend std::string operator+(StringRef lhs, StringRef rhs);
|
friend std::string operator+(StringRef lhs, StringRef rhs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2696,11 +2696,11 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<signed char> {
|
struct StringMaker<signed char> {
|
||||||
static std::string convert(signed char c);
|
static std::string convert(signed char value);
|
||||||
};
|
};
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<unsigned char> {
|
struct StringMaker<unsigned char> {
|
||||||
static std::string convert(unsigned char c);
|
static std::string convert(unsigned char value);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@ -5147,6 +5147,86 @@ namespace Detail {
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* Why does decomposing look the way it does:
|
||||||
|
*
|
||||||
|
* Conceptually, decomposing is simple. We change `REQUIRE( a == b )` into
|
||||||
|
* `Decomposer{} <= a == b`, so that `Decomposer{} <= a` is evaluated first,
|
||||||
|
* and our custom operator is used for `a == b`, because `a` is transformed
|
||||||
|
* into `ExprLhs<T&>` and then into `BinaryExpr<T&, U&>`.
|
||||||
|
*
|
||||||
|
* In practice, decomposing ends up a mess, because we have to support
|
||||||
|
* various fun things.
|
||||||
|
*
|
||||||
|
* 1) Types that are only comparable with literal 0, and they do this by
|
||||||
|
* comparing against a magic type with pointer constructor and deleted
|
||||||
|
* other constructors. Example: `REQUIRE((a <=> b) == 0)` in libstdc++
|
||||||
|
*
|
||||||
|
* 2) Types that are only comparable with literal 0, and they do this by
|
||||||
|
* comparing against a magic type with consteval integer constructor.
|
||||||
|
* Example: `REQUIRE((a <=> b) == 0)` in current MSVC STL.
|
||||||
|
*
|
||||||
|
* 3) Types that have no linkage, and so we cannot form a reference to
|
||||||
|
* them. Example: some implementations of traits.
|
||||||
|
*
|
||||||
|
* 4) Starting with C++20, when the compiler sees `a == b`, it also uses
|
||||||
|
* `b == a` when constructing the overload set. For us this means that
|
||||||
|
* when the compiler handles `ExprLhs<T> == b`, it also tries to resolve
|
||||||
|
* the overload set for `b == ExprLhs<T>`.
|
||||||
|
*
|
||||||
|
* To accomodate these use cases, decomposer ended up rather complex.
|
||||||
|
*
|
||||||
|
* 1) These types are handled by adding SFINAE overloads to our comparison
|
||||||
|
* operators, checking whether `T == U` are comparable with the given
|
||||||
|
* operator, and if not, whether T (or U) are comparable with literal 0.
|
||||||
|
* If yes, the overload compares T (or U) with 0 literal inline in the
|
||||||
|
* definition.
|
||||||
|
*
|
||||||
|
* Note that for extra correctness, we check that the other type is
|
||||||
|
* either an `int` (literal 0 is captured as `int` by templates), or
|
||||||
|
* a `long` (some platforms use 0L for `NULL` and we want to support
|
||||||
|
* that for pointer comparisons).
|
||||||
|
*
|
||||||
|
* 2) For these types, `is_foo_comparable<T, int>` is true, but letting
|
||||||
|
* them fall into the overload that actually does `T == int` causes
|
||||||
|
* compilation error. Handling them requires that the decomposition
|
||||||
|
* is `constexpr`, so that P2564R3 applies and the `consteval` from
|
||||||
|
* their accompanying magic type is propagated through the `constexpr`
|
||||||
|
* call stack.
|
||||||
|
*
|
||||||
|
* However this is not enough to handle these types automatically,
|
||||||
|
* because our default is to capture types by reference, to avoid
|
||||||
|
* runtime copies. While these references cannot become dangling,
|
||||||
|
* they outlive the constexpr context and thus the default capture
|
||||||
|
* path cannot be actually constexpr.
|
||||||
|
*
|
||||||
|
* The solution is to capture these types by value, by explicitly
|
||||||
|
* specializing `Catch::capture_by_value` for them. Catch2 provides
|
||||||
|
* specialization for `std::foo_ordering`s, but users can specialize
|
||||||
|
* the trait for their own types as well.
|
||||||
|
*
|
||||||
|
* 3) If a type has no linkage, we also cannot capture it by reference.
|
||||||
|
* The solution is once again to capture them by value. We handle
|
||||||
|
* the common cases by using `std::is_arithmetic` as the default
|
||||||
|
* for `Catch::capture_by_value`, but that is only a some-effort
|
||||||
|
* heuristic. But as with 2), users can specialize `capture_by_value`
|
||||||
|
* for their own types as needed.
|
||||||
|
*
|
||||||
|
* 4) To support C++20 and make the SFINAE on our decomposing operators
|
||||||
|
* work, the SFINAE has to happen in return type, rather than in
|
||||||
|
* a template type. This is due to our use of logical type traits
|
||||||
|
* (`conjunction`/`disjunction`/`negation`), that we use to workaround
|
||||||
|
* an issue in older (9-) versions of GCC. I still blame C++20 for
|
||||||
|
* this, because without the comparison order switching, the logical
|
||||||
|
* traits could still be used in template type.
|
||||||
|
*
|
||||||
|
* There are also other side concerns, e.g. supporting both `REQUIRE(a)`
|
||||||
|
* and `REQUIRE(a == b)`, or making `REQUIRE_THAT(a, IsEqual(b))` slot
|
||||||
|
* nicely into the same expression handling logic, but these are rather
|
||||||
|
* straightforward and add only a bit of complexity (e.g. common base
|
||||||
|
* class for decomposed expressions).
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||||
@ -5164,8 +5244,33 @@ namespace Detail {
|
|||||||
# pragma GCC diagnostic ignored "-Wsign-compare"
|
# pragma GCC diagnostic ignored "-Wsign-compare"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CPP20_OR_GREATER) && __has_include(<compare>)
|
||||||
|
# include <compare>
|
||||||
|
# if defined( __cpp_lib_three_way_comparison ) && \
|
||||||
|
__cpp_lib_three_way_comparison >= 201907L
|
||||||
|
# define CATCH_CONFIG_CPP20_COMPARE_OVERLOADS
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
// Note: There is nothing that stops us from extending this,
|
||||||
|
// e.g. to `std::is_scalar`, but the more encompassing
|
||||||
|
// traits are usually also more expensive. For now we
|
||||||
|
// keep this as it used to be and it can be changed later.
|
||||||
|
template <typename T>
|
||||||
|
struct capture_by_value
|
||||||
|
: std::integral_constant<bool, std::is_arithmetic<T>{}> {};
|
||||||
|
|
||||||
|
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
|
||||||
|
template <>
|
||||||
|
struct capture_by_value<std::strong_ordering> : std::true_type {};
|
||||||
|
template <>
|
||||||
|
struct capture_by_value<std::weak_ordering> : std::true_type {};
|
||||||
|
template <>
|
||||||
|
struct capture_by_value<std::partial_ordering> : std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct always_false : std::false_type {};
|
struct always_false : std::false_type {};
|
||||||
|
|
||||||
@ -5174,11 +5279,12 @@ namespace Catch {
|
|||||||
bool m_result;
|
bool m_result;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
|
constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
|
||||||
auto getResult() const -> bool { return m_result; }
|
constexpr auto getResult() const -> bool { return m_result; }
|
||||||
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
|
//! This function **has** to be overriden by the derived class.
|
||||||
|
virtual void streamReconstructedExpression( std::ostream& os ) const;
|
||||||
|
|
||||||
ITransientExpression( bool isBinaryExpression, bool result )
|
constexpr ITransientExpression( bool isBinaryExpression, bool result )
|
||||||
: m_isBinaryExpression( isBinaryExpression ),
|
: m_isBinaryExpression( isBinaryExpression ),
|
||||||
m_result( result )
|
m_result( result )
|
||||||
{}
|
{}
|
||||||
@ -5189,7 +5295,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// We don't actually need a virtual destructor, but many static analysers
|
// We don't actually need a virtual destructor, but many static analysers
|
||||||
// complain if it's not here :-(
|
// complain if it's not here :-(
|
||||||
virtual ~ITransientExpression(); // = default;
|
virtual ~ITransientExpression() = default;
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
|
friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
|
||||||
expr.streamReconstructedExpression(out);
|
expr.streamReconstructedExpression(out);
|
||||||
@ -5211,7 +5317,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
|
constexpr BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
|
||||||
: ITransientExpression{ true, comparisonResult },
|
: ITransientExpression{ true, comparisonResult },
|
||||||
m_lhs( lhs ),
|
m_lhs( lhs ),
|
||||||
m_op( op ),
|
m_op( op ),
|
||||||
@ -5284,7 +5390,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit UnaryExpr( LhsT lhs )
|
explicit constexpr UnaryExpr( LhsT lhs )
|
||||||
: ITransientExpression{ false, static_cast<bool>(lhs) },
|
: ITransientExpression{ false, static_cast<bool>(lhs) },
|
||||||
m_lhs( lhs )
|
m_lhs( lhs )
|
||||||
{}
|
{}
|
||||||
@ -5295,30 +5401,30 @@ namespace Catch {
|
|||||||
class ExprLhs {
|
class ExprLhs {
|
||||||
LhsT m_lhs;
|
LhsT m_lhs;
|
||||||
public:
|
public:
|
||||||
explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
|
explicit constexpr ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
|
||||||
|
|
||||||
#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
|
#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
||||||
Detail::negation<std::is_arithmetic< \
|
Detail::negation<capture_by_value< \
|
||||||
std::remove_reference_t<RhsT>>>>::value, \
|
std::remove_reference_t<RhsT>>>>::value, \
|
||||||
BinaryExpr<LhsT, RhsT const&>> { \
|
BinaryExpr<LhsT, RhsT const&>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
||||||
std::is_arithmetic<RhsT>>::value, \
|
capture_by_value<RhsT>>::value, \
|
||||||
BinaryExpr<LhsT, RhsT>> { \
|
BinaryExpr<LhsT, RhsT>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction< \
|
Detail::conjunction< \
|
||||||
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
||||||
@ -5332,7 +5438,7 @@ namespace Catch {
|
|||||||
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction< \
|
Detail::conjunction< \
|
||||||
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
||||||
@ -5350,28 +5456,29 @@ namespace Catch {
|
|||||||
|
|
||||||
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
|
#undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
|
||||||
|
|
||||||
|
|
||||||
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
|
#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
||||||
Detail::negation<std::is_arithmetic< \
|
Detail::negation<capture_by_value< \
|
||||||
std::remove_reference_t<RhsT>>>>::value, \
|
std::remove_reference_t<RhsT>>>>::value, \
|
||||||
BinaryExpr<LhsT, RhsT const&>> { \
|
BinaryExpr<LhsT, RhsT const&>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
|
||||||
std::is_arithmetic<RhsT>>::value, \
|
capture_by_value<RhsT>>::value, \
|
||||||
BinaryExpr<LhsT, RhsT>> { \
|
BinaryExpr<LhsT, RhsT>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction< \
|
Detail::conjunction< \
|
||||||
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
||||||
@ -5383,7 +5490,7 @@ namespace Catch {
|
|||||||
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
Detail::conjunction< \
|
Detail::conjunction< \
|
||||||
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
|
||||||
@ -5404,16 +5511,16 @@ namespace Catch {
|
|||||||
|
|
||||||
#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
|
#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
|
||||||
->std::enable_if_t< \
|
->std::enable_if_t< \
|
||||||
!std::is_arithmetic<std::remove_reference_t<RhsT>>::value, \
|
!capture_by_value<std::remove_reference_t<RhsT>>::value, \
|
||||||
BinaryExpr<LhsT, RhsT const&>> { \
|
BinaryExpr<LhsT, RhsT const&>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
} \
|
} \
|
||||||
template <typename RhsT> \
|
template <typename RhsT> \
|
||||||
friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
|
||||||
->std::enable_if_t<std::is_arithmetic<RhsT>::value, \
|
->std::enable_if_t<capture_by_value<RhsT>::value, \
|
||||||
BinaryExpr<LhsT, RhsT>> { \
|
BinaryExpr<LhsT, RhsT>> { \
|
||||||
return { \
|
return { \
|
||||||
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
|
||||||
@ -5439,19 +5546,23 @@ namespace Catch {
|
|||||||
"wrap the expression inside parentheses, or decompose it");
|
"wrap the expression inside parentheses, or decompose it");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
||||||
return UnaryExpr<LhsT>{ m_lhs };
|
return UnaryExpr<LhsT>{ m_lhs };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Decomposer {
|
struct Decomposer {
|
||||||
template<typename T, std::enable_if_t<!std::is_arithmetic<std::remove_reference_t<T>>::value, int> = 0>
|
template <typename T,
|
||||||
friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
|
std::enable_if_t<
|
||||||
|
!capture_by_value<std::remove_reference_t<T>>::value,
|
||||||
|
int> = 0>
|
||||||
|
constexpr friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
|
||||||
return ExprLhs<const T&>{ lhs };
|
return ExprLhs<const T&>{ lhs };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
|
template <typename T,
|
||||||
friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
|
std::enable_if_t<capture_by_value<T>::value, int> = 0>
|
||||||
|
constexpr friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
|
||||||
return ExprLhs<T>{ value };
|
return ExprLhs<T>{ value };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -5571,7 +5682,7 @@ namespace Catch {
|
|||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||||
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); /* NOLINT(bugprone-chained-comparison) */ \
|
||||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
@ -5786,7 +5897,9 @@ namespace Catch {
|
|||||||
namespace Detail {
|
namespace Detail {
|
||||||
// Intentionally without linkage, as it should only be used as a dummy
|
// Intentionally without linkage, as it should only be used as a dummy
|
||||||
// symbol for static analysis.
|
// symbol for static analysis.
|
||||||
int GetNewSectionHint();
|
// The arguments are used as a dummy for checking warnings in the passed
|
||||||
|
// expressions.
|
||||||
|
int GetNewSectionHint( StringRef, const char* const = nullptr );
|
||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
@ -5797,7 +5910,8 @@ namespace Catch {
|
|||||||
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
||||||
if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
|
if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
|
||||||
catchInternalSectionHint, \
|
catchInternalSectionHint, \
|
||||||
catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
|
catchInternalSectionHint = \
|
||||||
|
Catch::Detail::GetNewSectionHint(__VA_ARGS__); \
|
||||||
catchInternalPreviousSectionHint == __LINE__ ) \
|
catchInternalPreviousSectionHint == __LINE__ ) \
|
||||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||||
|
|
||||||
@ -5807,7 +5921,8 @@ namespace Catch {
|
|||||||
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
||||||
if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
|
if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
|
||||||
catchInternalSectionHint, \
|
catchInternalSectionHint, \
|
||||||
catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
|
catchInternalSectionHint = Catch::Detail::GetNewSectionHint( \
|
||||||
|
( Catch::ReusableStringStream() << __VA_ARGS__ ).str()); \
|
||||||
catchInternalPreviousSectionHint == __LINE__ ) \
|
catchInternalPreviousSectionHint == __LINE__ ) \
|
||||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||||
|
|
||||||
@ -5929,7 +6044,7 @@ struct AutoReg : Detail::NonCopyable {
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
struct DummyUse {
|
struct DummyUse {
|
||||||
DummyUse( void ( * )( int ) );
|
DummyUse( void ( * )( int ), Catch::NameAndTags const& );
|
||||||
};
|
};
|
||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
@ -5941,18 +6056,18 @@ namespace Catch {
|
|||||||
// tests can compile. The redefined `TEST_CASE` shadows this with param.
|
// tests can compile. The redefined `TEST_CASE` shadows this with param.
|
||||||
static int catchInternalSectionHint = 0;
|
static int catchInternalSectionHint = 0;
|
||||||
|
|
||||||
# define INTERNAL_CATCH_TESTCASE2( fname ) \
|
# define INTERNAL_CATCH_TESTCASE2( fname, ... ) \
|
||||||
static void fname( int ); \
|
static void fname( int ); \
|
||||||
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 \
|
||||||
static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
|
static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
|
||||||
dummyUser )( &(fname) ); \
|
dummyUser )( &(fname), Catch::NameAndTags{ __VA_ARGS__ } ); \
|
||||||
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
|
||||||
static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
|
static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
|
||||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||||
# define INTERNAL_CATCH_TESTCASE( ... ) \
|
# define INTERNAL_CATCH_TESTCASE( ... ) \
|
||||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) )
|
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ), __VA_ARGS__ )
|
||||||
|
|
||||||
|
|
||||||
#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
|
#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
|
||||||
@ -6935,7 +7050,7 @@ namespace Catch {
|
|||||||
struct TestCaseInfo : Detail::NonCopyable {
|
struct TestCaseInfo : Detail::NonCopyable {
|
||||||
|
|
||||||
TestCaseInfo(StringRef _className,
|
TestCaseInfo(StringRef _className,
|
||||||
NameAndTags const& _tags,
|
NameAndTags const& _nameAndTags,
|
||||||
SourceLineInfo const& _lineInfo);
|
SourceLineInfo const& _lineInfo);
|
||||||
|
|
||||||
bool isHidden() const;
|
bool isHidden() const;
|
||||||
@ -7148,7 +7263,7 @@ namespace Catch {
|
|||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 3
|
#define CATCH_VERSION_MAJOR 3
|
||||||
#define CATCH_VERSION_MINOR 5
|
#define CATCH_VERSION_MINOR 5
|
||||||
#define CATCH_VERSION_PATCH 2
|
#define CATCH_VERSION_PATCH 3
|
||||||
|
|
||||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
@ -7847,9 +7962,8 @@ namespace Catch {
|
|||||||
struct ExtendedMultResult {
|
struct ExtendedMultResult {
|
||||||
T upper;
|
T upper;
|
||||||
T lower;
|
T lower;
|
||||||
friend bool operator==( ExtendedMultResult const& lhs,
|
bool operator==( ExtendedMultResult const& rhs ) const {
|
||||||
ExtendedMultResult const& rhs ) {
|
return upper == rhs.upper && lower == rhs.lower;
|
||||||
return lhs.upper == rhs.upper && lhs.lower == rhs.lower;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -9322,7 +9436,7 @@ namespace Catch {
|
|||||||
|
|
||||||
std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
|
std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
|
||||||
|
|
||||||
EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
|
EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<StringRef> parseEnums( StringRef enums );
|
std::vector<StringRef> parseEnums( StringRef enums );
|
||||||
@ -9795,7 +9909,7 @@ namespace Catch {
|
|||||||
JsonObjectWriter( std::ostream& os );
|
JsonObjectWriter( std::ostream& os );
|
||||||
JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
|
JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
|
||||||
|
|
||||||
JsonObjectWriter( JsonObjectWriter&& source );
|
JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
|
||||||
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
||||||
|
|
||||||
~JsonObjectWriter();
|
~JsonObjectWriter();
|
||||||
@ -9814,7 +9928,7 @@ namespace Catch {
|
|||||||
JsonArrayWriter( std::ostream& os );
|
JsonArrayWriter( std::ostream& os );
|
||||||
JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
|
JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
|
||||||
|
|
||||||
JsonArrayWriter( JsonArrayWriter&& source );
|
JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
|
||||||
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
||||||
|
|
||||||
~JsonArrayWriter();
|
~JsonArrayWriter();
|
||||||
@ -13454,7 +13568,7 @@ namespace Catch {
|
|||||||
|
|
||||||
void assertionEnded( AssertionStats const& assertionStats ) override;
|
void assertionEnded( AssertionStats const& assertionStats ) override;
|
||||||
void sectionEnded( SectionStats const& sectionStats ) override;
|
void sectionEnded( SectionStats const& sectionStats ) override;
|
||||||
void testCasePartialEnded(TestCaseStats const& testInfo, uint64_t partNumber) override;
|
void testCasePartialEnded(TestCaseStats const& testStats, uint64_t partNumber) override;
|
||||||
void testCaseEnded( TestCaseStats const& testCaseStats ) override;
|
void testCaseEnded( TestCaseStats const& testCaseStats ) override;
|
||||||
void testRunEnded( TestRunStats const& testRunStats ) override;
|
void testRunEnded( TestRunStats const& testRunStats ) override;
|
||||||
|
|
||||||
@ -13622,7 +13736,7 @@ namespace Catch {
|
|||||||
xml.endElement();
|
xml.endElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeRun( TestRunNode const& groupNode );
|
void writeRun( TestRunNode const& runNode );
|
||||||
|
|
||||||
void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
|
void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
|
||||||
|
|
||||||
@ -13707,8 +13821,8 @@ namespace Catch {
|
|||||||
return "Reports test results as TeamCity service messages"s;
|
return "Reports test results as TeamCity service messages"s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testRunStarting( TestRunInfo const& groupInfo ) override;
|
void testRunStarting( TestRunInfo const& runInfo ) override;
|
||||||
void testRunEnded( TestRunStats const& testGroupStats ) override;
|
void testRunEnded( TestRunStats const& runStats ) override;
|
||||||
|
|
||||||
|
|
||||||
void assertionEnded(AssertionStats const& assertionStats) override;
|
void assertionEnded(AssertionStats const& assertionStats) override;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
project(
|
project(
|
||||||
'catch2',
|
'catch2',
|
||||||
'cpp',
|
'cpp',
|
||||||
version: '3.5.2', # CML version placeholder, don't delete
|
version: '3.5.3', # CML version placeholder, don't delete
|
||||||
license: 'BSL-1.0',
|
license: 'BSL-1.0',
|
||||||
meson_version: '>=0.54.1',
|
meson_version: '>=0.54.1',
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 3, 5, 2, "", 0 );
|
static Version version( 3, 5, 3, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 3
|
#define CATCH_VERSION_MAJOR 3
|
||||||
#define CATCH_VERSION_MINOR 5
|
#define CATCH_VERSION_MINOR 5
|
||||||
#define CATCH_VERSION_PATCH 2
|
#define CATCH_VERSION_PATCH 3
|
||||||
|
|
||||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
Loading…
Reference in New Issue
Block a user