Compare commits

..

1 Commits

Author SHA1 Message Date
Martin Hořeňovský
48f121b6d4 WIP 2025-09-22 22:41:14 +02:00
11 changed files with 112 additions and 122 deletions

View File

@@ -20,7 +20,6 @@ cmake_dependent_option(CATCH_BUILD_TESTING "Build the SelfTest project" ON "CATC
cmake_dependent_option(CATCH_BUILD_EXAMPLES "Build code examples" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_BUILD_FUZZERS "Build fuzzers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_BUILD_BENCHMARKS "Build the benchmarks" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
@@ -78,11 +77,6 @@ set(SELF_TEST_DIR ${CATCH_DIR}/tests/SelfTest)
# We need to bring-in the variables defined there to this scope
add_subdirectory(src)
if (CATCH_BUILD_BENCHMARKS)
set(CMAKE_FOLDER "benchmarks")
add_subdirectory(benchmarks)
endif()
# Build tests only if requested
if(BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
find_package(Python3 REQUIRED COMPONENTS Interpreter)

View File

@@ -15,23 +15,14 @@
}
},
{
"name": "most-tests",
"name": "all-tests",
"inherits": "basic-tests",
"displayName": "Full development build",
"description": "Enables development build with extended set of tests (still relatively cheap to build)",
"description": "Enables development build with examples and ALL tests",
"cacheVariables": {
"CATCH_BUILD_EXAMPLES": "ON",
"CATCH_BUILD_EXTRA_TESTS": "ON",
"CATCH_BUILD_SURROGATES": "ON",
"CATCH_BUILD_BENCHMARKS": "ON"
}
},
{
"name": "all-tests",
"inherits": "most-tests",
"displayName": "Full development build",
"description": "Enables development build with examples and ALL tests",
"cacheVariables": {
"CATCH_ENABLE_CONFIGURE_TESTS": "ON",
"CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
}

View File

@@ -1,16 +0,0 @@
include(CatchMiscFunctions)
add_executable(AssertionsFastPath
runtime_assertion_benches.cpp
)
add_executable(AssertionsSlowPath
runtime_assertion_benches.cpp
assertion_listener.cpp
)
target_link_libraries(AssertionsFastPath PRIVATE Catch2::Catch2WithMain)
target_link_libraries(AssertionsSlowPath PRIVATE Catch2::Catch2WithMain)
list(APPEND CATCH_TEST_TARGETS AssertionsFastPath AssertionsSlowPath)
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)

View File

@@ -1,28 +0,0 @@
// 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/reporters/catch_reporter_event_listener.hpp>
#include <catch2/reporters/catch_reporter_registrars.hpp>
/**
* Event listener that listens to all assertions, forcing assertion slow path
*/
class AssertionSlowPathListener : public Catch::EventListenerBase {
public:
static std::string getDescription() {
return "Validates ordering of Catch2's listener events";
}
AssertionSlowPathListener(Catch::IConfig const* config) :
EventListenerBase(config) {
m_preferences.shouldReportAllAssertions = true;
m_preferences.shouldReportAllAssertionStarts = true;
}
};
CATCH_REGISTER_LISTENER( AssertionSlowPathListener )

View File

@@ -1,27 +0,0 @@
// 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/catch_test_macros.hpp>
TEST_CASE("Simple REQUIRE - 10M") {
for (size_t i = 0; i < 10'000'000; ++i) {
REQUIRE(true);
}
}
TEST_CASE("Simple NOTHROW - 10M") {
for (size_t i = 0; i < 10'000'000; ++i) {
REQUIRE_NOTHROW([](){}());
}
}
TEST_CASE("Simple THROWS - 10M") {
for (size_t i = 0; i < 10'000'000; ++i) {
REQUIRE_THROWS([]() { throw 1; }());
}
}

View File

@@ -22,7 +22,7 @@ namespace Catch {
m_messageId( builder.m_info.sequence ) {
MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str();
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
getResultCapture().pushScopedMessage( CATCH_MOVE(info) );
}
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
@@ -31,14 +31,15 @@ namespace Catch {
}
ScopedMessage::~ScopedMessage() {
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
if ( !m_moved ) { getResultCapture().popScopedMessage( m_messageId ); }
}
Capturer::Capturer( StringRef macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType resultType,
StringRef names ) {
StringRef names ):
m_resultCapture( getResultCapture() ) {
auto trimmed = [&] (size_t start, size_t end) {
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
++start;
@@ -100,14 +101,14 @@ namespace Catch {
Capturer::~Capturer() {
assert( m_captured == m_messages.size() );
for (auto const& message : m_messages) {
IResultCapture::popScopedMessage( message.sequence );
m_resultCapture.popScopedMessage( message.sequence );
}
}
void Capturer::captureValue( size_t index, std::string const& value ) {
assert( index < m_messages.size() );
m_messages[index].message += value;
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
m_resultCapture.pushScopedMessage( CATCH_MOVE(m_messages[index]) );
m_captured++;
}

View File

@@ -63,6 +63,7 @@ namespace Catch {
class Capturer {
std::vector<MessageInfo> m_messages;
IResultCapture& m_resultCapture;
size_t m_captured = 0;
public:
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
@@ -110,7 +111,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)

View File

@@ -62,9 +62,10 @@ namespace Catch {
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
virtual void benchmarkFailed( StringRef error ) = 0;
static void pushScopedMessage( MessageInfo&& message );
static void popScopedMessage( unsigned int messageId );
static void emplaceUnscopedMessage( MessageBuilder&& builder );
virtual void pushScopedMessage( MessageInfo&& message ) = 0;
virtual void popScopedMessage( unsigned int messageId ) = 0;
virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
virtual void handleFatalErrorCondition( StringRef message ) = 0;
@@ -101,7 +102,6 @@ namespace Catch {
};
IResultCapture& getResultCapture();
}
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED

View File

@@ -483,6 +483,28 @@ namespace Catch {
m_reporter->benchmarkFailed( error );
}
void RunContext::pushScopedMessage( MessageInfo&& message ) {
Detail::g_messages.push_back( CATCH_MOVE(message) );
}
void RunContext::popScopedMessage( 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 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(),
[=]( MessageInfo const& msg ) {
return msg.sequence == messageId;
} ) );
}
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
@@ -816,28 +838,6 @@ namespace Catch {
CATCH_INTERNAL_ERROR("No result capture instance");
}
void IResultCapture::pushScopedMessage( MessageInfo&& message ) {
Detail::g_messages.push_back( CATCH_MOVE( message ) );
}
void IResultCapture::popScopedMessage( 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 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(),
[=]( MessageInfo const& msg ) {
return msg.sequence ==
messageId;
} ) );
}
void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) {
Detail::g_messageScopes.emplace_back( CATCH_MOVE( builder ) );
}
void seedRng(IConfig const& config) {
sharedRng().seed(config.rngSeed());
}

View File

@@ -94,6 +94,11 @@ namespace Catch {
void benchmarkEnded( BenchmarkStats<> const& stats ) override;
void benchmarkFailed( StringRef error ) override;
void pushScopedMessage( MessageInfo&& message ) override;
void popScopedMessage( unsigned int messageId ) override;
void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
std::string getCurrentTestName() const override;
const AssertionResult* getLastResult() const override;

View File

@@ -6,11 +6,13 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/benchmark/catch_benchmark.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <catch2/matchers/catch_matchers_vector.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include <chrono>
@@ -139,3 +141,70 @@ TEST_CASE( "Exception thrown inside stringify does not fail the test", "[toStrin
ThrowsOnStringification tos;
CHECK( tos == tos );
}
namespace {
[[maybe_unused]]
std::string convertIntoString( Catch::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 );
if ( !escapeInvisibles ) {
ret += '"';
ret += string;
ret += '"';
return ret;
}
size_t last_start = 0;
auto write_to = [&]( size_t idx ) {
if ( last_start < idx ) {
//ret.append( string.data() + last_start, idx - last_start );
ret += string.substr( last_start, idx - last_start );
}
last_start = idx + 1;
};
ret += '"';
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;
}
}
TEST_CASE( "string escaping benchmark", "[toString][!benchmark]" ) {
const auto input_length = GENERATE( as<size_t>{}, 10, 100, 10'000, 100'000 );
std::string test_input( input_length, 'a' );
BENCHMARK( "no-escape string, no-escaping, len=" +
std::to_string( input_length ) ) {
return Catch::Detail::convertIntoString( test_input, false );
};
BENCHMARK( "no-escape string, escaping, len=" +
std::to_string( input_length ) ) {
return Catch::Detail::convertIntoString( test_input, true );
};
std::string escape_input( input_length, '\r' );
BENCHMARK( "full escape string, no-escaping, len=" +
std::to_string( input_length ) ) {
return Catch::Detail::convertIntoString( escape_input, false );
};
BENCHMARK( "full escape string, escaping, len=" +
std::to_string( input_length ) ) {
return Catch::Detail::convertIntoString( escape_input, true );
};
}