mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-25 05:55:40 +02:00
Compare commits
5 Commits
devel-spon
...
devel
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b626e4c7ae | ||
![]() |
434bf55d47 | ||
![]() |
9048c24fa7 | ||
![]() |
8ed8c431c6 | ||
![]() |
dc3a4ea41a |
@@ -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"
|
||||||
}
|
}
|
||||||
|
109
README-2.md
109
README-2.md
@@ -1,109 +0,0 @@
|
|||||||
<a id="top"></a>
|
|
||||||
|
|
||||||
<table width="100%">
|
|
||||||
<tr>
|
|
||||||
<td align="center" width="50%"><img src="/data/artwork/catch2-logo-full-with-background.svg" width="100%"></td>
|
|
||||||
<td align="center" width="50%"><figure><figcaption>Special thanks to:</figcaption><img src="/data/sponsors/github_repo_sponsorship-inverted.png" width="100%"></figure></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
[](https://github.com/catchorg/catch2/releases)
|
|
||||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)
|
|
||||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-other-builds.yml)
|
|
||||||
[](https://github.com/catchorg/Catch2/actions/workflows/mac-builds.yml)
|
|
||||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
|
||||||
[](https://codecov.io/gh/catchorg/Catch2)
|
|
||||||
[](https://godbolt.org/z/EdoY15q9G)
|
|
||||||
[](https://discord.gg/4CWS9zD)
|
|
||||||
|
|
||||||
|
|
||||||
## What is Catch2?
|
|
||||||
|
|
||||||
Catch2 is mainly a unit testing framework for C++, but it also
|
|
||||||
provides basic micro-benchmarking features, and simple BDD macros.
|
|
||||||
|
|
||||||
Catch2's main advantage is that using it is both simple and natural.
|
|
||||||
Test names do not have to be valid identifiers, assertions look like
|
|
||||||
normal C++ boolean expressions, and sections provide a nice and local way
|
|
||||||
to share set-up and tear-down code in tests.
|
|
||||||
|
|
||||||
**Example unit test**
|
|
||||||
```cpp
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
uint32_t factorial( uint32_t number ) {
|
|
||||||
return number <= 1 ? number : factorial(number-1) * number;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
|
||||||
REQUIRE( factorial( 1) == 1 );
|
|
||||||
REQUIRE( factorial( 2) == 2 );
|
|
||||||
REQUIRE( factorial( 3) == 6 );
|
|
||||||
REQUIRE( factorial(10) == 3'628'800 );
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example microbenchmark**
|
|
||||||
```cpp
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
uint64_t fibonacci(uint64_t number) {
|
|
||||||
return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
|
|
||||||
REQUIRE(fibonacci(5) == 5);
|
|
||||||
|
|
||||||
REQUIRE(fibonacci(20) == 6'765);
|
|
||||||
BENCHMARK("fibonacci 20") {
|
|
||||||
return fibonacci(20);
|
|
||||||
};
|
|
||||||
|
|
||||||
REQUIRE(fibonacci(25) == 75'025);
|
|
||||||
BENCHMARK("fibonacci 25") {
|
|
||||||
return fibonacci(25);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
_Note that benchmarks are not run by default, so you need to run it explicitly
|
|
||||||
with the `[!benchmark]` tag._
|
|
||||||
|
|
||||||
|
|
||||||
## Catch2 v3 has been released!
|
|
||||||
|
|
||||||
You are on the `devel` branch, where the v3 version is being developed.
|
|
||||||
v3 brings a bunch of significant changes, the big one being that Catch2
|
|
||||||
is no longer a single-header library. Catch2 now behaves as a normal
|
|
||||||
library, with multiple headers and separately compiled implementation.
|
|
||||||
|
|
||||||
The documentation is slowly being updated to take these changes into
|
|
||||||
account, but this work is currently still ongoing.
|
|
||||||
|
|
||||||
For migrating from the v2 releases to v3, you should look at [our
|
|
||||||
documentation](docs/migrate-v2-to-v3.md#top). It provides a simple
|
|
||||||
guidelines on getting started, and collects most common migration
|
|
||||||
problems.
|
|
||||||
|
|
||||||
For the previous major version of Catch2 [look into the `v2.x` branch
|
|
||||||
here on GitHub](https://github.com/catchorg/Catch2/tree/v2.x).
|
|
||||||
|
|
||||||
|
|
||||||
## How to use it
|
|
||||||
This documentation comprises these three parts:
|
|
||||||
|
|
||||||
* [Why do we need yet another C++ Test Framework?](docs/why-catch.md#top)
|
|
||||||
* [Tutorial](docs/tutorial.md#top) - getting started
|
|
||||||
* [Reference section](docs/Readme.md#top) - all the details
|
|
||||||
|
|
||||||
|
|
||||||
## More
|
|
||||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
|
||||||
* For discussion or questions please use [our Discord](https://discord.gg/4CWS9zD)
|
|
||||||
* See who else is using Catch2 in [Open Source Software](docs/opensource-users.md#top)
|
|
||||||
or [commercially](docs/commercial-users.md#top).
|
|
@@ -1,11 +1,5 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
|

|
||||||
<table width="100%">
|
|
||||||
<tr>
|
|
||||||
<td align="center" width="50%"><img src="/data/artwork/catch2-logo-full-with-background.svg" width="100%"></td>
|
|
||||||
<td align="center" width="50%"><figure><figcaption>Special thanks to:</figcaption><img src="/data/sponsors/github_repo_sponsorship.png" width="100%"></figure></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
[](https://github.com/catchorg/catch2/releases)
|
[](https://github.com/catchorg/catch2/releases)
|
||||||
[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)
|
[](https://github.com/catchorg/Catch2/actions/workflows/linux-simple-builds.yml)
|
||||||
|
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; }());
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 188 KiB |
Binary file not shown.
Before Width: | Height: | Size: 264 KiB |
@@ -66,11 +66,14 @@ test execution. Specifically it understands
|
|||||||
* JUnit output path via `XML_OUTPUT_FILE`
|
* JUnit output path via `XML_OUTPUT_FILE`
|
||||||
* Test filtering via `TESTBRIDGE_TEST_ONLY`
|
* Test filtering via `TESTBRIDGE_TEST_ONLY`
|
||||||
* Test sharding via `TEST_SHARD_INDEX`, `TEST_TOTAL_SHARDS`, and `TEST_SHARD_STATUS_FILE`
|
* Test sharding via `TEST_SHARD_INDEX`, `TEST_TOTAL_SHARDS`, and `TEST_SHARD_STATUS_FILE`
|
||||||
|
* Creating a file to signal premature test exit via `TEST_PREMATURE_EXIT_FILE`
|
||||||
|
|
||||||
> Support for `XML_OUTPUT_FILE` was [introduced](https://github.com/catchorg/Catch2/pull/2399) in Catch2 3.0.1
|
> Support for `XML_OUTPUT_FILE` was [introduced](https://github.com/catchorg/Catch2/pull/2399) in Catch2 3.0.1
|
||||||
|
|
||||||
> Support for `TESTBRIDGE_TEST_ONLY` and sharding was introduced in Catch2 3.2.0
|
> Support for `TESTBRIDGE_TEST_ONLY` and sharding was introduced in Catch2 3.2.0
|
||||||
|
|
||||||
|
> Support for `TEST_PREMATURE_EXIT_FILE` was introduced in Catch2 X.Y.Z
|
||||||
|
|
||||||
This integration is enabled via either a [compile time configuration
|
This integration is enabled via either a [compile time configuration
|
||||||
option](configuration.md#bazel-support), or via `BAZEL_TEST` environment
|
option](configuration.md#bazel-support), or via `BAZEL_TEST` environment
|
||||||
variable set to "1".
|
variable set to "1".
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
[Test Sharding](#test-sharding)<br>
|
[Test Sharding](#test-sharding)<br>
|
||||||
[Allow running the binary without tests](#allow-running-the-binary-without-tests)<br>
|
[Allow running the binary without tests](#allow-running-the-binary-without-tests)<br>
|
||||||
[Output verbosity](#output-verbosity)<br>
|
[Output verbosity](#output-verbosity)<br>
|
||||||
|
[Create file to guard against silent early termination](#create-file-to-guard-against-silent-early-termination)<br>
|
||||||
|
|
||||||
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
||||||
Click one of the following links to take you straight to that option - or scroll on to browse the available options.
|
Click one of the following links to take you straight to that option - or scroll on to browse the available options.
|
||||||
@@ -649,6 +650,21 @@ ignored.
|
|||||||
Verbosity defaults to _normal_.
|
Verbosity defaults to _normal_.
|
||||||
|
|
||||||
|
|
||||||
|
## Create file to guard against silent early termination
|
||||||
|
<pre>--premature-exit-guard-file <path></pre>
|
||||||
|
|
||||||
|
> Introduced in Catch2 X.Y.Z
|
||||||
|
|
||||||
|
Tells Catch2 to create an empty file at specified path before the tests
|
||||||
|
start, and delete it after the tests finish. If the file is present after
|
||||||
|
the process stops, it can be assumed that the testing binary exited
|
||||||
|
prematurely, e.g. due to the OOM killer.
|
||||||
|
|
||||||
|
All directories in the path must already exist. If this option is used
|
||||||
|
and Catch2 cannot create the file (e.g. the location is not writable),
|
||||||
|
the test run will fail.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -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
|
||||||
|
@@ -220,13 +220,17 @@
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
// Universal Windows platform does not support SEH
|
// Universal Windows platform does not support SEH
|
||||||
// Or console colours (or console at all...)
|
# if !defined(CATCH_PLATFORM_WINDOWS_UWP)
|
||||||
# if defined(CATCH_PLATFORM_WINDOWS_UWP)
|
|
||||||
# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
|
|
||||||
# else
|
|
||||||
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
||||||
# endif
|
# 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 preprocessor needs some workaround for __VA_ARGS__
|
||||||
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
|
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
|
||||||
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
|
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
|
||||||
|
@@ -161,7 +161,11 @@ namespace {
|
|||||||
#endif // Windows/ ANSI/ None
|
#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__ ) \
|
||||||
|
|| defined( CATCH_PLATFORM_QNX )
|
||||||
# define CATCH_INTERNAL_HAS_ISATTY
|
# define CATCH_INTERNAL_HAS_ISATTY
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
@@ -69,7 +69,7 @@
|
|||||||
#endif
|
#endif
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
#elif defined(CATCH_PLATFORM_LINUX)
|
#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@ namespace Catch {
|
|||||||
#define CATCH_TRAP() __asm__(".inst 0xde01")
|
#define CATCH_TRAP() __asm__(".inst 0xde01")
|
||||||
#endif
|
#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
|
// 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
|
// directly at the location of the failing check instead of breaking inside
|
||||||
// raise() called from it, i.e. one stack frame below.
|
// raise() called from it, i.e. one stack frame below.
|
||||||
|
@@ -25,6 +25,9 @@
|
|||||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
# define CATCH_PLATFORM_LINUX
|
# define CATCH_PLATFORM_LINUX
|
||||||
|
|
||||||
|
#elif defined(__QNX__)
|
||||||
|
# define CATCH_PLATFORM_QNX
|
||||||
|
|
||||||
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
|
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
# define CATCH_PLATFORM_WINDOWS
|
# define CATCH_PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -95,7 +95,7 @@ foreach(target DisabledExceptions-DefaultHandler DisabledExceptions-CustomHandle
|
|||||||
target_compile_options(${target}
|
target_compile_options(${target}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:/EHs-c-;/D_HAS_EXCEPTIONS=0>
|
$<$<CXX_COMPILER_ID:MSVC>:/EHs-c-;/D_HAS_EXCEPTIONS=0>
|
||||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:AppleClang>>:-fno-exceptions>
|
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:QCC>,$<CXX_COMPILER_ID:AppleClang>>:-fno-exceptions>
|
||||||
)
|
)
|
||||||
target_link_libraries(${target} Catch2_buildall_interface)
|
target_link_libraries(${target} Catch2_buildall_interface)
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -429,6 +429,50 @@ set_tests_properties(Reporters::CrashInJunitReporter
|
|||||||
LABELS "uses-signals"
|
LABELS "uses-signals"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
add_executable(QuickExitInTest ${TESTS_DIR}/X40-QuickExit.cpp)
|
||||||
|
target_link_libraries(QuickExitInTest PRIVATE Catch2::Catch2WithMain)
|
||||||
|
add_test(
|
||||||
|
NAME BazelEnv::TEST_PREMATURE_EXIT_FILE
|
||||||
|
COMMAND
|
||||||
|
Python3::Interpreter
|
||||||
|
"${CATCH_DIR}/tests/TestScripts/testBazelExitGuardFile.py"
|
||||||
|
$<TARGET_FILE:QuickExitInTest>
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
"bazel"
|
||||||
|
)
|
||||||
|
set_tests_properties(BazelEnv::TEST_PREMATURE_EXIT_FILE
|
||||||
|
PROPERTIES
|
||||||
|
LABELS "uses-python"
|
||||||
|
)
|
||||||
|
add_test(
|
||||||
|
NAME PrematureExitGuardFileCanBeUsedFromCLI::CheckAfterCrash
|
||||||
|
COMMAND
|
||||||
|
Python3::Interpreter
|
||||||
|
"${CATCH_DIR}/tests/TestScripts/testBazelExitGuardFile.py"
|
||||||
|
$<TARGET_FILE:QuickExitInTest>
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
"cli"
|
||||||
|
)
|
||||||
|
set_tests_properties(PrematureExitGuardFileCanBeUsedFromCLI::CheckAfterCrash
|
||||||
|
PROPERTIES
|
||||||
|
LABELS "uses-python"
|
||||||
|
)
|
||||||
|
add_test(
|
||||||
|
NAME PrematureExitGuardFileCanBeUsedFromCLI::CheckWithoutCrash
|
||||||
|
COMMAND
|
||||||
|
Python3::Interpreter
|
||||||
|
"${CATCH_DIR}/tests/TestScripts/testBazelExitGuardFile.py"
|
||||||
|
$<TARGET_FILE:QuickExitInTest>
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
"no-crash"
|
||||||
|
)
|
||||||
|
set_tests_properties(PrematureExitGuardFileCanBeUsedFromCLI::CheckWithoutCrash
|
||||||
|
PROPERTIES
|
||||||
|
LABELS "uses-python"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
add_executable(AssertionStartingEventGoesBeforeAssertionIsEvaluated
|
add_executable(AssertionStartingEventGoesBeforeAssertionIsEvaluated
|
||||||
X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp
|
X20-AssertionStartingEventGoesBeforeAssertionIsEvaluated.cpp
|
||||||
)
|
)
|
||||||
|
28
tests/ExtraTests/X40-QuickExit.cpp
Normal file
28
tests/ExtraTests/X40-QuickExit.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
|
||||||
|
|
||||||
|
/**\file
|
||||||
|
* Call ~~quick_exit~~ inside a test.
|
||||||
|
*
|
||||||
|
* This is used to test whether Catch2 properly creates the crash guard
|
||||||
|
* file based on provided arguments.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
TEST_CASE("quick_exit", "[quick_exit]") {
|
||||||
|
// Return 0 as fake "successful" exit, while there should be a guard
|
||||||
|
// file created and kept.
|
||||||
|
std::exit(0);
|
||||||
|
// We cannot use quick_exit because libstdc++ on older MacOS versions didn't support it yet.
|
||||||
|
// std::quick_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("pass") {}
|
88
tests/TestScripts/testBazelExitGuardFile.py
Executable file
88
tests/TestScripts/testBazelExitGuardFile.py
Executable file
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def generate_path_suffix() -> str:
|
||||||
|
return os.urandom(16).hex()[:16]
|
||||||
|
|
||||||
|
|
||||||
|
def run_common(cmd, env = None):
|
||||||
|
cmd_env = env if env is not None else os.environ.copy()
|
||||||
|
print('Running:', cmd)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ret = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
check=True,
|
||||||
|
universal_newlines=True,
|
||||||
|
env=cmd_env
|
||||||
|
)
|
||||||
|
except subprocess.SubprocessError as ex:
|
||||||
|
print('Could not run "{}"'.format(cmd))
|
||||||
|
print("Return code: {}".format(ex.returncode))
|
||||||
|
print("stdout: {}".format(ex.stdout))
|
||||||
|
print("stderr: {}".format(ex.stderr))
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def test_bazel_env_vars(bin_path, guard_path):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["TEST_PREMATURE_EXIT_FILE"] = guard_path
|
||||||
|
env["BAZEL_TEST"] = '1'
|
||||||
|
run_common([bin_path], env)
|
||||||
|
|
||||||
|
def test_cli_parameter(bin_path, guard_path):
|
||||||
|
cmd = [
|
||||||
|
bin_path,
|
||||||
|
'--premature-exit-guard-file',
|
||||||
|
guard_path
|
||||||
|
]
|
||||||
|
run_common(cmd)
|
||||||
|
|
||||||
|
def test_no_crash(bin_path, guard_path):
|
||||||
|
cmd = [
|
||||||
|
bin_path,
|
||||||
|
'--premature-exit-guard-file',
|
||||||
|
guard_path,
|
||||||
|
# Disable the quick-exit test
|
||||||
|
'~[quick_exit]'
|
||||||
|
]
|
||||||
|
run_common(cmd)
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
'bazel': (test_bazel_env_vars, True),
|
||||||
|
'cli': (test_cli_parameter, True),
|
||||||
|
'no-crash': (test_no_crash, False),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bin_path = os.path.abspath(sys.argv[1])
|
||||||
|
output_dir = os.path.abspath(sys.argv[2])
|
||||||
|
test_kind = sys.argv[3]
|
||||||
|
guard_file_path = os.path.join(output_dir, f"guard_file.{generate_path_suffix()}")
|
||||||
|
print(f'Guard file path: "{guard_file_path}"')
|
||||||
|
|
||||||
|
check_func, file_should_exist = checks[test_kind]
|
||||||
|
check_func(bin_path, guard_file_path)
|
||||||
|
|
||||||
|
assert os.path.exists(guard_file_path) == file_should_exist
|
||||||
|
# With randomly generated file suffix, we should not run into name conflicts.
|
||||||
|
# However, we try to cleanup anyway, to avoid having infinity files in
|
||||||
|
# long living build directories.
|
||||||
|
if file_should_exist:
|
||||||
|
try:
|
||||||
|
os.remove(guard_file_path)
|
||||||
|
except Exception as ex:
|
||||||
|
print(f'Could not remove file {guard_file_path} because: {ex}')
|
||||||
|
|
Reference in New Issue
Block a user