mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[upstream_utils] Upgrade to Catch2 3.14.0 (#8757)
This commit is contained in:
1
thirdparty/catch2/extras/CatchAddTests.cmake
vendored
1
thirdparty/catch2/extras/CatchAddTests.cmake
vendored
@@ -146,6 +146,7 @@ function(catch_discover_tests_impl)
|
||||
|
||||
# Exit early if no tests are detected
|
||||
if(num_tests STREQUAL "0")
|
||||
file(WRITE "${_CTEST_FILE}" "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -92,6 +92,10 @@ namespace Catch {
|
||||
lhs.customOptions == rhs.customOptions;
|
||||
}
|
||||
|
||||
bool operator==( PathFilter const& lhs, PathFilter const& rhs ) {
|
||||
return lhs.type == rhs.type && lhs.filter == rhs.filter;
|
||||
}
|
||||
|
||||
Config::Config( ConfigData const& data ):
|
||||
m_data( data ) {
|
||||
// We need to trim filter specs to avoid trouble with superfluous
|
||||
@@ -101,9 +105,6 @@ namespace Catch {
|
||||
for (auto& elem : m_data.testsOrTags) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
for (auto& elem : m_data.sectionsToRun) {
|
||||
elem = trim(elem);
|
||||
}
|
||||
|
||||
// Insert the default reporter if user hasn't asked for a specific one
|
||||
if ( m_data.reporterSpecifications.empty() ) {
|
||||
@@ -119,6 +120,8 @@ namespace Catch {
|
||||
m_data.reporterSpecifications.push_back( std::move( *parsed ) );
|
||||
}
|
||||
|
||||
// Reading bazel env vars can change some parts of the config data,
|
||||
// so we have to process the bazel env before acting on the config.
|
||||
if ( enableBazelEnvSupport() ) {
|
||||
readBazelEnvVars();
|
||||
}
|
||||
@@ -167,7 +170,8 @@ namespace Catch {
|
||||
bool Config::listListeners() const { return m_data.listListeners; }
|
||||
|
||||
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
std::vector<PathFilter> const& Config::getPathFilters() const { return m_data.pathFilters; }
|
||||
bool Config::useNewFilterBehaviour() const { return m_data.useNewPathFilteringBehaviour; }
|
||||
|
||||
std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
|
||||
return m_data.reporterSpecifications;
|
||||
@@ -183,6 +187,8 @@ namespace Catch {
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
std::string const& Config::getExitGuardFilePath() const { return m_data.prematureExitGuardFilePath; }
|
||||
|
||||
// IConfig interface
|
||||
bool Config::allowThrows() const { return !m_data.noThrow; }
|
||||
StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
@@ -193,6 +199,9 @@ namespace Catch {
|
||||
bool Config::warnAboutUnmatchedTestSpecs() const {
|
||||
return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
|
||||
}
|
||||
bool Config::warnAboutInfiniteGenerators() const {
|
||||
return !!( m_data.warnings & WarnAbout::InfiniteGenerator );
|
||||
}
|
||||
bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
|
||||
ShowDurations Config::showDurations() const { return m_data.showDurations; }
|
||||
double Config::minDuration() const { return m_data.minDuration; }
|
||||
@@ -244,6 +253,26 @@ namespace Catch {
|
||||
m_data.shardCount = bazelShardOptions->shardCount;
|
||||
}
|
||||
}
|
||||
|
||||
const auto bazelExitGuardFile = Detail::getEnv( "TEST_PREMATURE_EXIT_FILE" );
|
||||
if (bazelExitGuardFile) {
|
||||
m_data.prematureExitGuardFilePath = bazelExitGuardFile;
|
||||
}
|
||||
|
||||
const auto bazelRandomSeed = Detail::getEnv( "TEST_RANDOM_SEED" );
|
||||
if ( bazelRandomSeed ) {
|
||||
auto parsedSeed = parseUInt( bazelRandomSeed, 0 );
|
||||
if ( !parsedSeed ) {
|
||||
// Currently we handle issues with parsing other Bazel Env
|
||||
// options by warning and ignoring the issue. So we do the
|
||||
// same for random seed option.
|
||||
Catch::cerr()
|
||||
<< "Warning: could not parse 'TEST_RANDOM_SEED' ('"
|
||||
<< bazelRandomSeed << "') as proper seed.\n";
|
||||
} else {
|
||||
m_data.rngSeed = *parsedSeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
@@ -19,28 +19,28 @@ namespace Catch {
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
|
||||
m_info( CATCH_MOVE(builder.m_info) ) {
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
m_messageId( builder.m_info.sequence ) {
|
||||
MessageInfo info( CATCH_MOVE( builder.m_info ) );
|
||||
info.message = builder.m_stream.str();
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
|
||||
}
|
||||
|
||||
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
||||
m_info( CATCH_MOVE( old.m_info ) ) {
|
||||
m_messageId( old.m_messageId ) {
|
||||
old.m_moved = true;
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !m_moved ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
|
||||
}
|
||||
|
||||
|
||||
Capturer::Capturer( StringRef macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
ResultWas::OfType resultType,
|
||||
StringRef names ):
|
||||
m_resultCapture( getResultCapture() ) {
|
||||
StringRef names,
|
||||
bool isScoped):
|
||||
m_isScoped(isScoped) {
|
||||
auto trimmed = [&] (size_t start, size_t end) {
|
||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||
++start;
|
||||
@@ -86,8 +86,8 @@ namespace Catch {
|
||||
case ',':
|
||||
if (start != pos && openings.empty()) {
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
|
||||
m_messages.back().message += " := ";
|
||||
m_messages.back().message += trimmed(start, pos);
|
||||
m_messages.back().message += " := "_sr;
|
||||
start = pos;
|
||||
}
|
||||
break;
|
||||
@@ -96,20 +96,26 @@ namespace Catch {
|
||||
}
|
||||
assert(openings.empty() && "Mismatched openings");
|
||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
|
||||
m_messages.back().message += " := ";
|
||||
m_messages.back().message += trimmed(start, names.size() - 1);
|
||||
m_messages.back().message += " := "_sr;
|
||||
}
|
||||
Capturer::~Capturer() {
|
||||
assert( m_captured == m_messages.size() );
|
||||
for ( size_t i = 0; i < m_captured; ++i ) {
|
||||
m_resultCapture.popScopedMessage( m_messages[i] );
|
||||
if ( m_isScoped ) {
|
||||
for ( auto const& message : m_messages ) {
|
||||
IResultCapture::popScopedMessage( message.sequence );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Capturer::captureValue( size_t index, std::string const& value ) {
|
||||
assert( index < m_messages.size() );
|
||||
m_messages[index].message += value;
|
||||
m_resultCapture.pushScopedMessage( m_messages[index] );
|
||||
if ( m_isScoped ) {
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||
} else {
|
||||
IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||
}
|
||||
m_captured++;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,6 @@ namespace Catch {
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
cleanUpContext();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
@@ -140,6 +142,50 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
// Creates empty file at path. The path must be writable, we do not
|
||||
// try to create directories in path because that's hard in C++14.
|
||||
void setUpGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
#if defined( _MSC_VER )
|
||||
std::FILE* file = nullptr;
|
||||
if ( fopen_s( &file, guardFilePath.c_str(), "w" ) ) {
|
||||
char msgBuffer[100];
|
||||
const auto err = errno;
|
||||
std::string errMsg;
|
||||
if ( !strerror_s( msgBuffer, err ) ) {
|
||||
errMsg = msgBuffer;
|
||||
} else {
|
||||
errMsg = "Could not translate errno to a string";
|
||||
}
|
||||
|
||||
#else
|
||||
std::FILE* file = std::fopen( guardFilePath.c_str(), "w" );
|
||||
if ( !file ) {
|
||||
const auto err = errno;
|
||||
const char* errMsg = std::strerror( err );
|
||||
#endif
|
||||
|
||||
CATCH_RUNTIME_ERROR( "Could not open the exit guard file '"
|
||||
<< guardFilePath << "' because '"
|
||||
<< errMsg << "' (" << err << ')' );
|
||||
}
|
||||
const int ret = std::fclose( file );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when closing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
// Removes file at path. Assuming we created it in setUpGuardFile.
|
||||
void tearDownGuardFile( std::string const& guardFilePath ) {
|
||||
if ( !guardFilePath.empty() ) {
|
||||
const int ret = std::remove( guardFilePath.c_str() );
|
||||
CATCH_ENFORCE(
|
||||
ret == 0,
|
||||
"Error when removing the exit guard file: " << ret );
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Session::Session() {
|
||||
@@ -258,6 +304,7 @@ namespace Catch {
|
||||
static_cast<void>(std::getchar());
|
||||
}
|
||||
int exitCode = runInternal();
|
||||
|
||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
|
||||
static_cast<void>(std::getchar());
|
||||
@@ -298,6 +345,10 @@ namespace Catch {
|
||||
CATCH_TRY {
|
||||
config(); // Force config to be constructed
|
||||
|
||||
// We need to retrieve potential Bazel config with the full Config
|
||||
// constructor, so we have to create the guard file after it is created.
|
||||
setUpGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
if (m_configData.filenamesAsTags) {
|
||||
@@ -327,9 +378,12 @@ namespace Catch {
|
||||
TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
|
||||
auto const totals = tests.execute();
|
||||
|
||||
// If we got here, running the tests finished normally-enough.
|
||||
// They might've failed, but that would've been reported elsewhere.
|
||||
tearDownGuardFile( m_config->getExitGuardFilePath() );
|
||||
|
||||
if ( tests.hadUnmatchedTestSpecs()
|
||||
&& m_config->warnAboutUnmatchedTestSpecs() ) {
|
||||
// UnmatchedTestSpecExitCode
|
||||
return UnmatchedTestSpecExitCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,39 +57,69 @@ namespace Detail {
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
std::size_t catch_strnlen( const char* str, std::size_t n ) {
|
||||
auto ret = std::char_traits<char>::find( str, n, '\0' );
|
||||
if ( ret != nullptr ) { return static_cast<std::size_t>( ret - str ); }
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string formatTimeT(std::time_t time) {
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
const auto err = gmtime_s( &timeInfo, &time );
|
||||
if ( err ) {
|
||||
return "gmtime from provided timepoint has failed. This "
|
||||
"happens e.g. with pre-1970 dates using Microsoft libc";
|
||||
}
|
||||
#else
|
||||
std::tm* timeInfo = std::gmtime( &time );
|
||||
#endif
|
||||
|
||||
auto const timeStampSize = sizeof( "2017-01-16T17:06:45Z" );
|
||||
char timeStamp[timeStampSize];
|
||||
const char* const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::strftime( timeStamp, timeStampSize, fmt, &timeInfo );
|
||||
#else
|
||||
std::strftime( timeStamp, timeStampSize, fmt, timeInfo );
|
||||
#endif
|
||||
return std::string( timeStamp, timeStampSize - 1 );
|
||||
}
|
||||
|
||||
std::string convertIntoString(StringRef string, bool escapeInvisibles) {
|
||||
std::string ret;
|
||||
// This is enough for the "don't escape invisibles" case, and a good
|
||||
// lower bound on the "escape invisibles" case.
|
||||
ret.reserve(string.size() + 2);
|
||||
ret.reserve( string.size() + 2 );
|
||||
|
||||
if (!escapeInvisibles) {
|
||||
if ( !escapeInvisibles ) {
|
||||
ret += '"';
|
||||
ret += string;
|
||||
ret += '"';
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t last_start = 0;
|
||||
auto write_to = [&]( size_t idx ) {
|
||||
if ( last_start < idx ) {
|
||||
ret += string.substr( last_start, idx - last_start );
|
||||
}
|
||||
last_start = idx + 1;
|
||||
};
|
||||
|
||||
ret += '"';
|
||||
for (char c : string) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
ret.append("\\r");
|
||||
break;
|
||||
case '\n':
|
||||
ret.append("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
ret.append("\\t");
|
||||
break;
|
||||
case '\f':
|
||||
ret.append("\\f");
|
||||
break;
|
||||
default:
|
||||
ret.push_back(c);
|
||||
break;
|
||||
for ( size_t i = 0; i < string.size(); ++i ) {
|
||||
const char c = string[i];
|
||||
if ( c == '\r' || c == '\n' || c == '\t' || c == '\f' ) {
|
||||
write_to( i );
|
||||
if ( c == '\r' ) { ret.append( "\\r" ); }
|
||||
if ( c == '\n' ) { ret.append( "\\n" ); }
|
||||
if ( c == '\t' ) { ret.append( "\\t" ); }
|
||||
if ( c == '\f' ) { ret.append( "\\f" ); }
|
||||
}
|
||||
}
|
||||
write_to( string.size() );
|
||||
ret += '"';
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 10, 0, "", 0 );
|
||||
static Version version( 3, 14, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
|
||||
namespace Catch {
|
||||
@@ -17,14 +15,6 @@ namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
[[noreturn]]
|
||||
void throw_generator_exception(char const* msg) {
|
||||
Catch::throw_exception(GeneratorException{ msg });
|
||||
}
|
||||
} // end namespace Detail
|
||||
|
||||
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
|
||||
|
||||
IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
|
||||
|
||||
@@ -37,5 +37,10 @@ namespace Catch {
|
||||
m_current_number = m_pimpl->dist( m_pimpl->rng );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RandomFloatingGenerator<long double>::isFinite() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
24
thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp
vendored
Normal file
24
thirdparty/catch2/src/main/native/cpp/catch2/generators/catch_generators_throw.cpp
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/generators/catch_generators_throw.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
namespace Detail {
|
||||
|
||||
[[noreturn]]
|
||||
void throw_generator_exception( char const* msg ) {
|
||||
Catch::throw_exception( GeneratorException{ msg } );
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
@@ -7,7 +7,14 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void missingCaptureInstance() {
|
||||
CATCH_INTERNAL_ERROR( "No result capture instance" );
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
IResultCapture::~IResultCapture() = default;
|
||||
}
|
||||
} // namespace Catch
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
@@ -21,6 +23,31 @@ namespace Catch {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GeneratorUntypedBase::skipToNthElementImpl( std::size_t n ) {
|
||||
for ( size_t i = m_currentElementIndex; i < n; ++i ) {
|
||||
bool isValid = next();
|
||||
if ( !isValid ) {
|
||||
Detail::throw_generator_exception(
|
||||
"Coud not jump to Nth element: not enough elements" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratorUntypedBase::skipToNthElement( std::size_t n ) {
|
||||
if ( n < m_currentElementIndex ) {
|
||||
Detail::throw_generator_exception(
|
||||
"Tried to jump generator backwards" );
|
||||
}
|
||||
if ( n == m_currentElementIndex ) { return; }
|
||||
|
||||
skipToNthElementImpl(n);
|
||||
// Fixup tracking after moving the generator forward
|
||||
// * Ensure that the correct element index is set after skipping
|
||||
// * Invalidate cache
|
||||
m_currentElementIndex = n;
|
||||
m_stringReprCache.clear();
|
||||
}
|
||||
|
||||
StringRef GeneratorUntypedBase::currentElementAsString() const {
|
||||
if ( m_stringReprCache.empty() ) {
|
||||
m_stringReprCache = stringifyImpl();
|
||||
@@ -28,5 +55,7 @@ namespace Catch {
|
||||
return m_stringReprCache;
|
||||
}
|
||||
|
||||
bool GeneratorUntypedBase::isFinite() const { return true; }
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
@@ -32,6 +32,9 @@ namespace Catch {
|
||||
} else if ( warning == "UnmatchedTestSpec" ) {
|
||||
config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
} else if ( warning == "InfiniteGenerators" ) {
|
||||
config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::InfiniteGenerator);
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
}
|
||||
|
||||
return ParserResult ::runtimeError(
|
||||
@@ -189,6 +192,19 @@ namespace Catch {
|
||||
config.shardCount = *parsedCount;
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setBenchmarkSamples = [&]( std::string const& samples ) {
|
||||
auto parsedSamples = parseUInt( samples );
|
||||
if ( !parsedSamples ) {
|
||||
return ParserResult::runtimeError(
|
||||
"Could not parse '" + samples + "' as benchmark samples" );
|
||||
}
|
||||
if ( *parsedSamples == 0 ) {
|
||||
return ParserResult::runtimeError(
|
||||
"Benchmark samples must be greater than 0" );
|
||||
}
|
||||
config.benchmarkSamples = *parsedSamples;
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
|
||||
auto const setShardIndex = [&](std::string const& shardIndex) {
|
||||
auto parsedIndex = parseUInt( shardIndex );
|
||||
@@ -200,6 +216,43 @@ namespace Catch {
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
|
||||
auto const setSectionFilter = [&]( std::string const& sectionFilter ) {
|
||||
config.pathFilters.emplace_back( PathFilter::For::Section, trim(sectionFilter) );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const setGeneratorFilter = [&]( std::string const& generatorFilter ) {
|
||||
if (generatorFilter != "*") {
|
||||
// TODO: avoid re-parsing the index?
|
||||
auto parsedIndex = parseUInt( generatorFilter );
|
||||
if ( !parsedIndex ) {
|
||||
return ParserResult::runtimeError( "Could not parse '" +
|
||||
generatorFilter +
|
||||
"' as generator index" );
|
||||
}
|
||||
}
|
||||
config.useNewPathFilteringBehaviour = true;
|
||||
config.pathFilters.emplace_back( PathFilter::For::Generator, trim(generatorFilter) );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
// Copy-capturing other `setFoo` functions enables calling them later,
|
||||
// as the config ref remains valid, but the local lambda vars won't.
|
||||
auto const setPathFilter = [=, &config]( std::string const& pathFilter ) {
|
||||
config.useNewPathFilteringBehaviour = true;
|
||||
if ( pathFilter.size() < 3 ) {
|
||||
return ParserResult::runtimeError(
|
||||
"Path filter '" + pathFilter + "' is too short" );
|
||||
}
|
||||
if ( startsWith( pathFilter, "g:" ) ) {
|
||||
return setGeneratorFilter( pathFilter.substr( 2 ) );
|
||||
}
|
||||
if ( startsWith( pathFilter, "c:" ) ) {
|
||||
return setSectionFilter( pathFilter.substr( 2 ) );
|
||||
}
|
||||
return ParserResult::runtimeError( "Path filter '" + pathFilter +
|
||||
"' has unknown type prefix" );
|
||||
};
|
||||
|
||||
|
||||
auto cli
|
||||
= ExeName( config.processName )
|
||||
| Help( config.showHelp )
|
||||
@@ -245,9 +298,15 @@ namespace Catch {
|
||||
| Opt( config.filenamesAsTags )
|
||||
["-#"]["--filenames-as-tags"]
|
||||
( "adds a tag for the filename" )
|
||||
| Opt( config.sectionsToRun, "section name" )
|
||||
| Opt( accept_many, setSectionFilter, "section name" )
|
||||
["-c"]["--section"]
|
||||
( "specify section to run" )
|
||||
| Opt( accept_many, setGeneratorFilter, "index spec" )
|
||||
["-g"]["--generator-index"]
|
||||
( "specify generator elements to try" )
|
||||
| Opt( accept_many, setPathFilter, "path filter spec" )
|
||||
["-p"]["--path-filter"]
|
||||
( "qualified path filter" )
|
||||
| Opt( setVerbosity, "quiet|normal|high" )
|
||||
["-v"]["--verbosity"]
|
||||
( "set output verbosity" )
|
||||
@@ -265,7 +324,7 @@ namespace Catch {
|
||||
( "list all listeners" )
|
||||
| Opt( setTestOrder, "decl|lex|rand" )
|
||||
["--order"]
|
||||
( "test case order (defaults to decl)" )
|
||||
( "test case order (defaults to rand)" )
|
||||
| Opt( setRngSeed, "'time'|'random-device'|number" )
|
||||
["--rng-seed"]
|
||||
( "set a specific seed for random numbers" )
|
||||
@@ -281,7 +340,7 @@ namespace Catch {
|
||||
| Opt( config.skipBenchmarks)
|
||||
["--skip-benchmarks"]
|
||||
( "disable running benchmarks")
|
||||
| Opt( config.benchmarkSamples, "samples" )
|
||||
| Opt( setBenchmarkSamples, "samples" )
|
||||
["--benchmark-samples"]
|
||||
( "number of samples to collect (default: 100)" )
|
||||
| Opt( config.benchmarkResamples, "resamples" )
|
||||
@@ -305,6 +364,9 @@ namespace Catch {
|
||||
| Opt( config.allowZeroTests )
|
||||
["--allow-running-no-tests"]
|
||||
( "Treat 'No tests run' as a success" )
|
||||
| Opt( config.prematureExitGuardFilePath, "path" )
|
||||
["--premature-exit-guard-file"]
|
||||
( "create a file before running tests and delete it during clean exit" )
|
||||
| Arg( config.testsOrTags, "test name|pattern|tags" )
|
||||
( "which test or tests to use" );
|
||||
|
||||
|
||||
@@ -161,7 +161,13 @@ namespace {
|
||||
#endif // Windows/ ANSI/ None
|
||||
|
||||
|
||||
#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ ) || defined(__FreeBSD__)
|
||||
#if defined( CATCH_PLATFORM_LINUX ) \
|
||||
|| defined( CATCH_PLATFORM_MAC ) \
|
||||
|| defined( __GLIBC__ ) \
|
||||
|| (defined( __FreeBSD__ ) \
|
||||
/* PlayStation platform does not have `isatty()` */ \
|
||||
&& !defined(CATCH_PLATFORM_PLAYSTATION)) \
|
||||
|| defined( CATCH_PLATFORM_QNX )
|
||||
# define CATCH_INTERNAL_HAS_ISATTY
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -6,25 +6,14 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_noncopyable.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
Context* Context::currentContext = nullptr;
|
||||
|
||||
void cleanUpContext() {
|
||||
delete Context::currentContext;
|
||||
Context::currentContext = nullptr;
|
||||
}
|
||||
void Context::createContext() {
|
||||
currentContext = new Context();
|
||||
}
|
||||
Context Context::currentContext;
|
||||
|
||||
Context& getCurrentMutableContext() {
|
||||
if ( !Context::currentContext ) { Context::createContext(); }
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *Context::currentContext;
|
||||
return Context::currentContext;
|
||||
}
|
||||
|
||||
SimplePcg32& sharedRng() {
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
#endif
|
||||
} // namespace Catch
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -86,23 +86,27 @@ namespace Catch {
|
||||
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
|
||||
};
|
||||
|
||||
// Since we do not support multiple instantiations, we put these
|
||||
// into global variables and rely on cleaning them up in outlined
|
||||
// constructors/destructors
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
|
||||
|
||||
|
||||
static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
for (auto const& def : signalDefs) {
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
|
||||
reportFatal(def.name);
|
||||
}
|
||||
}
|
||||
// If its not an exception we care about, pass it along.
|
||||
// If a filter was previously registered, invoke it
|
||||
if (previousTopLevelExceptionFilter) {
|
||||
return previousTopLevelExceptionFilter(ExceptionInfo);
|
||||
}
|
||||
// Otherwise, pass along all exceptions.
|
||||
// This stops us from eating debugger breaks etc.
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Since we do not support multiple instantiations, we put these
|
||||
// into global variables and rely on cleaning them up in outlined
|
||||
// constructors/destructors
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
|
||||
|
||||
|
||||
// For MSVC, we reserve part of the stack memory for handling
|
||||
// memory overflow structured exception.
|
||||
FatalConditionHandler::FatalConditionHandler() {
|
||||
|
||||
@@ -7,20 +7,24 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
#include <catch2/internal/catch_thread_local.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
// Messages are owned by their individual threads, so the counter should
|
||||
// be thread-local as well. Alternative consideration: atomic counter,
|
||||
// so threads don't share IDs and things are easier to debug.
|
||||
static CATCH_INTERNAL_THREAD_LOCAL unsigned int messageIDCounter = 0;
|
||||
}
|
||||
|
||||
MessageInfo::MessageInfo( StringRef _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
ResultWas::OfType _type )
|
||||
: macroName( _macroName ),
|
||||
lineInfo( _lineInfo ),
|
||||
type( _type ),
|
||||
sequence( ++globalCount )
|
||||
sequence( ++messageIDCounter )
|
||||
{}
|
||||
|
||||
// Messages are owned by their individual threads, so the counter should be thread-local as well.
|
||||
// Alternative consideration: atomic, so threads don't share IDs and things are easier to debug.
|
||||
thread_local unsigned int MessageInfo::globalCount = 0;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
@@ -23,16 +24,16 @@ namespace Catch {
|
||||
std::ostringstream m_referenceStream; // Used for copy state/ flags from
|
||||
Detail::Mutex m_mutex;
|
||||
|
||||
auto add() -> std::size_t {
|
||||
auto add() -> std::pair<std::size_t, std::ostringstream*> {
|
||||
Detail::LockGuard _( m_mutex );
|
||||
if( m_unused.empty() ) {
|
||||
m_streams.push_back( Detail::make_unique<std::ostringstream>() );
|
||||
return m_streams.size()-1;
|
||||
return { m_streams.size()-1, m_streams.back().get() };
|
||||
}
|
||||
else {
|
||||
auto index = m_unused.back();
|
||||
m_unused.pop_back();
|
||||
return index;
|
||||
return { index, m_streams[index].get() };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +47,10 @@ namespace Catch {
|
||||
}
|
||||
};
|
||||
|
||||
ReusableStringStream::ReusableStringStream()
|
||||
: m_index( Singleton<StringStreams>::getMutable().add() ),
|
||||
m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
|
||||
{}
|
||||
ReusableStringStream::ReusableStringStream() {
|
||||
std::tie( m_index, m_oss ) =
|
||||
Singleton<StringStreams>::getMutable().add();
|
||||
}
|
||||
|
||||
ReusableStringStream::~ReusableStringStream() {
|
||||
static_cast<std::ostringstream*>( m_oss )->str("");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/generators/catch_generators_throw.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
@@ -19,8 +20,12 @@
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/internal/catch_output_redirect.hpp>
|
||||
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||
#include <catch2/internal/catch_path_filter.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_thread_local.hpp>
|
||||
#include <catch2/internal/catch_unreachable.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
@@ -32,12 +37,51 @@ namespace Catch {
|
||||
struct GeneratorTracker final : TestCaseTracking::TrackerBase,
|
||||
IGeneratorTracker {
|
||||
GeneratorBasePtr m_generator;
|
||||
// Filtered generator has moved to specific index due to
|
||||
// a filter, it needs special handling of `countedNext()`
|
||||
bool m_isFiltered = false;
|
||||
|
||||
GeneratorTracker(
|
||||
TestCaseTracking::NameAndLocation&& nameAndLocation,
|
||||
TrackerContext& ctx,
|
||||
ITracker* parent ):
|
||||
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
|
||||
ITracker* parent,
|
||||
GeneratorBasePtr&& generator ):
|
||||
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ),
|
||||
m_generator( CATCH_MOVE( generator ) ) {
|
||||
assert( m_generator &&
|
||||
"Cannot create tracker without generator" );
|
||||
|
||||
// Handle potential filter and move forward here...
|
||||
// Old style filters do not affect generators at all
|
||||
if (m_newStyleFilters && m_allTrackerDepth < m_filterRef->size()) {
|
||||
auto const& filter =
|
||||
( *m_filterRef )[m_allTrackerDepth];
|
||||
// Generator cannot be un-entered the way a section
|
||||
// can be, so the tracker has to throw for a wrong
|
||||
// filter to stop the execution flow.
|
||||
if (filter.type == PathFilter::For::Section) {
|
||||
// We want the semantics of `SKIP()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG(
|
||||
"SKIP",
|
||||
Catch::ResultWas::ExplicitSkip,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"" );
|
||||
Catch::Detail::Unreachable();
|
||||
}
|
||||
// '*' is the wildcard for "all elements in generator"
|
||||
// used for filtering sections below the generator, but
|
||||
// not the generator itself.
|
||||
if ( filter.filter != "*" ) {
|
||||
m_isFiltered = true;
|
||||
// TBD: We assume that the filter was validated as
|
||||
// number during parsing. We should pass it
|
||||
// as number from the CLI parser.
|
||||
size_t targetIndex = std::stoul( filter.filter );
|
||||
m_generator->skipToNthElement( targetIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GeneratorTracker*
|
||||
acquire( TrackerContext& ctx,
|
||||
@@ -81,9 +125,6 @@ namespace Catch {
|
||||
|
||||
// TrackerBase interface
|
||||
bool isGeneratorTracker() const override { return true; }
|
||||
auto hasGenerator() const -> bool override {
|
||||
return !!m_generator;
|
||||
}
|
||||
void close() override {
|
||||
TrackerBase::close();
|
||||
// If a generator has a child (it is followed by a section)
|
||||
@@ -112,29 +153,24 @@ namespace Catch {
|
||||
// _can_ start, and thus we should wait for them, or
|
||||
// they cannot start (due to filters), and we shouldn't
|
||||
// wait for them
|
||||
ITracker* parent = m_parent;
|
||||
// This is safe: there is always at least one section
|
||||
// tracker in a test case tracking tree
|
||||
while ( !parent->isSectionTracker() ) {
|
||||
parent = parent->parent();
|
||||
|
||||
// No filters left -> no restrictions on running sections
|
||||
size_t childDepth = 1 + (m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth);
|
||||
if ( childDepth >= m_filterRef->size() ) {
|
||||
return true;
|
||||
}
|
||||
assert( parent &&
|
||||
"Missing root (test case) level section" );
|
||||
|
||||
auto const& parentSection =
|
||||
static_cast<SectionTracker const&>( *parent );
|
||||
auto const& filters = parentSection.getFilters();
|
||||
// No filters -> no restrictions on running sections
|
||||
if ( filters.empty() ) { return true; }
|
||||
|
||||
// If we are using the new style filters, we need to check
|
||||
// whether the successive filter is for section or a generator.
|
||||
if ( m_newStyleFilters
|
||||
&& (*m_filterRef)[childDepth].type != PathFilter::For::Section ) {
|
||||
return false;
|
||||
}
|
||||
// Look for any child section that could match the remaining filters
|
||||
for ( auto const& child : m_children ) {
|
||||
if ( child->isSectionTracker() &&
|
||||
std::find( filters.begin(),
|
||||
filters.end(),
|
||||
static_cast<SectionTracker const&>(
|
||||
*child )
|
||||
.trimmedName() ) !=
|
||||
filters.end() ) {
|
||||
static_cast<SectionTracker const&>( *child )
|
||||
.trimmedName() == StringRef((*m_filterRef)[childDepth].filter) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -146,9 +182,10 @@ namespace Catch {
|
||||
// value, but we do not want to invoke the side-effect if
|
||||
// this generator is still waiting for any child to start.
|
||||
assert( m_generator && "Tracker without generator" );
|
||||
if ( should_wait_for_child ||
|
||||
( m_runState == CompletedSuccessfully &&
|
||||
m_generator->countedNext() ) ) {
|
||||
if ( should_wait_for_child
|
||||
|| ( m_runState == CompletedSuccessfully
|
||||
&& !m_isFiltered // filtered generators cannot meaningfully move forward, as they would get past the filter
|
||||
&& m_generator->countedNext() ) ) {
|
||||
m_children.clear();
|
||||
m_runState = Executing;
|
||||
}
|
||||
@@ -158,9 +195,6 @@ namespace Catch {
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
return m_generator;
|
||||
}
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = CATCH_MOVE( generator );
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
}
|
||||
@@ -177,27 +211,101 @@ namespace Catch {
|
||||
// should also be thread local. For now we just use naked globals
|
||||
// below, in the future we will want to allocate piece of memory
|
||||
// from heap, to avoid consuming too much thread-local storage.
|
||||
//
|
||||
// Note that we also don't want non-trivial the thread-local variables
|
||||
// below be initialized for every thread, only for those that touch
|
||||
// Catch2. To make this work with both GCC/Clang and MSVC, we have to
|
||||
// make them thread-local magic statics. (Class-level statics have the
|
||||
// desired semantics on GCC, but not on MSVC).
|
||||
|
||||
// This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
|
||||
static thread_local bool g_lastAssertionPassed = false;
|
||||
static CATCH_INTERNAL_THREAD_LOCAL bool g_lastAssertionPassed = false;
|
||||
|
||||
// This is the source location for last encountered macro. It is
|
||||
// used to provide the users with more precise location of error
|
||||
// when an unexpected exception/fatal error happens.
|
||||
static thread_local SourceLineInfo g_lastKnownLineInfo("DummyLocation", static_cast<size_t>(-1));
|
||||
static CATCH_INTERNAL_THREAD_LOCAL SourceLineInfo
|
||||
g_lastKnownLineInfo( "DummyLocation", static_cast<size_t>( -1 ) );
|
||||
|
||||
// Should we clear message scopes before sending off the messages to
|
||||
// reporter? Set in `assertionPassedFastPath` to avoid doing the full
|
||||
// clear there for performance reasons.
|
||||
static thread_local bool g_clearMessageScopes = false;
|
||||
static CATCH_INTERNAL_THREAD_LOCAL bool g_clearMessageScopes = false;
|
||||
|
||||
|
||||
// Holds the data for both scoped and unscoped messages together,
|
||||
// to avoid issues where their lifetimes start in wrong order,
|
||||
// and then are destroyed in wrong order.
|
||||
class MessageHolder {
|
||||
// The actual message vector passed to the reporters
|
||||
std::vector<MessageInfo> messages;
|
||||
// IDs of messages from UNSCOPED_X macros, which we have to
|
||||
// remove manually.
|
||||
std::vector<unsigned int> unscoped_ids;
|
||||
|
||||
public:
|
||||
// We do not need to special-case the unscoped messages when
|
||||
// we only keep around the raw msg ids.
|
||||
~MessageHolder() = default;
|
||||
|
||||
void addUnscopedMessage( MessageInfo&& info ) {
|
||||
repairUnscopedMessageInvariant();
|
||||
unscoped_ids.push_back( info.sequence );
|
||||
messages.push_back( CATCH_MOVE( info ) );
|
||||
}
|
||||
|
||||
void addUnscopedMessage(MessageBuilder&& builder) {
|
||||
MessageInfo info( CATCH_MOVE( builder.m_info ) );
|
||||
info.message = builder.m_stream.str();
|
||||
addUnscopedMessage( CATCH_MOVE( info ) );
|
||||
}
|
||||
|
||||
void addScopedMessage(MessageInfo&& info) {
|
||||
messages.push_back( CATCH_MOVE( info ) );
|
||||
}
|
||||
|
||||
std::vector<MessageInfo> const& getMessages() const {
|
||||
return messages;
|
||||
}
|
||||
|
||||
void removeMessage( unsigned int messageId ) {
|
||||
// Note: On average, it would probably be better to look for
|
||||
// the message backwards. However, we do not expect to have
|
||||
// to deal with more messages than low single digits, so
|
||||
// the improvement is tiny, and we would have to hand-write
|
||||
// the loop to avoid terrible codegen of reverse iterators
|
||||
// in debug mode.
|
||||
auto iter =
|
||||
std::find_if( messages.begin(),
|
||||
messages.end(),
|
||||
[messageId]( MessageInfo const& msg ) {
|
||||
return msg.sequence == messageId;
|
||||
} );
|
||||
assert( iter != messages.end() &&
|
||||
"Trying to remove non-existent message." );
|
||||
messages.erase( iter );
|
||||
}
|
||||
|
||||
void removeUnscopedMessages() {
|
||||
for ( const auto messageId : unscoped_ids ) {
|
||||
removeMessage( messageId );
|
||||
}
|
||||
unscoped_ids.clear();
|
||||
g_clearMessageScopes = false;
|
||||
}
|
||||
|
||||
void repairUnscopedMessageInvariant() {
|
||||
if ( g_clearMessageScopes ) { removeUnscopedMessages(); }
|
||||
g_clearMessageScopes = false;
|
||||
}
|
||||
};
|
||||
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
// Actual messages to be provided to the reporter
|
||||
static thread_local std::vector<MessageInfo> g_messages;
|
||||
|
||||
// Owners for the UNSCOPED_X information macro
|
||||
static thread_local std::vector<ScopedMessage> g_messageScopes;
|
||||
static MessageHolder& g_messageHolder() {
|
||||
static CATCH_INTERNAL_THREAD_LOCAL MessageHolder value;
|
||||
return value;
|
||||
}
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
} // namespace Detail
|
||||
@@ -214,6 +322,13 @@ namespace Catch {
|
||||
{
|
||||
getCurrentMutableContext().setResultCapture( this );
|
||||
m_reporter->testRunStarting(m_runInfo);
|
||||
|
||||
// TODO: HACK!
|
||||
// We need to make sure the underlying cache is initialized
|
||||
// while we are guaranteed to be running in a single thread,
|
||||
// because the initialization is not thread-safe.
|
||||
ReusableStringStream rss;
|
||||
(void)rss;
|
||||
}
|
||||
|
||||
RunContext::~RunContext() {
|
||||
@@ -233,7 +348,8 @@ namespace Catch {
|
||||
|
||||
ITracker& rootTracker = m_trackerContext.startRun();
|
||||
assert(rootTracker.isSectionTracker());
|
||||
static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
|
||||
rootTracker.setFilters( &m_config->getPathFilters(),
|
||||
m_config->useNewFilterBehaviour() );
|
||||
|
||||
// We intentionally only seed the internal RNG once per test case,
|
||||
// before it is first invoked. The reason for that is a complex
|
||||
@@ -336,21 +452,19 @@ namespace Catch {
|
||||
Detail::g_lastAssertionPassed = true;
|
||||
}
|
||||
|
||||
if ( Detail::g_clearMessageScopes ) {
|
||||
Detail::g_messageScopes.clear();
|
||||
Detail::g_clearMessageScopes = false;
|
||||
}
|
||||
auto& msgHolder = Detail::g_messageHolder();
|
||||
msgHolder.repairUnscopedMessageInvariant();
|
||||
|
||||
// From here, we are touching shared state and need mutex.
|
||||
Detail::LockGuard lock( m_assertionMutex );
|
||||
{
|
||||
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||
updateTotalsFromAtomics();
|
||||
m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) );
|
||||
m_reporter->assertionEnded( AssertionStats( result, msgHolder.getMessages(), m_totals ) );
|
||||
}
|
||||
|
||||
if ( result.getResultType() != ResultWas::Warning ) {
|
||||
Detail::g_messageScopes.clear();
|
||||
msgHolder.removeUnscopedMessages();
|
||||
}
|
||||
|
||||
// Reset working state. assertion info will be reset after
|
||||
@@ -407,18 +521,32 @@ namespace Catch {
|
||||
SourceLineInfo lineInfo,
|
||||
Generators::GeneratorBasePtr&& generator ) {
|
||||
|
||||
// TBD: Do we want to avoid the warning if the generator is filtered?
|
||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||
!generator->isFinite() ) {
|
||||
// We want the semantics of `FAIL()`, but we inline it
|
||||
// to avoid issues with conditionally prefixed macros
|
||||
INTERNAL_CATCH_MSG( "FAIL",
|
||||
Catch::ResultWas::ExplicitFailure,
|
||||
Catch::ResultDisposition::Normal,
|
||||
"GENERATE() would run infinitely" );
|
||||
}
|
||||
|
||||
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
||||
auto& currentTracker = m_trackerContext.currentTracker();
|
||||
assert(
|
||||
currentTracker.nameAndLocation() != nameAndLoc &&
|
||||
"Trying to create tracker for a generator that already has one" );
|
||||
|
||||
auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
|
||||
CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker );
|
||||
auto newTracker =
|
||||
Catch::Detail::make_unique<Generators::GeneratorTracker>(
|
||||
CATCH_MOVE( nameAndLoc ),
|
||||
m_trackerContext,
|
||||
¤tTracker,
|
||||
CATCH_MOVE( generator ) );
|
||||
auto ret = newTracker.get();
|
||||
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
||||
|
||||
ret->setGenerator( CATCH_MOVE( generator ) );
|
||||
ret->open();
|
||||
return ret;
|
||||
}
|
||||
@@ -483,28 +611,6 @@ namespace Catch {
|
||||
m_reporter->benchmarkFailed( error );
|
||||
}
|
||||
|
||||
void RunContext::pushScopedMessage( MessageInfo const& message ) {
|
||||
Detail::g_messages.push_back( message );
|
||||
}
|
||||
|
||||
void RunContext::popScopedMessage( MessageInfo const& message ) {
|
||||
// Note: On average, it would probably be better to look for the message
|
||||
// backwards. However, we do not expect to have to deal with more
|
||||
// messages than low single digits, so the optimization is tiny,
|
||||
// and we would have to hand-write the loop to avoid terrible
|
||||
// codegen of reverse iterators in debug mode.
|
||||
Detail::g_messages.erase(
|
||||
std::find_if( Detail::g_messages.begin(),
|
||||
Detail::g_messages.end(),
|
||||
[id = message.sequence]( MessageInfo const& msg ) {
|
||||
return msg.sequence == id;
|
||||
} ) );
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
|
||||
Detail::g_messageScopes.emplace_back( CATCH_MOVE(builder) );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
@@ -661,10 +767,10 @@ namespace Catch {
|
||||
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
Detail::g_messageScopes.clear();
|
||||
// TBD: At this point, m_messages should be empty. Do we want to
|
||||
// assert that this is true, or keep the defensive clear call?
|
||||
Detail::g_messages.clear();
|
||||
auto& msgHolder = Detail::g_messageHolder();
|
||||
msgHolder.removeUnscopedMessages();
|
||||
assert( msgHolder.getMessages().empty() &&
|
||||
"There should be no leftover messages after the test ends" );
|
||||
|
||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
@@ -831,11 +937,20 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
IResultCapture& getResultCapture() {
|
||||
if (auto* capture = getCurrentContext().getResultCapture())
|
||||
return *capture;
|
||||
else
|
||||
CATCH_INTERNAL_ERROR("No result capture instance");
|
||||
void IResultCapture::pushScopedMessage( MessageInfo&& message ) {
|
||||
Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) );
|
||||
}
|
||||
|
||||
void IResultCapture::popScopedMessage( unsigned int messageId ) {
|
||||
Detail::g_messageHolder().removeMessage( messageId );
|
||||
}
|
||||
|
||||
void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) {
|
||||
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
|
||||
}
|
||||
|
||||
void IResultCapture::addUnscopedMessage( MessageInfo&& message ) {
|
||||
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
|
||||
}
|
||||
|
||||
void seedRng(IConfig const& config) {
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_path_filter.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -27,6 +28,17 @@ namespace TestCaseTracking {
|
||||
location( _location )
|
||||
{}
|
||||
|
||||
ITracker::ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
|
||||
m_nameAndLocation( CATCH_MOVE( nameAndLoc ) ), m_parent( parent ) {
|
||||
if ( m_parent ) {
|
||||
m_allTrackerDepth = m_parent->m_allTrackerDepth + 1;
|
||||
// We leave section trackers to bump themselves up, as
|
||||
// we cannot use `isSectionTracker` in constructor
|
||||
m_sectionOnlyDepth = m_parent->m_sectionOnlyDepth;
|
||||
m_filterRef = m_parent->m_filterRef;
|
||||
m_newStyleFilters = m_parent->m_newStyleFilters;
|
||||
}
|
||||
}
|
||||
|
||||
ITracker::~ITracker() = default;
|
||||
|
||||
@@ -159,25 +171,32 @@ namespace TestCaseTracking {
|
||||
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
|
||||
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
|
||||
{
|
||||
if( parent ) {
|
||||
while ( !parent->isSectionTracker() ) {
|
||||
parent = parent->parent();
|
||||
}
|
||||
|
||||
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
|
||||
addNextFilters( parentSection.m_filters );
|
||||
if( m_parent ) {
|
||||
++m_sectionOnlyDepth;
|
||||
}
|
||||
}
|
||||
|
||||
bool SectionTracker::isComplete() const {
|
||||
bool complete = true;
|
||||
|
||||
if (m_filters.empty()
|
||||
|| m_filters[0].empty()
|
||||
|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
|
||||
complete = TrackerBase::isComplete();
|
||||
// If there are active filters AND we do not pass them,
|
||||
// the section is always "completed"
|
||||
const size_t filterIndex =
|
||||
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||
if ( filterIndex < m_filterRef->size() ) {
|
||||
// There is active filter, check it
|
||||
// 1) New style filter must explicitly target section
|
||||
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
|
||||
PathFilter::For::Section ) {
|
||||
return true;
|
||||
}
|
||||
// 2) Both style filters must match the trimmed name exactly
|
||||
if ( m_trimmed_name !=
|
||||
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return complete;
|
||||
|
||||
// Otherwise we delegate to the generic processing
|
||||
return TrackerBase::isComplete();
|
||||
}
|
||||
|
||||
bool SectionTracker::isSectionTracker() const { return true; }
|
||||
@@ -213,19 +232,6 @@ namespace TestCaseTracking {
|
||||
open();
|
||||
}
|
||||
|
||||
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
|
||||
if( !filters.empty() ) {
|
||||
m_filters.reserve( m_filters.size() + filters.size() + 2 );
|
||||
m_filters.emplace_back(StringRef{}); // Root - should never be consulted
|
||||
m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
|
||||
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
||||
}
|
||||
}
|
||||
void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
|
||||
if( filters.size() > 1 )
|
||||
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
|
||||
}
|
||||
|
||||
StringRef SectionTracker::trimmedName() const {
|
||||
return m_trimmed_name;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ namespace {
|
||||
return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
|
||||
}
|
||||
|
||||
bool isUtf8ContinuationByte( char c ) {
|
||||
return ( static_cast<unsigned char>( c ) & 0xC0 ) == 0x80;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Catch {
|
||||
@@ -52,6 +56,11 @@ namespace Catch {
|
||||
if ( it != m_string.end() ) {
|
||||
++m_size;
|
||||
++it;
|
||||
// Skip UTF-8 continuation bytes
|
||||
while ( it != m_string.end() &&
|
||||
isUtf8ContinuationByte( *it ) ) {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +123,11 @@ namespace Catch {
|
||||
void AnsiSkippingString::const_iterator::advance() {
|
||||
assert( m_it != m_string->end() );
|
||||
m_it++;
|
||||
// Skip UTF-8 continuation bytes
|
||||
while ( m_it != m_string->end() &&
|
||||
isUtf8ContinuationByte( *m_it ) ) {
|
||||
m_it++;
|
||||
}
|
||||
tryParseAnsiEscapes();
|
||||
}
|
||||
|
||||
@@ -133,6 +147,11 @@ namespace Catch {
|
||||
assert( *m_it == '\033' );
|
||||
m_it--;
|
||||
}
|
||||
// Skip back over UTF-8 continuation bytes to the leading byte
|
||||
while ( isUtf8ContinuationByte( *m_it ) ) {
|
||||
assert( m_it != m_string->begin() );
|
||||
m_it--;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isBoundary( AnsiSkippingString const& line,
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace Catch {
|
||||
|
||||
void ReporterBase::listReporters(
|
||||
std::vector<ReporterDescription> const& descriptions ) {
|
||||
defaultListReporters(m_stream, descriptions, m_config->verbosity());
|
||||
defaultListReporters( m_stream, descriptions, m_config->verbosity() );
|
||||
}
|
||||
|
||||
void ReporterBase::listListeners(
|
||||
std::vector<ListenerDescription> const& descriptions ) {
|
||||
defaultListListeners( m_stream, descriptions );
|
||||
defaultListListeners( m_stream, descriptions, m_config->verbosity() );
|
||||
}
|
||||
|
||||
void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
|
||||
@@ -43,7 +43,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
|
||||
defaultListTags( m_stream, tags, m_config->hasTestFilters() );
|
||||
defaultListTags( m_stream, tags, m_config->hasTestFilters(), m_config->verbosity() );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
@@ -143,7 +143,15 @@ namespace Catch {
|
||||
}
|
||||
|
||||
void defaultListListeners( std::ostream& out,
|
||||
std::vector<ListenerDescription> const& descriptions ) {
|
||||
std::vector<ListenerDescription> const& descriptions,
|
||||
Verbosity verbosity ) {
|
||||
if ( verbosity == Verbosity::Quiet ) {
|
||||
for ( auto const& desc : descriptions ) {
|
||||
out << desc.name << '\n';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
out << "Registered listeners:\n";
|
||||
|
||||
if(descriptions.empty()) {
|
||||
@@ -176,7 +184,14 @@ namespace Catch {
|
||||
|
||||
void defaultListTags( std::ostream& out,
|
||||
std::vector<TagInfo> const& tags,
|
||||
bool isFiltered ) {
|
||||
bool isFiltered,
|
||||
Verbosity verbosity ) {
|
||||
if (verbosity == Verbosity::Quiet) {
|
||||
for (auto const& tagCount : tags) {
|
||||
out << tagCount.all() << '\n';
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( isFiltered ) {
|
||||
out << "Tags for matching test cases:\n";
|
||||
} else {
|
||||
@@ -195,7 +210,7 @@ namespace Catch {
|
||||
return lhs.count < rhs.count;
|
||||
} )
|
||||
->count;
|
||||
|
||||
|
||||
// more padding necessary for 3+ digits
|
||||
if (maxTagCount >= 100) {
|
||||
auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
|
||||
|
||||
@@ -241,70 +241,77 @@ namespace Catch {
|
||||
void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
|
||||
for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
|
||||
if (assertionOrBenchmark.isAssertion()) {
|
||||
writeAssertion(assertionOrBenchmark.asAssertion());
|
||||
// JUnit XML format supports only 1 error/failure/skip
|
||||
// assertion elements per test case
|
||||
if (writeAssertion(assertionOrBenchmark.asAssertion())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JunitReporter::writeAssertion( AssertionStats const& stats ) {
|
||||
bool JunitReporter::writeAssertion( AssertionStats const& stats ) {
|
||||
AssertionResult const& result = stats.assertionResult;
|
||||
if ( !result.isOk() ||
|
||||
result.getResultType() == ResultWas::ExplicitSkip ) {
|
||||
std::string elementName;
|
||||
switch( result.getResultType() ) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
case ResultWas::ExpressionFailed:
|
||||
case ResultWas::DidntThrowException:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::ExplicitSkip:
|
||||
elementName = "skipped";
|
||||
break;
|
||||
// We should never see these here:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
elementName = "internalError";
|
||||
break;
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
|
||||
|
||||
xml.writeAttribute( "message"_sr, result.getExpression() );
|
||||
xml.writeAttribute( "type"_sr, result.getTestMacroName() );
|
||||
|
||||
ReusableStringStream rss;
|
||||
if ( result.getResultType() == ResultWas::ExplicitSkip ) {
|
||||
rss << "SKIPPED\n";
|
||||
} else {
|
||||
rss << "FAILED" << ":\n";
|
||||
if (result.hasExpression()) {
|
||||
rss << " ";
|
||||
rss << result.getExpressionInMacro();
|
||||
rss << '\n';
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
rss << "with expansion:\n";
|
||||
rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
if( result.hasMessage() )
|
||||
rss << result.getMessage() << '\n';
|
||||
for( auto const& msg : stats.infoMessages )
|
||||
if( msg.type == ResultWas::Info )
|
||||
rss << msg.message << '\n';
|
||||
|
||||
rss << "at " << result.getSourceInfo();
|
||||
xml.writeText( rss.str(), XmlFormatting::Newline );
|
||||
if ( result.isOk() &&
|
||||
result.getResultType() != ResultWas::ExplicitSkip ) {
|
||||
return false;
|
||||
}
|
||||
std::string elementName;
|
||||
switch ( result.getResultType() ) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
case ResultWas::ExpressionFailed:
|
||||
case ResultWas::DidntThrowException:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::ExplicitSkip:
|
||||
elementName = "skipped";
|
||||
break;
|
||||
// We should never see these here:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
elementName = "internalError";
|
||||
break;
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement( elementName );
|
||||
|
||||
xml.writeAttribute( "message"_sr, result.getExpression() );
|
||||
xml.writeAttribute( "type"_sr, result.getTestMacroName() );
|
||||
|
||||
ReusableStringStream rss;
|
||||
if ( result.getResultType() == ResultWas::ExplicitSkip ) {
|
||||
rss << "SKIPPED\n";
|
||||
} else {
|
||||
rss << "FAILED:\n";
|
||||
if ( result.hasExpression() ) {
|
||||
rss << " ";
|
||||
rss << result.getExpressionInMacro();
|
||||
rss << '\n';
|
||||
}
|
||||
if ( result.hasExpandedExpression() ) {
|
||||
rss << "with expansion:\n";
|
||||
rss << TextFlow::Column( result.getExpandedExpression() )
|
||||
.indent( 2 )
|
||||
<< '\n';
|
||||
}
|
||||
}
|
||||
|
||||
if ( result.hasMessage() ) { rss << result.getMessage() << '\n'; }
|
||||
for ( auto const& msg : stats.infoMessages ) {
|
||||
if ( msg.type == ResultWas::Info ) { rss << msg.message << '\n'; }
|
||||
}
|
||||
|
||||
rss << "at " << result.getSourceInfo();
|
||||
xml.writeText( rss.str(), XmlFormatting::Newline );
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
// The fwd decl & default specialization needs to be seen by VS2017 before
|
||||
|
||||
@@ -8,14 +8,16 @@
|
||||
#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
|
||||
#include <catch2/benchmark/catch_clock.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
struct DummyTemplateArgPlaceholder;
|
||||
}
|
||||
|
||||
// We cannot forward declare the type with default template argument
|
||||
// multiple times, so it is split out into a separate header so that
|
||||
// we can prevent multiple declarations in dependees
|
||||
template <typename Duration = Benchmark::FDuration>
|
||||
// we can prevent multiple declarations in dependencies
|
||||
template <typename Duration = Detail::DummyTemplateArgPlaceholder>
|
||||
struct BenchmarkStats;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
#include <catch2/internal/catch_logical_traits.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
@@ -88,6 +89,7 @@
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_output_redirect.hpp>
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
#include <catch2/internal/catch_path_filter.hpp>
|
||||
#include <catch2/internal/catch_platform.hpp>
|
||||
#include <catch2/internal/catch_polyfills.hpp>
|
||||
#include <catch2/internal/catch_preprocessor.hpp>
|
||||
@@ -121,6 +123,7 @@
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_thread_local.hpp>
|
||||
#include <catch2/internal/catch_thread_support.hpp>
|
||||
#include <catch2/internal/catch_to_string.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_path_filter.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
@@ -86,7 +87,10 @@ namespace Catch {
|
||||
std::vector<ReporterSpec> reporterSpecifications;
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
std::vector<PathFilter> pathFilters;
|
||||
bool useNewPathFilteringBehaviour = false;
|
||||
|
||||
std::string prematureExitGuardFilePath;
|
||||
};
|
||||
|
||||
|
||||
@@ -107,19 +111,23 @@ namespace Catch {
|
||||
getProcessedReporterSpecs() const;
|
||||
|
||||
std::vector<std::string> const& getTestsOrTags() const override;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
std::vector<PathFilter> const& getPathFilters() const override;
|
||||
bool useNewFilterBehaviour() const override;
|
||||
|
||||
TestSpec const& testSpec() const override;
|
||||
bool hasTestFilters() const override;
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
std::string const& getExitGuardFilePath() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
StringRef name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
bool warnAboutUnmatchedTestSpecs() const override;
|
||||
bool warnAboutInfiniteGenerators() const override;
|
||||
bool zeroTestsCountAsSuccess() const override;
|
||||
ShowDurations showDurations() const override;
|
||||
double minDuration() const override;
|
||||
|
||||
@@ -57,16 +57,16 @@ namespace Catch {
|
||||
ScopedMessage( ScopedMessage&& old ) noexcept;
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
unsigned int m_messageId;
|
||||
bool m_moved = false;
|
||||
};
|
||||
|
||||
class Capturer {
|
||||
std::vector<MessageInfo> m_messages;
|
||||
IResultCapture& m_resultCapture;
|
||||
size_t m_captured = 0;
|
||||
bool m_isScoped = false;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names, bool isScoped );
|
||||
|
||||
Capturer(Capturer const&) = delete;
|
||||
Capturer& operator=(Capturer const&) = delete;
|
||||
@@ -98,11 +98,12 @@ namespace Catch {
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||
Catch::Capturer varName( macroName##_catch_sr, \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
Catch::ResultWas::Info, \
|
||||
#__VA_ARGS__##_catch_sr ); \
|
||||
#define INTERNAL_CATCH_CAPTURE( varName, macroName, scopedCapture, ... ) \
|
||||
Catch::Capturer varName( macroName##_catch_sr, \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
Catch::ResultWas::Info, \
|
||||
#__VA_ARGS__##_catch_sr, \
|
||||
scopedCapture ); \
|
||||
varName.captureValues( 0, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -111,7 +112,7 @@ namespace Catch {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
||||
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
|
||||
|
||||
|
||||
#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
|
||||
@@ -119,28 +120,32 @@ namespace Catch {
|
||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||
#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
|
||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
|
||||
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", true, __VA_ARGS__ )
|
||||
#define CATCH_UNSCOPED_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_UNSCOPED_CAPTURE", false, __VA_ARGS__ )
|
||||
|
||||
#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define CATCH_INFO( msg ) (void)(0)
|
||||
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define CATCH_WARN( msg ) (void)(0)
|
||||
#define CATCH_CAPTURE( ... ) (void)(0)
|
||||
#define CATCH_INFO( msg ) (void)(0)
|
||||
#define CATCH_UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define CATCH_WARN( msg ) (void)(0)
|
||||
#define CATCH_CAPTURE( ... ) (void)(0)
|
||||
#define CATCH_UNSCOPED_CAPTURE( ... ) (void)(0)
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
|
||||
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", true, __VA_ARGS__ )
|
||||
#define UNSCOPED_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "UNSCOPED_CAPTURE", false, __VA_ARGS__ )
|
||||
|
||||
#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
#define INFO( msg ) (void)(0)
|
||||
#define UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define WARN( msg ) (void)(0)
|
||||
#define CAPTURE( ... ) (void)(0)
|
||||
#define INFO( msg ) (void)(0)
|
||||
#define UNSCOPED_INFO( msg ) (void)(0)
|
||||
#define WARN( msg ) (void)(0)
|
||||
#define CAPTURE( ... ) (void)(0)
|
||||
#define UNSCOPED_CAPTURE( ... ) (void)(0)
|
||||
|
||||
#endif // end of user facing macro declarations
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef CATCH_TOSTRING_HPP_INCLUDED
|
||||
#define CATCH_TOSTRING_HPP_INCLUDED
|
||||
|
||||
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
@@ -40,13 +40,9 @@ namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
inline std::size_t catch_strnlen(const char *str, std::size_t n) {
|
||||
auto ret = std::char_traits<char>::find(str, n, '\0');
|
||||
if (ret != nullptr) {
|
||||
return static_cast<std::size_t>(ret - str);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
std::size_t catch_strnlen(const char *str, std::size_t n);
|
||||
|
||||
std::string formatTimeT( std::time_t time );
|
||||
|
||||
constexpr StringRef unprintableString = "{?}"_sr;
|
||||
|
||||
@@ -411,44 +407,38 @@ namespace Catch {
|
||||
|
||||
// Separate std::tuple specialization
|
||||
#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
|
||||
#include <tuple>
|
||||
# include <tuple>
|
||||
# include <utility>
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
template<
|
||||
typename Tuple,
|
||||
std::size_t N = 0,
|
||||
bool = (N < std::tuple_size<Tuple>::value)
|
||||
>
|
||||
struct TupleElementPrinter {
|
||||
static void print(const Tuple& tuple, std::ostream& os) {
|
||||
os << (N ? ", " : " ")
|
||||
<< ::Catch::Detail::stringify(std::get<N>(tuple));
|
||||
TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
|
||||
}
|
||||
};
|
||||
template <typename Tuple, std::size_t... Is>
|
||||
void PrintTuple( const Tuple& tuple,
|
||||
std::ostream& os,
|
||||
std::index_sequence<Is...> ) {
|
||||
// 1 + Account for when the tuple is empty
|
||||
char a[1 + sizeof...( Is )] = {
|
||||
( ( os << ( Is ? ", " : " " )
|
||||
<< ::Catch::Detail::stringify( std::get<Is>( tuple ) ) ),
|
||||
'\0' )... };
|
||||
(void)a;
|
||||
}
|
||||
|
||||
template<
|
||||
typename Tuple,
|
||||
std::size_t N
|
||||
>
|
||||
struct TupleElementPrinter<Tuple, N, false> {
|
||||
static void print(const Tuple&, std::ostream&) {}
|
||||
};
|
||||
} // namespace Detail
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename ...Types>
|
||||
template <typename... Types>
|
||||
struct StringMaker<std::tuple<Types...>> {
|
||||
static std::string convert(const std::tuple<Types...>& tuple) {
|
||||
static std::string convert( const std::tuple<Types...>& tuple ) {
|
||||
ReusableStringStream rss;
|
||||
rss << '{';
|
||||
Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
|
||||
Detail::PrintTuple(
|
||||
tuple,
|
||||
rss.get(),
|
||||
std::make_index_sequence<sizeof...( Types )>{} );
|
||||
rss << " }";
|
||||
return rss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace Catch
|
||||
#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
|
||||
|
||||
#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||
@@ -635,28 +625,7 @@ struct ratio_string<std::milli> {
|
||||
const auto systemish = std::chrono::time_point_cast<
|
||||
std::chrono::system_clock::duration>( time_point );
|
||||
const auto as_time_t = std::chrono::system_clock::to_time_t( systemish );
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
const auto err = gmtime_s( &timeInfo, &as_time_t );
|
||||
if ( err ) {
|
||||
return "gmtime from provided timepoint has failed. This "
|
||||
"happens e.g. with pre-1970 dates using Microsoft libc";
|
||||
}
|
||||
#else
|
||||
std::tm* timeInfo = std::gmtime( &as_time_t );
|
||||
#endif
|
||||
|
||||
auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
|
||||
char timeStamp[timeStampSize];
|
||||
const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
|
||||
#else
|
||||
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
|
||||
#endif
|
||||
return std::string(timeStamp, timeStampSize - 1);
|
||||
return ::Catch::Detail::formatTimeT( as_time_t );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,12 +196,12 @@
|
||||
#endif
|
||||
|
||||
|
||||
// #undef CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS
|
||||
// #undef CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS
|
||||
// #undef CATCH_CONFIG_THREAD_SAFE_ASSERTIONS
|
||||
// #undef CATCH_CONFIG_NO_THREAD_SAFE_ASSERTIONS
|
||||
|
||||
#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS ) && \
|
||||
defined( CATCH_CONFIG_NO_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
|
||||
# error Cannot force EXPERIMENTAL_THREAD_SAFE_ASSERTIONS to both ON and OFF
|
||||
#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS ) && \
|
||||
defined( CATCH_CONFIG_NO_THREAD_SAFE_ASSERTIONS )
|
||||
# error Cannot force THREAD_SAFE_ASSERTIONS to both ON and OFF
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 10
|
||||
#define CATCH_VERSION_MINOR 14
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/generators/catch_generators_throw.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
@@ -22,14 +23,6 @@ namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
//! Throws GeneratorException with the provided message
|
||||
[[noreturn]]
|
||||
void throw_generator_exception(char const * msg);
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
template<typename T>
|
||||
class IGenerator : public GeneratorUntypedBase {
|
||||
std::string stringifyImpl() const override {
|
||||
@@ -64,6 +57,9 @@ namespace Detail {
|
||||
bool next() {
|
||||
return m_generator->countedNext();
|
||||
}
|
||||
|
||||
bool isFinite() const { return m_generator->isFinite(); }
|
||||
void skipToNthElement( size_t n ) { m_generator->skipToNthElement(n); }
|
||||
};
|
||||
|
||||
|
||||
@@ -84,6 +80,8 @@ namespace Detail {
|
||||
bool next() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFinite() const override { return true; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -93,6 +91,15 @@ namespace Detail {
|
||||
"specialization, use SingleValue Generator instead.");
|
||||
std::vector<T> m_values;
|
||||
size_t m_idx = 0;
|
||||
|
||||
void skipToNthElementImpl( std::size_t n ) override {
|
||||
if ( n >= m_values.size() ) {
|
||||
Detail::throw_generator_exception(
|
||||
"Coud not jump to Nth element: not enough elements" );
|
||||
}
|
||||
m_idx = n;
|
||||
}
|
||||
|
||||
public:
|
||||
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||
|
||||
@@ -103,6 +110,8 @@ namespace Detail {
|
||||
++m_idx;
|
||||
return m_idx < m_values.size();
|
||||
}
|
||||
|
||||
bool isFinite() const override { return true; }
|
||||
};
|
||||
|
||||
template <typename T, typename DecayedT = std::decay_t<T>>
|
||||
@@ -167,6 +176,14 @@ namespace Detail {
|
||||
}
|
||||
return m_current < m_generators.size();
|
||||
}
|
||||
|
||||
bool isFinite() const override {
|
||||
for (auto const& gen : m_generators) {
|
||||
if (!gen.isFinite()) { return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
@@ -22,6 +23,17 @@ namespace Generators {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
size_t m_returned = 0;
|
||||
size_t m_target;
|
||||
|
||||
void skipToNthElementImpl( std::size_t n ) override {
|
||||
if ( n >= m_target ) {
|
||||
Detail::throw_generator_exception(
|
||||
"Coud not jump to Nth element: not enough elements" );
|
||||
}
|
||||
|
||||
m_generator.skipToNthElement( n );
|
||||
m_returned = n;
|
||||
}
|
||||
|
||||
public:
|
||||
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
@@ -46,6 +58,8 @@ namespace Generators {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool isFinite() const override { return true; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -87,6 +101,8 @@ namespace Generators {
|
||||
while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool isFinite() const override { return m_generator.isFinite(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -111,6 +127,9 @@ namespace Generators {
|
||||
m_target_repeats(repeats)
|
||||
{
|
||||
assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
|
||||
if (!m_generator.isFinite()) {
|
||||
Detail::throw_generator_exception( "Cannot repeat infinite generator" );
|
||||
}
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
@@ -144,6 +163,8 @@ namespace Generators {
|
||||
}
|
||||
return m_current_repeat < m_target_repeats;
|
||||
}
|
||||
|
||||
bool isFinite() const override { return m_generator.isFinite(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -157,25 +178,30 @@ namespace Generators {
|
||||
GeneratorWrapper<U> m_generator;
|
||||
Func m_function;
|
||||
// To avoid returning dangling reference, we have to save the values
|
||||
T m_cache;
|
||||
mutable Optional<T> m_cache;
|
||||
|
||||
void skipToNthElementImpl( std::size_t n ) override {
|
||||
m_generator.skipToNthElement( n );
|
||||
m_cache.reset();
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename F2 = Func>
|
||||
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_function(CATCH_FORWARD(function)),
|
||||
m_cache(m_function(m_generator.get()))
|
||||
m_function(CATCH_FORWARD(function))
|
||||
{}
|
||||
|
||||
T const& get() const override {
|
||||
return m_cache;
|
||||
if ( !m_cache ) { m_cache = m_function( m_generator.get() ); }
|
||||
return *m_cache;
|
||||
}
|
||||
bool next() override {
|
||||
const auto success = m_generator.next();
|
||||
if (success) {
|
||||
m_cache = m_function(m_generator.get());
|
||||
}
|
||||
return success;
|
||||
m_cache.reset();
|
||||
return m_generator.next();
|
||||
}
|
||||
|
||||
bool isFinite() const override { return m_generator.isFinite(); }
|
||||
};
|
||||
|
||||
template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
|
||||
@@ -197,7 +223,6 @@ namespace Generators {
|
||||
std::vector<T> m_chunk;
|
||||
size_t m_chunk_size;
|
||||
GeneratorWrapper<T> m_generator;
|
||||
bool m_used_up = false;
|
||||
public:
|
||||
ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
|
||||
m_chunk_size(size), m_generator(CATCH_MOVE(generator))
|
||||
@@ -226,6 +251,8 @@ namespace Generators {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isFinite() const override { return m_generator.isFinite(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -235,6 +262,56 @@ namespace Generators {
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ConcatGenerator final : public IGenerator<T> {
|
||||
std::vector<GeneratorWrapper<T>> m_generators;
|
||||
size_t m_current_generator = 0;
|
||||
|
||||
void InsertGenerators( GeneratorWrapper<T>&& gen ) {
|
||||
m_generators.push_back( CATCH_MOVE( gen ) );
|
||||
}
|
||||
|
||||
template <typename... Generators>
|
||||
void InsertGenerators( GeneratorWrapper<T>&& gen, Generators&&... gens ) {
|
||||
m_generators.push_back( CATCH_MOVE( gen ) );
|
||||
InsertGenerators( CATCH_MOVE( gens )... );
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename... Generators>
|
||||
ConcatGenerator( Generators&&... generators ) {
|
||||
InsertGenerators( CATCH_MOVE( generators )... );
|
||||
}
|
||||
|
||||
T const& get() const override {
|
||||
return m_generators[m_current_generator].get();
|
||||
}
|
||||
bool next() override {
|
||||
const bool success = m_generators[m_current_generator].next();
|
||||
if ( success ) { return true; }
|
||||
|
||||
// If current generator is used up, we have to move to the next one
|
||||
++m_current_generator;
|
||||
return m_current_generator < m_generators.size();
|
||||
}
|
||||
|
||||
bool isFinite() const override {
|
||||
for ( auto const& gen : m_generators ) {
|
||||
if ( !gen.isFinite() ) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Generators>
|
||||
GeneratorWrapper<T> cat( GeneratorWrapper<T>&& generator,
|
||||
Generators&&... generators ) {
|
||||
return GeneratorWrapper<T>(
|
||||
Catch::Detail::make_unique<ConcatGenerator<T>>(
|
||||
CATCH_MOVE( generator ), CATCH_MOVE( generators )... ) );
|
||||
}
|
||||
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
@@ -26,5 +26,6 @@
|
||||
#include <catch2/generators/catch_generators_adapters.hpp>
|
||||
#include <catch2/generators/catch_generators_random.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include <catch2/generators/catch_generators_throw.hpp>
|
||||
|
||||
#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
m_current_number = m_dist(m_rng);
|
||||
return true;
|
||||
}
|
||||
bool isFinite() const override { return false; }
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -59,6 +60,7 @@ public:
|
||||
bool next() override;
|
||||
|
||||
~RandomFloatingGenerator() override; // = default
|
||||
bool isFinite() const override;
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
@@ -80,6 +82,7 @@ public:
|
||||
m_current_number = m_dist(m_rng);
|
||||
return true;
|
||||
}
|
||||
bool isFinite() const override { return false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
m_current += m_step;
|
||||
return (m_positive) ? (m_current < m_end) : (m_current > m_end);
|
||||
}
|
||||
|
||||
bool isFinite() const override { return true; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -87,6 +89,8 @@ public:
|
||||
++m_current;
|
||||
return m_current != m_elems.size();
|
||||
}
|
||||
|
||||
bool isFinite() const override { return true; }
|
||||
};
|
||||
|
||||
template <typename InputIterator,
|
||||
|
||||
23
thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_throw.hpp
vendored
Normal file
23
thirdparty/catch2/src/main/native/include/catch2/generators/catch_generators_throw.hpp
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_GENERATORS_THROW_HPP_INCLUDED
|
||||
#define CATCH_GENERATORS_THROW_HPP_INCLUDED
|
||||
|
||||
namespace Catch {
|
||||
namespace Generators {
|
||||
namespace Detail {
|
||||
|
||||
//! Throws GeneratorException with the provided message
|
||||
[[noreturn]]
|
||||
void throw_generator_exception( char const* msg );
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_GENERATORS_THROW_HPP_INCLUDED
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
@@ -62,10 +63,10 @@ namespace Catch {
|
||||
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
|
||||
virtual void benchmarkFailed( StringRef error ) = 0;
|
||||
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
|
||||
static void pushScopedMessage( MessageInfo&& message );
|
||||
static void popScopedMessage( unsigned int messageId );
|
||||
static void addUnscopedMessage( MessageInfo&& message );
|
||||
static void emplaceUnscopedMessage( MessageBuilder&& builder );
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
@@ -101,7 +102,18 @@ namespace Catch {
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
};
|
||||
|
||||
IResultCapture& getResultCapture();
|
||||
namespace Detail {
|
||||
[[noreturn]]
|
||||
void missingCaptureInstance();
|
||||
}
|
||||
inline IResultCapture& getResultCapture() {
|
||||
if (auto* capture = getCurrentContext().getResultCapture()) {
|
||||
return *capture;
|
||||
} else {
|
||||
Detail::missingCaptureInstance();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Catch {
|
||||
NoAssertions = 0x01,
|
||||
//! A command line test spec matched no test cases
|
||||
UnmatchedTestSpec = 0x02,
|
||||
//! The resulting generator in GENERATE is infinite
|
||||
InfiniteGenerator = 0x04,
|
||||
}; };
|
||||
|
||||
enum class ShowDurations {
|
||||
@@ -60,6 +62,7 @@ namespace Catch {
|
||||
|
||||
class TestSpec;
|
||||
class IStream;
|
||||
struct PathFilter;
|
||||
|
||||
class IConfig : public Detail::NonCopyable {
|
||||
public:
|
||||
@@ -71,6 +74,7 @@ namespace Catch {
|
||||
virtual bool shouldDebugBreak() const = 0;
|
||||
virtual bool warnAboutMissingAssertions() const = 0;
|
||||
virtual bool warnAboutUnmatchedTestSpecs() const = 0;
|
||||
virtual bool warnAboutInfiniteGenerators() const = 0;
|
||||
virtual bool zeroTestsCountAsSuccess() const = 0;
|
||||
virtual int abortAfter() const = 0;
|
||||
virtual bool showInvisibles() const = 0;
|
||||
@@ -84,7 +88,9 @@ namespace Catch {
|
||||
virtual unsigned int shardCount() const = 0;
|
||||
virtual unsigned int shardIndex() const = 0;
|
||||
virtual ColourMode defaultColourMode() const = 0;
|
||||
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
|
||||
virtual std::vector<PathFilter> const& getPathFilters() const = 0;
|
||||
virtual bool useNewFilterBehaviour() const = 0;
|
||||
|
||||
virtual Verbosity verbosity() const = 0;
|
||||
|
||||
virtual bool skipBenchmarks() const = 0;
|
||||
|
||||
@@ -35,6 +35,15 @@ namespace Catch {
|
||||
//! Customization point for `currentElementAsString`
|
||||
virtual std::string stringifyImpl() const = 0;
|
||||
|
||||
/**
|
||||
* Customization point for skipping to the n-th element
|
||||
*
|
||||
* Defaults to successively calling `countedNext`. If there
|
||||
* are not enough elements to reach the nth one, will throw
|
||||
* an error.
|
||||
*/
|
||||
virtual void skipToNthElementImpl( std::size_t n );
|
||||
|
||||
public:
|
||||
GeneratorUntypedBase() = default;
|
||||
// Generation of copy ops is deprecated (and Clang will complain)
|
||||
@@ -58,6 +67,13 @@ namespace Catch {
|
||||
|
||||
std::size_t currentElementIndex() const { return m_currentElementIndex; }
|
||||
|
||||
/**
|
||||
* Moves the generator forward **to** the n-th element
|
||||
*
|
||||
* Cannot move backwards. Can stay in place.
|
||||
*/
|
||||
void skipToNthElement( std::size_t n );
|
||||
|
||||
/**
|
||||
* Returns generator's current element as user-friendly string.
|
||||
*
|
||||
@@ -72,6 +88,15 @@ namespace Catch {
|
||||
* comes first.
|
||||
*/
|
||||
StringRef currentElementAsString() const;
|
||||
|
||||
/**
|
||||
* Returns true if calls to `next` will eventually return false
|
||||
*
|
||||
* Note that for backwards compatibility this is currently defaulted
|
||||
* to return `true`, but in the future all generators will have to
|
||||
* provide their own implementation.
|
||||
*/
|
||||
virtual bool isFinite() const;
|
||||
};
|
||||
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
||||
|
||||
@@ -80,9 +105,7 @@ namespace Catch {
|
||||
class IGeneratorTracker {
|
||||
public:
|
||||
virtual ~IGeneratorTracker(); // = default;
|
||||
virtual auto hasGenerator() const -> bool = 0;
|
||||
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
@@ -110,10 +110,15 @@
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wc++20-extensions\"" )
|
||||
# else
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
|
||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
|
||||
# endif
|
||||
|
||||
# if ( __clang_major__ >= 22 )
|
||||
# define CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wc2y-extensions\"" )
|
||||
# endif
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
|
||||
_Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
|
||||
|
||||
@@ -208,7 +213,7 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Visual C++
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
// We want to defer to nvcc-specific warning suppression if we are compiled
|
||||
// with nvcc masquerading for MSVC.
|
||||
@@ -219,14 +224,23 @@
|
||||
__pragma( warning( pop ) )
|
||||
# endif
|
||||
|
||||
// Suppress MSVC C++ Core Guidelines checker warning 26426:
|
||||
// "Global initializer calls a non-constexpr function (i.22)"
|
||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
__pragma( warning( disable : 26426 ) )
|
||||
|
||||
// Universal Windows platform does not support SEH
|
||||
// Or console colours (or console at all...)
|
||||
# if defined(CATCH_PLATFORM_WINDOWS_UWP)
|
||||
# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
|
||||
# else
|
||||
# if !defined(CATCH_PLATFORM_WINDOWS_UWP)
|
||||
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
||||
# endif
|
||||
|
||||
// Only some Windows platform families support the console
|
||||
# if defined(WINAPI_FAMILY_PARTITION)
|
||||
# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
|
||||
# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
|
||||
# endif
|
||||
# endif
|
||||
|
||||
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
|
||||
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
|
||||
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
|
||||
@@ -420,6 +434,9 @@
|
||||
#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS )
|
||||
# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS
|
||||
#endif
|
||||
#if !defined( CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS )
|
||||
# define CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
|
||||
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
||||
|
||||
@@ -19,11 +19,9 @@ namespace Catch {
|
||||
IConfig const* m_config = nullptr;
|
||||
IResultCapture* m_resultCapture = nullptr;
|
||||
|
||||
CATCH_EXPORT static Context* currentContext;
|
||||
CATCH_EXPORT static Context currentContext;
|
||||
friend Context& getCurrentMutableContext();
|
||||
friend Context const& getCurrentContext();
|
||||
static void createContext();
|
||||
friend void cleanUpContext();
|
||||
|
||||
public:
|
||||
constexpr IResultCapture* getResultCapture() const {
|
||||
@@ -34,21 +32,14 @@ namespace Catch {
|
||||
m_resultCapture = resultCapture;
|
||||
}
|
||||
constexpr void setConfig( IConfig const* config ) { m_config = config; }
|
||||
|
||||
};
|
||||
|
||||
Context& getCurrentMutableContext();
|
||||
|
||||
inline Context const& getCurrentContext() {
|
||||
// We duplicate the logic from `getCurrentMutableContext` here,
|
||||
// to avoid paying the call overhead in debug mode.
|
||||
if ( !Context::currentContext ) { Context::createContext(); }
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *Context::currentContext;
|
||||
return Context::currentContext;
|
||||
}
|
||||
|
||||
void cleanUpContext();
|
||||
|
||||
class SimplePcg32;
|
||||
SimplePcg32& sharedRng();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Catch {
|
||||
#define CATCH_TRAP() __asm__(".inst 0xde01")
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
|
||||
// If we can use inline assembler, do it because this allows us to break
|
||||
// directly at the location of the failing check instead of breaking inside
|
||||
// raise() called from it, i.e. one stack frame below.
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
|
||||
#if !defined( CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS )
|
||||
# define DEPRECATED( msg ) [[deprecated( msg )]]
|
||||
# define CATCH_DEPRECATED( msg ) [[deprecated( msg )]]
|
||||
#else
|
||||
# define DEPRECATED( msg )
|
||||
# define CATCH_DEPRECATED( msg )
|
||||
#endif
|
||||
|
||||
#endif // CATCH_DEPRECATION_MACRO_HPP_INCLUDED
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_JSONWRITER_HPP_INCLUDED
|
||||
#define CATCH_JSONWRITER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
@@ -27,8 +28,8 @@ namespace Catch {
|
||||
|
||||
class JsonValueWriter {
|
||||
public:
|
||||
JsonValueWriter( std::ostream& os );
|
||||
JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonObjectWriter writeObject() &&;
|
||||
JsonArrayWriter writeArray() &&;
|
||||
@@ -62,8 +63,8 @@ namespace Catch {
|
||||
|
||||
class JsonObjectWriter {
|
||||
public:
|
||||
JsonObjectWriter( std::ostream& os );
|
||||
JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
|
||||
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
||||
@@ -81,8 +82,8 @@ namespace Catch {
|
||||
|
||||
class JsonArrayWriter {
|
||||
public:
|
||||
JsonArrayWriter( std::ostream& os );
|
||||
JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
|
||||
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
||||
|
||||
24
thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp
vendored
Normal file
24
thirdparty/catch2/src/main/native/include/catch2/internal/catch_lifetimebound.hpp
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#ifndef CATCH_LIFETIMEBOUND_HPP_INCLUDED
|
||||
#define CATCH_LIFETIMEBOUND_HPP_INCLUDED
|
||||
|
||||
#if !defined( __has_cpp_attribute )
|
||||
# define CATCH_ATTR_LIFETIMEBOUND
|
||||
#elif __has_cpp_attribute( msvc::lifetimebound )
|
||||
# define CATCH_ATTR_LIFETIMEBOUND [[msvc::lifetimebound]]
|
||||
#elif __has_cpp_attribute( clang::lifetimebound )
|
||||
# define CATCH_ATTR_LIFETIMEBOUND [[clang::lifetimebound]]
|
||||
#elif __has_cpp_attribute( lifetimebound )
|
||||
# define CATCH_ATTR_LIFETIMEBOUND [[lifetimebound]]
|
||||
#else
|
||||
# define CATCH_ATTR_LIFETIMEBOUND
|
||||
#endif
|
||||
|
||||
#endif // CATCH_LIFETIMEBOUND_HPP_INCLUDED
|
||||
@@ -26,18 +26,17 @@ namespace Catch {
|
||||
std::string message;
|
||||
SourceLineInfo lineInfo;
|
||||
ResultWas::OfType type;
|
||||
// The "ID" of the message, used to know when to remove it from reporter context.
|
||||
unsigned int sequence;
|
||||
|
||||
DEPRECATED( "Explicitly use the 'sequence' member instead" )
|
||||
CATCH_DEPRECATED( "Explicitly use the 'sequence' member instead" )
|
||||
bool operator == (MessageInfo const& other) const {
|
||||
return sequence == other.sequence;
|
||||
}
|
||||
DEPRECATED( "Explicitly use the 'sequence' member instead" )
|
||||
CATCH_DEPRECATED( "Explicitly use the 'sequence' member instead" )
|
||||
bool operator < (MessageInfo const& other) const {
|
||||
return sequence < other.sequence;
|
||||
}
|
||||
private:
|
||||
static thread_local unsigned int globalCount;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
33
thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp
vendored
Normal file
33
thirdparty/catch2/src/main/native/include/catch2/internal/catch_path_filter.hpp
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_PATH_FILTER_HPP_INCLUDED
|
||||
#define CATCH_PATH_FILTER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct PathFilter {
|
||||
enum class For {
|
||||
Section,
|
||||
Generator,
|
||||
};
|
||||
PathFilter( For type_, std::string filter_ ):
|
||||
type( type_ ), filter( CATCH_MOVE( filter_ ) ) {}
|
||||
|
||||
For type;
|
||||
std::string filter;
|
||||
|
||||
friend bool operator==( PathFilter const& lhs, PathFilter const& rhs );
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_PATH_FILTER_HPP_INCLUDED
|
||||
@@ -25,6 +25,9 @@
|
||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define CATCH_PLATFORM_LINUX
|
||||
|
||||
#elif defined(__QNX__)
|
||||
# define CATCH_PLATFORM_QNX
|
||||
|
||||
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# define CATCH_PLATFORM_WINDOWS
|
||||
|
||||
|
||||
@@ -94,11 +94,6 @@ namespace Catch {
|
||||
void benchmarkEnded( BenchmarkStats<> const& stats ) override;
|
||||
void benchmarkFailed( StringRef error ) override;
|
||||
|
||||
void pushScopedMessage( MessageInfo const& message ) override;
|
||||
void popScopedMessage( MessageInfo const& message ) override;
|
||||
|
||||
void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
|
||||
|
||||
std::string getCurrentTestName() const override;
|
||||
|
||||
const AssertionResult* getLastResult() const override;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_STRING_MANIP_HPP_INCLUDED
|
||||
#define CATCH_STRING_MANIP_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
@@ -28,10 +29,10 @@ namespace Catch {
|
||||
//! Returns a new string without whitespace at the start/end
|
||||
std::string trim( std::string const& str );
|
||||
//! Returns a substring of the original ref without whitespace. Beware lifetimes!
|
||||
StringRef trim(StringRef ref);
|
||||
StringRef trim( StringRef ref CATCH_ATTR_LIFETIMEBOUND );
|
||||
|
||||
// !!! Be aware, returns refs into original string - make sure original string outlives them
|
||||
std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
|
||||
std::vector<StringRef> splitStringRef( StringRef str CATCH_ATTR_LIFETIMEBOUND, char delimiter );
|
||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
|
||||
|
||||
/**
|
||||
@@ -49,7 +50,7 @@ namespace Catch {
|
||||
StringRef m_label;
|
||||
|
||||
public:
|
||||
constexpr pluralise(std::uint64_t count, StringRef label):
|
||||
constexpr pluralise(std::uint64_t count, StringRef label CATCH_ATTR_LIFETIMEBOUND):
|
||||
m_count(count),
|
||||
m_label(label)
|
||||
{}
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
#ifndef CATCH_STRINGREF_HPP_INCLUDED
|
||||
#define CATCH_STRINGREF_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <cassert>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Catch {
|
||||
@@ -36,14 +37,16 @@ namespace Catch {
|
||||
public: // construction
|
||||
constexpr StringRef() noexcept = default;
|
||||
|
||||
StringRef( char const* rawChars ) noexcept;
|
||||
StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND ) noexcept;
|
||||
|
||||
constexpr StringRef( char const* rawChars, size_type size ) noexcept
|
||||
constexpr StringRef( char const* rawChars CATCH_ATTR_LIFETIMEBOUND,
|
||||
size_type size ) noexcept
|
||||
: m_start( rawChars ),
|
||||
m_size( size )
|
||||
{}
|
||||
|
||||
StringRef( std::string const& stdString ) noexcept
|
||||
StringRef(
|
||||
std::string const& stdString CATCH_ATTR_LIFETIMEBOUND ) noexcept
|
||||
: m_start( stdString.c_str() ),
|
||||
m_size( stdString.size() )
|
||||
{}
|
||||
@@ -89,7 +92,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
// Returns the current start pointer. May not be null-terminated.
|
||||
constexpr char const* data() const noexcept {
|
||||
constexpr char const* data() const noexcept CATCH_ATTR_LIFETIMEBOUND {
|
||||
return m_start;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
|
||||
#define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
@@ -16,6 +17,9 @@
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct PathFilter;
|
||||
|
||||
namespace TestCaseTracking {
|
||||
|
||||
struct NameAndLocation {
|
||||
@@ -48,7 +52,7 @@ namespace TestCaseTracking {
|
||||
StringRef name;
|
||||
SourceLineInfo location;
|
||||
|
||||
constexpr NameAndLocationRef( StringRef name_,
|
||||
constexpr NameAndLocationRef( StringRef name_ CATCH_ATTR_LIFETIMEBOUND,
|
||||
SourceLineInfo location_ ):
|
||||
name( name_ ), location( location_ ) {}
|
||||
|
||||
@@ -91,12 +95,23 @@ namespace TestCaseTracking {
|
||||
Children m_children;
|
||||
CycleState m_runState = NotStarted;
|
||||
|
||||
public:
|
||||
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
|
||||
m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
|
||||
m_parent( parent )
|
||||
{}
|
||||
// Members for path filtering
|
||||
std::vector<PathFilter> const* m_filterRef = nullptr;
|
||||
|
||||
// Note: There are 2 dummy section trackers (root, test-case) before
|
||||
// the first "real" section tracker can be encountered. We start
|
||||
// the default tracker at -2, so that the first "real" section
|
||||
// tracker overflows to index 0.
|
||||
// Nesting depth of this tracker, used to decide which new-style filter applies.
|
||||
size_t m_allTrackerDepth = static_cast<size_t>( -2 );
|
||||
// Nesting depth of sections (inc. this tracker), used for old-style filters.
|
||||
// Must be updated by the section tracker on its own.
|
||||
size_t m_sectionOnlyDepth = static_cast<size_t>( -2 );
|
||||
// Transitory: Remove once we remove backwards compatibility with old-style (v3.x) filters
|
||||
bool m_newStyleFilters = false;
|
||||
|
||||
public:
|
||||
ITracker( NameAndLocation&& nameAndLoc, ITracker* parent );
|
||||
|
||||
// static queries
|
||||
NameAndLocation const& nameAndLocation() const {
|
||||
@@ -122,6 +137,11 @@ namespace TestCaseTracking {
|
||||
//! Returns true iff tracker has started
|
||||
bool hasStarted() const;
|
||||
|
||||
void setFilters( std::vector<PathFilter> const* filters, bool newStyleFilters ) {
|
||||
m_filterRef = filters;
|
||||
m_newStyleFilters = newStyleFilters;
|
||||
}
|
||||
|
||||
// actions
|
||||
virtual void close() = 0; // Successfully complete
|
||||
virtual void fail() = 0;
|
||||
@@ -207,8 +227,7 @@ namespace TestCaseTracking {
|
||||
void moveToThis();
|
||||
};
|
||||
|
||||
class SectionTracker : public TrackerBase {
|
||||
std::vector<StringRef> m_filters;
|
||||
class SectionTracker final : public TrackerBase {
|
||||
// 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
|
||||
@@ -225,10 +244,6 @@ namespace TestCaseTracking {
|
||||
|
||||
void tryOpen();
|
||||
|
||||
void addInitialFilters( std::vector<std::string> const& filters );
|
||||
void addNextFilters( std::vector<StringRef> const& filters );
|
||||
//! Returns filters active in this tracker
|
||||
std::vector<StringRef> const& getFilters() const { return m_filters; }
|
||||
//! Returns whitespace-trimmed name of the tracked section
|
||||
StringRef trimmedName() const;
|
||||
};
|
||||
|
||||
19
thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp
vendored
Normal file
19
thirdparty/catch2/src/main/native/include/catch2/internal/catch_thread_local.hpp
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#ifndef CATCH_THREAD_LOCAL_HPP_INCLUDED
|
||||
#define CATCH_THREAD_LOCAL_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
|
||||
#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS )
|
||||
#define CATCH_INTERNAL_THREAD_LOCAL thread_local
|
||||
#else
|
||||
#define CATCH_INTERNAL_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
#endif // CATCH_THREAD_LOCAL_HPP_INCLUDED
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
|
||||
#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
|
||||
#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS )
|
||||
# include <atomic>
|
||||
# include <mutex>
|
||||
#endif
|
||||
@@ -19,14 +19,14 @@
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
|
||||
#if defined( CATCH_CONFIG_THREAD_SAFE_ASSERTIONS )
|
||||
using Mutex = std::mutex;
|
||||
using LockGuard = std::lock_guard<std::mutex>;
|
||||
struct AtomicCounts {
|
||||
std::atomic<std::uint64_t> passed = 0;
|
||||
std::atomic<std::uint64_t> failed = 0;
|
||||
std::atomic<std::uint64_t> failedButOk = 0;
|
||||
std::atomic<std::uint64_t> skipped = 0;
|
||||
std::atomic<std::uint64_t> passed{ 0 };
|
||||
std::atomic<std::uint64_t> failed{ 0 };
|
||||
std::atomic<std::uint64_t> failedButOk{ 0 };
|
||||
std::atomic<std::uint64_t> skipped{ 0 };
|
||||
};
|
||||
#else // ^^ Use actual mutex, lock and atomics
|
||||
// vv Dummy implementations for single-thread performance
|
||||
|
||||
@@ -8,9 +8,22 @@
|
||||
#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED
|
||||
#define CATCH_UNIQUE_NAME_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_config_counter.hpp>
|
||||
|
||||
// Fixme: Clang 22 has an annoying bug where the localized suppression
|
||||
// below does not actually suppress the extension warning from
|
||||
// using __COUNTER__, so we have to leak the suppression for the
|
||||
// whole TU. Hopefully Clang 23 fixes this before full release.
|
||||
// As AppleClang does its own thing version-wise, we ignore it
|
||||
// completely.
|
||||
#if defined( __clang__ ) && ( __clang_major__ >= 22 ) && !defined( __APPLE__ )
|
||||
CATCH_INTERNAL_SUPPRESS_COUNTER_WARNINGS
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
|
||||
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
|
||||
|
||||
#ifdef CATCH_CONFIG_COUNTER
|
||||
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
|
||||
#else
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_XMLWRITER_HPP_INCLUDED
|
||||
#define CATCH_XMLWRITER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace Catch {
|
||||
public:
|
||||
enum ForWhat { ForTextNodes, ForAttributes };
|
||||
|
||||
constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
|
||||
constexpr XmlEncode( StringRef str CATCH_ATTR_LIFETIMEBOUND, ForWhat forWhat = ForTextNodes ):
|
||||
m_str( str ), m_forWhat( forWhat ) {}
|
||||
|
||||
|
||||
@@ -61,7 +62,7 @@ namespace Catch {
|
||||
|
||||
class ScopedElement {
|
||||
public:
|
||||
ScopedElement( XmlWriter* writer, XmlFormatting fmt );
|
||||
ScopedElement( XmlWriter* writer CATCH_ATTR_LIFETIMEBOUND, XmlFormatting fmt );
|
||||
|
||||
ScopedElement( ScopedElement&& other ) noexcept;
|
||||
ScopedElement& operator=( ScopedElement&& other ) noexcept;
|
||||
@@ -93,7 +94,7 @@ namespace Catch {
|
||||
XmlFormatting m_fmt;
|
||||
};
|
||||
|
||||
XmlWriter( std::ostream& os );
|
||||
XmlWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
~XmlWriter();
|
||||
|
||||
XmlWriter( XmlWriter const& ) = delete;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <catch2/matchers/internal/catch_matchers_impl.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -79,11 +80,15 @@ namespace Matchers {
|
||||
return description;
|
||||
}
|
||||
|
||||
friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) {
|
||||
friend MatchAllOf operator&&( MatchAllOf&& lhs,
|
||||
MatcherBase<ArgT> const& rhs
|
||||
CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
lhs.m_matchers.push_back(&rhs);
|
||||
return CATCH_MOVE(lhs);
|
||||
}
|
||||
friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) {
|
||||
friend MatchAllOf
|
||||
operator&&( MatcherBase<ArgT> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAllOf&& rhs ) {
|
||||
rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
|
||||
return CATCH_MOVE(rhs);
|
||||
}
|
||||
@@ -131,11 +136,15 @@ namespace Matchers {
|
||||
return description;
|
||||
}
|
||||
|
||||
friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) {
|
||||
friend MatchAnyOf operator||( MatchAnyOf&& lhs,
|
||||
MatcherBase<ArgT> const& rhs
|
||||
CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
lhs.m_matchers.push_back(&rhs);
|
||||
return CATCH_MOVE(lhs);
|
||||
}
|
||||
friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) {
|
||||
friend MatchAnyOf
|
||||
operator||( MatcherBase<ArgT> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAnyOf&& rhs ) {
|
||||
rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
|
||||
return CATCH_MOVE(rhs);
|
||||
}
|
||||
@@ -155,7 +164,8 @@ namespace Matchers {
|
||||
MatcherBase<ArgT> const& m_underlyingMatcher;
|
||||
|
||||
public:
|
||||
explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ):
|
||||
explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher
|
||||
CATCH_ATTR_LIFETIMEBOUND ):
|
||||
m_underlyingMatcher( underlyingMatcher )
|
||||
{}
|
||||
|
||||
@@ -171,16 +181,22 @@ namespace Matchers {
|
||||
} // namespace Detail
|
||||
|
||||
template <typename T>
|
||||
Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
|
||||
Detail::MatchAllOf<T>
|
||||
operator&&( MatcherBase<T> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherBase<T> const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return Detail::MatchAllOf<T>{} && lhs && rhs;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
|
||||
Detail::MatchAnyOf<T>
|
||||
operator||( MatcherBase<T> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherBase<T> const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return Detail::MatchAnyOf<T>{} || lhs || rhs;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) {
|
||||
Detail::MatchNotOf<T>
|
||||
operator!( MatcherBase<T> const& matcher CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return Detail::MatchNotOf<T>{ matcher };
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_logical_traits.hpp>
|
||||
|
||||
#include <array>
|
||||
@@ -114,7 +115,8 @@ namespace Matchers {
|
||||
MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
|
||||
MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
|
||||
|
||||
MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
|
||||
MatchAllOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND)
|
||||
: m_matchers{ {std::addressof(matchers)...} } {}
|
||||
explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
|
||||
|
||||
template<typename Arg>
|
||||
@@ -136,8 +138,8 @@ namespace Matchers {
|
||||
template<typename... MatchersRHS>
|
||||
friend
|
||||
MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
|
||||
MatchAllOfGeneric<MatcherTs...>&& lhs,
|
||||
MatchAllOfGeneric<MatchersRHS...>&& rhs) {
|
||||
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAllOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
@@ -145,8 +147,8 @@ namespace Matchers {
|
||||
template<typename MatcherRHS>
|
||||
friend std::enable_if_t<is_matcher_v<MatcherRHS>,
|
||||
MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
|
||||
MatchAllOfGeneric<MatcherTs...>&& lhs,
|
||||
MatcherRHS const& rhs) {
|
||||
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
|
||||
}
|
||||
|
||||
@@ -154,8 +156,8 @@ namespace Matchers {
|
||||
template<typename MatcherLHS>
|
||||
friend std::enable_if_t<is_matcher_v<MatcherLHS>,
|
||||
MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
|
||||
MatcherLHS const& lhs,
|
||||
MatchAllOfGeneric<MatcherTs...>&& rhs) {
|
||||
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAllOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
|
||||
}
|
||||
};
|
||||
@@ -169,7 +171,8 @@ namespace Matchers {
|
||||
MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
|
||||
MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
|
||||
|
||||
MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
|
||||
MatchAnyOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND)
|
||||
: m_matchers{ {std::addressof(matchers)...} } {}
|
||||
explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
|
||||
|
||||
template<typename Arg>
|
||||
@@ -190,8 +193,8 @@ namespace Matchers {
|
||||
//! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
|
||||
template<typename... MatchersRHS>
|
||||
friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
|
||||
MatchAnyOfGeneric<MatcherTs...>&& lhs,
|
||||
MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
|
||||
MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAnyOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
|
||||
}
|
||||
|
||||
@@ -199,8 +202,8 @@ namespace Matchers {
|
||||
template<typename MatcherRHS>
|
||||
friend std::enable_if_t<is_matcher_v<MatcherRHS>,
|
||||
MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
|
||||
MatchAnyOfGeneric<MatcherTs...>&& lhs,
|
||||
MatcherRHS const& rhs) {
|
||||
MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
|
||||
}
|
||||
|
||||
@@ -208,8 +211,8 @@ namespace Matchers {
|
||||
template<typename MatcherLHS>
|
||||
friend std::enable_if_t<is_matcher_v<MatcherLHS>,
|
||||
MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
|
||||
MatcherLHS const& lhs,
|
||||
MatchAnyOfGeneric<MatcherTs...>&& rhs) {
|
||||
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatchAnyOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND) {
|
||||
return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
|
||||
}
|
||||
};
|
||||
@@ -225,7 +228,8 @@ namespace Matchers {
|
||||
MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
|
||||
MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
|
||||
|
||||
explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
|
||||
explicit MatchNotOfGeneric(MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND)
|
||||
: m_matcher{matcher} {}
|
||||
|
||||
template<typename Arg>
|
||||
bool match(Arg&& arg) const {
|
||||
@@ -237,7 +241,9 @@ namespace Matchers {
|
||||
}
|
||||
|
||||
//! Negating negation can just unwrap and return underlying matcher
|
||||
friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
|
||||
friend MatcherT const&
|
||||
operator!( MatchNotOfGeneric<MatcherT> const& matcher
|
||||
CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return matcher.m_matcher;
|
||||
}
|
||||
};
|
||||
@@ -247,20 +253,22 @@ namespace Matchers {
|
||||
// compose only generic matchers
|
||||
template<typename MatcherLHS, typename MatcherRHS>
|
||||
std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
|
||||
operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
|
||||
operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename MatcherRHS>
|
||||
std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
|
||||
operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
|
||||
operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
//! Wrap provided generic matcher in generic negator
|
||||
template<typename MatcherT>
|
||||
std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>, Detail::MatchNotOfGeneric<MatcherT>>
|
||||
operator ! (MatcherT const& matcher) {
|
||||
operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return Detail::MatchNotOfGeneric<MatcherT>{matcher};
|
||||
}
|
||||
|
||||
@@ -268,25 +276,29 @@ namespace Matchers {
|
||||
// compose mixed generic and non-generic matchers
|
||||
template<typename MatcherLHS, typename ArgRHS>
|
||||
std::enable_if_t<Detail::is_generic_matcher_v<MatcherLHS>, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
|
||||
operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
|
||||
operator&&( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherBase<ArgRHS> const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
template<typename ArgLHS, typename MatcherRHS>
|
||||
std::enable_if_t<Detail::is_generic_matcher_v<MatcherRHS>, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
|
||||
operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
|
||||
operator&&( MatcherBase<ArgLHS> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
template<typename MatcherLHS, typename ArgRHS>
|
||||
std::enable_if_t<Detail::is_generic_matcher_v<MatcherLHS>, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
|
||||
operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
|
||||
operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherBase<ArgRHS> const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
template<typename ArgLHS, typename MatcherRHS>
|
||||
std::enable_if_t<Detail::is_generic_matcher_v<MatcherRHS>, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
|
||||
operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
|
||||
operator||( MatcherBase<ArgLHS> const& lhs CATCH_ATTR_LIFETIMEBOUND,
|
||||
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ namespace Catch {
|
||||
* format
|
||||
*/
|
||||
void defaultListListeners( std::ostream& out,
|
||||
std::vector<ListenerDescription> const& descriptions );
|
||||
std::vector<ListenerDescription> const& descriptions,
|
||||
Verbosity verbosity );
|
||||
|
||||
/**
|
||||
* Lists tag information to the provided stream in user-friendly format
|
||||
@@ -64,7 +65,10 @@ namespace Catch {
|
||||
* bases. The output should be backwards compatible with the output of
|
||||
* Catch2 v2 binaries.
|
||||
*/
|
||||
void defaultListTags( std::ostream& out, std::vector<TagInfo> const& tags, bool isFiltered );
|
||||
void defaultListTags( std::ostream& out,
|
||||
std::vector<TagInfo> const& tags,
|
||||
bool isFiltered,
|
||||
Verbosity verbosity );
|
||||
|
||||
/**
|
||||
* Lists test case information to the provided stream in user-friendly
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Catch {
|
||||
bool testOkToFail );
|
||||
|
||||
void writeAssertions(SectionNode const& sectionNode);
|
||||
void writeAssertion(AssertionStats const& stats);
|
||||
bool writeAssertion(AssertionStats const& stats);
|
||||
|
||||
XmlWriter xml;
|
||||
Timer suiteTimer;
|
||||
|
||||
@@ -49,7 +49,7 @@ def copy_upstream_src(wpilib_root: Path):
|
||||
def main():
|
||||
name = "catch2"
|
||||
url = "https://github.com/catchorg/Catch2.git"
|
||||
tag = "v3.10.0"
|
||||
tag = "v3.14.0"
|
||||
|
||||
patch_options = {
|
||||
"ignore_whitespace": True,
|
||||
|
||||
Reference in New Issue
Block a user