mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-25 14:05:39 +02:00
Compare commits
3 Commits
devel-fast
...
devel
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f7e7fa0983 | ||
![]() |
b626e4c7ae | ||
![]() |
434bf55d47 |
@@ -20,6 +20,7 @@ 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_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_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_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_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_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)
|
cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
|
||||||
@@ -77,6 +78,11 @@ set(SELF_TEST_DIR ${CATCH_DIR}/tests/SelfTest)
|
|||||||
# We need to bring-in the variables defined there to this scope
|
# We need to bring-in the variables defined there to this scope
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
if (CATCH_BUILD_BENCHMARKS)
|
||||||
|
set(CMAKE_FOLDER "benchmarks")
|
||||||
|
add_subdirectory(benchmarks)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Build tests only if requested
|
# Build tests only if requested
|
||||||
if(BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
if(BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||||
|
@@ -15,14 +15,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "all-tests",
|
"name": "most-tests",
|
||||||
"inherits": "basic-tests",
|
"inherits": "basic-tests",
|
||||||
"displayName": "Full development build",
|
"displayName": "Full development build",
|
||||||
"description": "Enables development build with examples and ALL tests",
|
"description": "Enables development build with extended set of tests (still relatively cheap to build)",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CATCH_BUILD_EXAMPLES": "ON",
|
"CATCH_BUILD_EXAMPLES": "ON",
|
||||||
"CATCH_BUILD_EXTRA_TESTS": "ON",
|
"CATCH_BUILD_EXTRA_TESTS": "ON",
|
||||||
"CATCH_BUILD_SURROGATES": "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_CONFIGURE_TESTS": "ON",
|
||||||
"CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
|
"CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
|
||||||
}
|
}
|
||||||
|
16
benchmarks/CMakeLists.txt
Normal file
16
benchmarks/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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)
|
28
benchmarks/assertion_listener.cpp
Normal file
28
benchmarks/assertion_listener.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
// 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 )
|
27
benchmarks/runtime_assertion_benches.cpp
Normal file
27
benchmarks/runtime_assertion_benches.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
// 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; }());
|
||||||
|
}
|
||||||
|
}
|
@@ -22,7 +22,7 @@ namespace Catch {
|
|||||||
m_messageId( builder.m_info.sequence ) {
|
m_messageId( builder.m_info.sequence ) {
|
||||||
MessageInfo info( CATCH_MOVE( builder.m_info ) );
|
MessageInfo info( CATCH_MOVE( builder.m_info ) );
|
||||||
info.message = builder.m_stream.str();
|
info.message = builder.m_stream.str();
|
||||||
getResultCapture().pushScopedMessage( CATCH_MOVE(info) );
|
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
|
||||||
@@ -31,15 +31,14 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScopedMessage::~ScopedMessage() {
|
ScopedMessage::~ScopedMessage() {
|
||||||
if ( !m_moved ) { getResultCapture().popScopedMessage( m_messageId ); }
|
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Capturer::Capturer( StringRef macroName,
|
Capturer::Capturer( StringRef macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
ResultWas::OfType resultType,
|
ResultWas::OfType resultType,
|
||||||
StringRef names ):
|
StringRef names ) {
|
||||||
m_resultCapture( getResultCapture() ) {
|
|
||||||
auto trimmed = [&] (size_t start, size_t end) {
|
auto trimmed = [&] (size_t start, size_t end) {
|
||||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||||
++start;
|
++start;
|
||||||
@@ -101,14 +100,14 @@ namespace Catch {
|
|||||||
Capturer::~Capturer() {
|
Capturer::~Capturer() {
|
||||||
assert( m_captured == m_messages.size() );
|
assert( m_captured == m_messages.size() );
|
||||||
for (auto const& message : m_messages) {
|
for (auto const& message : m_messages) {
|
||||||
m_resultCapture.popScopedMessage( message.sequence );
|
IResultCapture::popScopedMessage( message.sequence );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Capturer::captureValue( size_t index, std::string const& value ) {
|
void Capturer::captureValue( size_t index, std::string const& value ) {
|
||||||
assert( index < m_messages.size() );
|
assert( index < m_messages.size() );
|
||||||
m_messages[index].message += value;
|
m_messages[index].message += value;
|
||||||
m_resultCapture.pushScopedMessage( CATCH_MOVE(m_messages[index]) );
|
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||||
m_captured++;
|
m_captured++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,6 @@ namespace Catch {
|
|||||||
|
|
||||||
class Capturer {
|
class Capturer {
|
||||||
std::vector<MessageInfo> m_messages;
|
std::vector<MessageInfo> m_messages;
|
||||||
IResultCapture& m_resultCapture;
|
|
||||||
size_t m_captured = 0;
|
size_t m_captured = 0;
|
||||||
public:
|
public:
|
||||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||||
@@ -111,7 +110,7 @@ namespace Catch {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
|
#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)
|
#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
@@ -62,10 +62,9 @@ namespace Catch {
|
|||||||
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
|
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
|
||||||
virtual void benchmarkFailed( StringRef error ) = 0;
|
virtual void benchmarkFailed( StringRef error ) = 0;
|
||||||
|
|
||||||
virtual void pushScopedMessage( MessageInfo&& message ) = 0;
|
static void pushScopedMessage( MessageInfo&& message );
|
||||||
virtual void popScopedMessage( unsigned int messageId ) = 0;
|
static void popScopedMessage( unsigned int messageId );
|
||||||
|
static void emplaceUnscopedMessage( MessageBuilder&& builder );
|
||||||
virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
|
|
||||||
|
|
||||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||||
|
|
||||||
@@ -102,6 +101,7 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
IResultCapture& getResultCapture();
|
IResultCapture& getResultCapture();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
@@ -23,16 +24,16 @@ namespace Catch {
|
|||||||
std::ostringstream m_referenceStream; // Used for copy state/ flags from
|
std::ostringstream m_referenceStream; // Used for copy state/ flags from
|
||||||
Detail::Mutex m_mutex;
|
Detail::Mutex m_mutex;
|
||||||
|
|
||||||
auto add() -> std::size_t {
|
auto add() -> std::pair<std::size_t, std::ostringstream*> {
|
||||||
Detail::LockGuard _( m_mutex );
|
Detail::LockGuard _( m_mutex );
|
||||||
if( m_unused.empty() ) {
|
if( m_unused.empty() ) {
|
||||||
m_streams.push_back( Detail::make_unique<std::ostringstream>() );
|
m_streams.push_back( Detail::make_unique<std::ostringstream>() );
|
||||||
return m_streams.size()-1;
|
return { m_streams.size()-1, m_streams.back().get() };
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto index = m_unused.back();
|
auto index = m_unused.back();
|
||||||
m_unused.pop_back();
|
m_unused.pop_back();
|
||||||
return index;
|
return { index, m_streams[index].get() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,10 +47,10 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ReusableStringStream::ReusableStringStream()
|
ReusableStringStream::ReusableStringStream() {
|
||||||
: m_index( Singleton<StringStreams>::getMutable().add() ),
|
std::tie( m_index, m_oss ) =
|
||||||
m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
|
Singleton<StringStreams>::getMutable().add();
|
||||||
{}
|
}
|
||||||
|
|
||||||
ReusableStringStream::~ReusableStringStream() {
|
ReusableStringStream::~ReusableStringStream() {
|
||||||
static_cast<std::ostringstream*>( m_oss )->str("");
|
static_cast<std::ostringstream*>( m_oss )->str("");
|
||||||
|
@@ -483,28 +483,6 @@ namespace Catch {
|
|||||||
m_reporter->benchmarkFailed( error );
|
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 {
|
std::string RunContext::getCurrentTestName() const {
|
||||||
return m_activeTestCase
|
return m_activeTestCase
|
||||||
? m_activeTestCase->getTestCaseInfo().name
|
? m_activeTestCase->getTestCaseInfo().name
|
||||||
@@ -838,6 +816,28 @@ namespace Catch {
|
|||||||
CATCH_INTERNAL_ERROR("No result capture instance");
|
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) {
|
void seedRng(IConfig const& config) {
|
||||||
sharedRng().seed(config.rngSeed());
|
sharedRng().seed(config.rngSeed());
|
||||||
}
|
}
|
||||||
|
@@ -94,11 +94,6 @@ namespace Catch {
|
|||||||
void benchmarkEnded( BenchmarkStats<> const& stats ) override;
|
void benchmarkEnded( BenchmarkStats<> const& stats ) override;
|
||||||
void benchmarkFailed( StringRef error ) 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;
|
std::string getCurrentTestName() const override;
|
||||||
|
|
||||||
const AssertionResult* getLastResult() const override;
|
const AssertionResult* getLastResult() const override;
|
||||||
|
@@ -6,13 +6,11 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// 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/internal/catch_enum_values_registry.hpp>
|
||||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/catch_template_test_macros.hpp>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@@ -141,70 +139,3 @@ TEST_CASE( "Exception thrown inside stringify does not fail the test", "[toStrin
|
|||||||
ThrowsOnStringification tos;
|
ThrowsOnStringification tos;
|
||||||
CHECK( tos == 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 );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user