mirror of
https://github.com/catchorg/Catch2.git
synced 2025-10-05 19:41:09 +02:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
33e6fd217a | ||
|
a58df2d7c5 | ||
|
a9223b2bb3 | ||
|
363ca5af18 | ||
|
cb6d713774 | ||
|
8e4ab5dd8f | ||
|
8219ed79f2 | ||
|
b3fb4b9fea | ||
|
6500dc8149 | ||
|
4be9de6c54 | ||
|
91b3b3bf40 | ||
|
a00d654437 | ||
|
756ae05d30 | ||
|
a2e41916f2 | ||
|
0e772cc0d2 | ||
|
3bcd0a4e74 | ||
|
f7e7fa0983 | ||
|
b626e4c7ae | ||
|
434bf55d47 | ||
|
9048c24fa7 | ||
|
8ed8c431c6 | ||
|
dc3a4ea41a | ||
|
cd93d202e0 | ||
|
227af796b4 | ||
|
33adb4c779 | ||
|
25319fd304 | ||
|
85c4bad86b | ||
|
582200a1f8 | ||
|
f4e05a67bb | ||
|
fb2e4fbe41 | ||
|
78a9518a28 | ||
|
3e82ef9317 | ||
|
7cad6d7539 | ||
|
644821ce28 | ||
|
03c62cdf2e | ||
|
9a3d68315b | ||
|
bcd4116df7 | ||
|
9b3f508a1b | ||
|
c5e0ef4e67 | ||
|
17fe5eaa5c | ||
|
fbfd13501c | ||
|
ccabd4de89 | ||
|
a1c7ee115f | ||
|
d547cae549 |
@@ -78,5 +78,5 @@ WarningsAsErrors: >-
|
||||
readability-duplicate-include,
|
||||
HeaderFilterRegex: '.*\.(c|cxx|cpp)$'
|
||||
FormatStyle: none
|
||||
CheckOptions: {}
|
||||
CheckOptions: []
|
||||
...
|
||||
|
@@ -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_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)
|
||||
@@ -34,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
endif()
|
||||
|
||||
project(Catch2
|
||||
VERSION 3.9.0 # CML version placeholder, don't delete
|
||||
VERSION 3.11.0 # CML version placeholder, don't delete
|
||||
LANGUAGES CXX
|
||||
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
|
||||
DESCRIPTION "A modern, C++-native, unit test framework."
|
||||
@@ -77,6 +78,11 @@ 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)
|
||||
@@ -195,17 +201,23 @@ if(NOT_SUBPROJECT)
|
||||
"set(include_dir \"${CMAKE_INSTALL_INCLUDEDIR}\")"
|
||||
"set(lib_dir \"${CMAKE_INSTALL_LIBDIR}\")"
|
||||
[[
|
||||
message(STATUS "DESTDIR: $ENV{DESTDIR}")
|
||||
set(DESTDIR_PREFIX "")
|
||||
if (DEFINED ENV{DESTDIR})
|
||||
set(DESTDIR_PREFIX "$ENV{DESTDIR}")
|
||||
endif ()
|
||||
message(STATUS "PREFIX: ${DESTDIR_PREFIX}")
|
||||
set(lib_name "$<TARGET_FILE_BASE_NAME:Catch2>")
|
||||
configure_file(
|
||||
"${impl_pc_file}"
|
||||
"${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2.pc"
|
||||
"${DESTDIR_PREFIX}${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2.pc"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(lib_name "$<TARGET_FILE_BASE_NAME:Catch2WithMain>")
|
||||
configure_file(
|
||||
"${main_pc_file}"
|
||||
"${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2-with-main.pc"
|
||||
"${DESTDIR_PREFIX}${CMAKE_INSTALL_PREFIX}/${install_pkgconfdir}/catch2-with-main.pc"
|
||||
@ONLY
|
||||
)
|
||||
]]
|
||||
|
@@ -15,14 +15,23 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "all-tests",
|
||||
"name": "most-tests",
|
||||
"inherits": "basic-tests",
|
||||
"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": {
|
||||
"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"
|
||||
}
|
||||
|
13
README.md
13
README.md
@@ -1,5 +1,16 @@
|
||||
<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>
|
||||
<a href="https://tuple.app/catch2"><img src="/data/sponsors/github_repo_sponsorship.png" width="100%"></a>
|
||||
</figure>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[](https://github.com/catchorg/catch2/releases)
|
||||
[](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; }());
|
||||
}
|
||||
}
|
BIN
data/sponsors/github_repo_sponsorship.png
Normal file
BIN
data/sponsors/github_repo_sponsorship.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
@@ -66,17 +66,24 @@ test execution. Specifically it understands
|
||||
* JUnit output path via `XML_OUTPUT_FILE`
|
||||
* Test filtering via `TESTBRIDGE_TEST_ONLY`
|
||||
* 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`
|
||||
* Setting the RNG seed via `TEST_RANDOM_SEED`
|
||||
|
||||
> 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 `TEST_PREMATURE_EXIT_FILE` and `TEST_RANDOM_SEED` was introduced in Catch2 3.11.0
|
||||
|
||||
This integration is enabled via either a [compile time configuration
|
||||
option](configuration.md#bazel-support), or via `BAZEL_TEST` environment
|
||||
variable set to "1".
|
||||
|
||||
> Support for `BAZEL_TEST` was [introduced](https://github.com/catchorg/Catch2/pull/2459) in Catch2 3.1.0
|
||||
|
||||
Note that if both the Bazel environment var and command line option for
|
||||
something are used, the environment variable wins.
|
||||
|
||||
|
||||
## Low-level tools
|
||||
|
||||
|
@@ -32,6 +32,7 @@
|
||||
[Test Sharding](#test-sharding)<br>
|
||||
[Allow running the binary without tests](#allow-running-the-binary-without-tests)<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.
|
||||
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_.
|
||||
|
||||
|
||||
## Create file to guard against silent early termination
|
||||
<pre>--premature-exit-guard-file <path></pre>
|
||||
|
||||
> Introduced in Catch2 3.11.0
|
||||
|
||||
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)
|
||||
|
@@ -114,11 +114,12 @@ a test case,
|
||||
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
|
||||
on elements from a different generator
|
||||
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
|
||||
* 4 specific purpose generators (defined in `catch2/generators/catch_generators_random.hpp`)
|
||||
* 2 random generators (defined in `catch2/generators/catch_generators_random.hpp`)
|
||||
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
|
||||
* `RandomFloatGenerator<Float>` -- generates random Floats from range
|
||||
* `RangeGenerator<T>(first, last)` -- generates all values inside a `[first, last)` arithmetic range (defined in `catch2/generators/catch_generators_range.hpp`)
|
||||
* `IteratorGenerator<T>` -- copies and returns values from an iterator range (defined in `catch2/generators/catch_generators_range.hpp`)
|
||||
* 2 range generators (defined in `catch2/generators/catch_generators_range.hpp`)
|
||||
* `RangeGenerator<T>(first, last)` -- generates all values inside a `[first, last)` arithmetic range
|
||||
* `IteratorGenerator<T>` -- copies and returns values from an iterator range
|
||||
|
||||
> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch2 2.7.0.
|
||||
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[3.11.0](#3110)<br>
|
||||
[3.10.0](#3100)<br>
|
||||
[3.9.1](#391)<br>
|
||||
[3.9.0](#390)<br>
|
||||
[3.8.1](#381)<br>
|
||||
[3.8.0](#380)<br>
|
||||
@@ -68,6 +71,54 @@
|
||||
[Even Older versions](#even-older-versions)<br>
|
||||
|
||||
|
||||
## 3.11.0
|
||||
|
||||
### Fixes
|
||||
* Fixed building on non-desktop GDK platforms (#3029)
|
||||
* Fixed message macros being susceptible to race in specific scenario (#3031)
|
||||
* Catch2's SEH filter will call the previously installed filter after reporting the error (#3033)
|
||||
|
||||
### Improvements
|
||||
* Handling of scoped messages (e.g. `CAPTURE`) is a bit faster.
|
||||
* Better out-of-the-box support for QNX (#2953)
|
||||
* Improved performance of assertions by up-to 10%
|
||||
* Release mode assertion fast-path sees the biggest improvement.
|
||||
* Faster processing of non-escaped strings in `--invisibles` mode.
|
||||
* Added support for Bazel's `TEST_RANDOM_SEED` env var (#3021)
|
||||
* Added support for Bazel's `TEST_PREMATURE_EXIT_FILE` env var (#3020)
|
||||
* This creates a file that is deleted if the tests exit normally, but stays around if the process dies unexpectedly.
|
||||
* This functionality is also exposed through CLI as `--premature-exit-guard-file`
|
||||
|
||||
### Miscellaneous
|
||||
* **[Tuple.app](https://tuple.app/catch2) has sponsored Catch2**
|
||||
|
||||
|
||||
## 3.10.0
|
||||
|
||||
### Fixes
|
||||
* pkg-config files will take `DESTDIR` env var into account when selecting install destination (#3006, #3019)
|
||||
* Changed `filter` to store the provided predicate by value (#3002, #3005)
|
||||
* This is done to avoid dangling-by-default behaviour when `filter` is used inside `GENERATE_COPY`/`GENERATE_REF`.
|
||||
|
||||
### Improvements
|
||||
* Escaping XML and JSON output is faster when the strings do not need escaping.
|
||||
* The improvement starts at about 3x throughput, up to 10x for long strings.
|
||||
* Message macros (`INFO`, `CAPTURE`, `WARN`, `SUCCEED`, etc) are now thread safe.
|
||||
|
||||
|
||||
## 3.9.1
|
||||
|
||||
### Fixes
|
||||
* Fixed bad error reporting for multiple nested assertions (#1292)
|
||||
* Fixed W4702 (unreachable code) in the polyfill for std::unreachable (#3007)
|
||||
* Fixed decomposition of assertions comparing enum-backed bitfields (#3001)
|
||||
* Fixed StringMaker specialization for `time_point<system_clock>` with non-default duration type (#2685)
|
||||
|
||||
### Improvements
|
||||
* Exceptions thrown during stringification of decomposed expression no longer fail the assertion (#2980)
|
||||
* The selection logic for `CATCH_TRAP` prefers `__builtin_debugtrap` on all platforms when Catch2 is compiled with Clang
|
||||
|
||||
|
||||
## 3.9.0
|
||||
|
||||
### Improvements
|
||||
|
@@ -52,6 +52,20 @@ TEST_CASE("failing test") {
|
||||
}
|
||||
```
|
||||
|
||||
Same applies for a `SKIP` nested inside an assertion:
|
||||
|
||||
```cpp
|
||||
static bool do_skip() {
|
||||
SKIP();
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Another failing test") {
|
||||
CHECK(do_skip());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Interaction with Sections and Generators
|
||||
|
||||
Sections, nested sections as well as specific outputs from [generators](generators.md#top)
|
||||
|
@@ -2,7 +2,9 @@
|
||||
# Thread safety in Catch2
|
||||
|
||||
**Contents**<br>
|
||||
[Using assertion macros from multiple threads](#using-assertion-macros-from-multiple-threads)<br>
|
||||
[Using assertion macros from spawned threads](#using-assertion-macros-from-spawned-threads)<br>
|
||||
[Assertion-like message macros and spawned threads](#assertion-like-message-macros-and-spawned-threads)<br>
|
||||
[Message macros and spawned threads](#message-macros-and-spawned-threads)<br>
|
||||
[examples](#examples)<br>
|
||||
[`STATIC_REQUIRE` and `STATIC_CHECK`](#static_require-and-static_check)<br>
|
||||
[Fatal errors and multiple threads](#fatal-errors-and-multiple-threads)<br>
|
||||
@@ -10,17 +12,18 @@
|
||||
|
||||
> Thread safe assertions were introduced in Catch2 3.9.0
|
||||
|
||||
Thread safety in Catch2 is currently limited to all the assertion macros.
|
||||
Interacting with benchmark macros, message macros (e.g. `INFO` or `CAPTURE`),
|
||||
sections macros, generator macros, or test case macros is not thread-safe.
|
||||
The message macros are likely to be made thread-safe in the future, but
|
||||
the way sections define test runs is incompatible with user being able
|
||||
to spawn threads arbitrarily, thus that limitation is here to stay.
|
||||
Thread safety in Catch2 is currently limited to all the assertion macros,
|
||||
and to message or message-adjacent macros (e.g. `INFO` or `WARN`).
|
||||
|
||||
Interacting with benchmark macros, sections macros, generator macros, or
|
||||
test case macros is not thread-safe. The way sections define paths through
|
||||
the test is incompatible with user spawning threads arbitrarily, so this
|
||||
limitation is here to stay.
|
||||
|
||||
**Important: thread safety in Catch2 is [opt-in](configuration.md#experimental-thread-safety)**
|
||||
|
||||
|
||||
## Using assertion macros from multiple threads
|
||||
## Using assertion macros from spawned threads
|
||||
|
||||
The full set of Catch2's runtime assertion macros is thread-safe. However,
|
||||
it is important to keep in mind that their semantics might not support
|
||||
@@ -30,7 +33,7 @@ Specifically, the `REQUIRE` family of assertion macros have semantics
|
||||
of stopping the test execution on failure. This is done by throwing
|
||||
an exception, but since the user-spawned thread will not have the test-level
|
||||
try-catch block ready to catch the test failure exception, failing a
|
||||
`REQUIRE` assertion inside this thread will terminate the process.
|
||||
`REQUIRE` assertion inside user-spawned thread will terminate the process.
|
||||
|
||||
The `CHECK` family of assertions does not have this issue, because it
|
||||
does not try to stop the test execution.
|
||||
@@ -38,16 +41,36 @@ does not try to stop the test execution.
|
||||
Note that `CHECKED_IF` and `CHECKED_ELSE` are also thread safe (internally
|
||||
they are assertion macro + an if).
|
||||
|
||||
**`SKIP()`, `FAIL()`, `SUCCEED()` are not assertion macros, and are not
|
||||
thread-safe.**
|
||||
|
||||
## Assertion-like message macros and spawned threads
|
||||
|
||||
> Assertion-like messages were made thread safe in Catch2 3.10.0
|
||||
|
||||
Similarly to assertion macros, not all assertion-like message macros can
|
||||
be used from spawned thread.
|
||||
|
||||
`SKIP` and `FAIL` macros stop the test execution. Just like with `REQUIRE`,
|
||||
this means that they cannot be used inside user-spawned threads. `SUCCEED`,
|
||||
`FAIL_CHECK` and `WARN` do not attempt to stop the test execution and
|
||||
thus can be used from any thread.
|
||||
|
||||
|
||||
## Message macros and spawned threads
|
||||
|
||||
> Message macros were made thread safe in Catch2 3.10.0
|
||||
|
||||
Macros that add extra messages to following assertion, such as `INFO`
|
||||
or `CAPTURE`, are all thread safe and can be used in any thread. Note
|
||||
that these messages are per-thread, and thus `INFO` inside a user-spawned
|
||||
thread will not be seen by the main thread, and vice versa.
|
||||
|
||||
|
||||
## examples
|
||||
|
||||
### `REQUIRE` from main thread, `CHECK` from spawned threads
|
||||
### `REQUIRE` from the main thread, `CHECK` from spawned threads
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "Failed REQUIRE in main thread is fine" ) {
|
||||
TEST_CASE( "Failed REQUIRE in the main thread is fine" ) {
|
||||
std::vector<std::jthread> threads;
|
||||
for ( size_t t = 0; t < 16; ++t) {
|
||||
threads.emplace_back( []() {
|
||||
@@ -85,7 +108,7 @@ TEST_CASE( "Successful REQUIRE in spawned thread is fine" ) {
|
||||
This will also work as expected, because the `REQUIRE` is successful.
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "Failed REQUIRE in spawned thread is fine" ) {
|
||||
TEST_CASE( "Failed REQUIRE in spawned thread kills the process" ) {
|
||||
std::vector<std::jthread> threads;
|
||||
for ( size_t t = 0; t < 16; ++t) {
|
||||
threads.emplace_back( []() {
|
||||
@@ -99,12 +122,88 @@ TEST_CASE( "Failed REQUIRE in spawned thread is fine" ) {
|
||||
This will fail catastrophically and terminate the process.
|
||||
|
||||
|
||||
### INFO across threads
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "messages don't cross threads" ) {
|
||||
std::jthread t1( [&]() {
|
||||
for ( size_t i = 0; i < 100; ++i ) {
|
||||
INFO( "spawned thread #1" );
|
||||
CHECK( 1 == 1 );
|
||||
}
|
||||
} );
|
||||
|
||||
std::thread t2( [&]() {
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
UNSCOPED_INFO( "spawned thread #2" );
|
||||
}
|
||||
} );
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
CHECK( 1 == 2 );
|
||||
}
|
||||
}
|
||||
```
|
||||
None of the failed checks will show the "spawned thread #1" message, as
|
||||
that message is for the `t1` thread. If the reporter shows passing
|
||||
assertions (e.g. due to the tests being run with `-s`), you will see the
|
||||
"spawned thread #1" message alongside the passing `CHECK( 1 == 1 )` assertion.
|
||||
|
||||
The message "spawned thread #2" will never be shown, because there are no
|
||||
assertions in `t2`.
|
||||
|
||||
|
||||
### FAIL/SKIP from the main thread
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "FAIL in the main thread is fine" ) {
|
||||
std::vector<std::jthread> threads;
|
||||
for ( size_t t = 0; t < 16; ++t) {
|
||||
threads.emplace_back( []() {
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
CHECK( true );
|
||||
CHECK( false );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
FAIL();
|
||||
}
|
||||
```
|
||||
|
||||
This will work as expected, that is, the process will finish running
|
||||
normally, the test case will fail and there will be 321 total assertions,
|
||||
160 passing and 161 failing (`FAIL` counts as failed assertion).
|
||||
|
||||
However, when the main thread hits `FAIL`, it will wait for the other
|
||||
threads to finish due to `std::jthread`'s destructor joining the spawned
|
||||
thread. Due to this, using `SKIP` is not recommended once more threads
|
||||
are spawned; while the main thread will bail from the test execution,
|
||||
the spawned threads will keep running and may fail the test case.
|
||||
|
||||
|
||||
### FAIL/SKIP from spawned threads
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "FAIL/SKIP in spawned thread kills the process" ) {
|
||||
std::vector<std::jthread> threads;
|
||||
for ( size_t t = 0; t < 16; ++t) {
|
||||
threads.emplace_back( []() {
|
||||
for (size_t i = 0; i < 10'000; ++i) {
|
||||
FAIL();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
```
|
||||
As with failing `REQUIRE`, both `FAIL` and `SKIP` in spawned threads
|
||||
terminate the process.
|
||||
|
||||
|
||||
## `STATIC_REQUIRE` and `STATIC_CHECK`
|
||||
|
||||
None of `STATIC_REQUIRE`, `STATIC_REQUIRE_FALSE`, `STATIC_CHECK`, and
|
||||
`STATIC_CHECK_FALSE` are currently thread safe. This might be surprising
|
||||
given that they are a compile-time checks, but they also rely on the
|
||||
message macros to register the result with reporter at runtime.
|
||||
All of `STATIC_REQUIRE`, `STATIC_REQUIRE_FALSE`, `STATIC_CHECK`, and
|
||||
`STATIC_CHECK_FALSE` are thread safe in the delayed evaluation configuration.
|
||||
|
||||
|
||||
## Fatal errors and multiple threads
|
||||
|
@@ -6,8 +6,8 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
// Catch v3.9.0
|
||||
// Generated: 2025-07-24 22:00:25.173359
|
||||
// Catch v3.11.0
|
||||
// Generated: 2025-09-30 10:49:12.549018
|
||||
// ----------------------------------------------------------
|
||||
// This file is an amalgamation of multiple different files.
|
||||
// You probably shouldn't edit it directly.
|
||||
@@ -825,6 +825,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();
|
||||
}
|
||||
@@ -889,6 +891,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; }
|
||||
@@ -950,6 +954,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
|
||||
@@ -975,28 +999,26 @@ 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 ) {
|
||||
auto trimmed = [&] (size_t start, size_t end) {
|
||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||
++start;
|
||||
@@ -1042,8 +1064,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;
|
||||
@@ -1052,19 +1074,20 @@ 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] );
|
||||
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] );
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||
m_captured++;
|
||||
}
|
||||
|
||||
@@ -1148,7 +1171,6 @@ namespace Catch {
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
cleanUpContext();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
@@ -1160,6 +1182,8 @@ namespace Catch {
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
@@ -1274,6 +1298,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() {
|
||||
@@ -1392,6 +1460,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());
|
||||
@@ -1432,6 +1501,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) {
|
||||
@@ -1461,9 +1534,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;
|
||||
}
|
||||
|
||||
@@ -1973,35 +2049,35 @@ namespace Detail {
|
||||
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;
|
||||
@@ -2026,6 +2102,13 @@ namespace Detail {
|
||||
rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
std::string makeExceptionHappenedString() {
|
||||
return "{ stringification failed with an exception: \"" +
|
||||
translateActiveException() + "\" }";
|
||||
|
||||
}
|
||||
|
||||
} // end Detail namespace
|
||||
|
||||
|
||||
@@ -2271,7 +2354,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 9, 0, "", 0 );
|
||||
static Version version( 3, 11, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -2359,8 +2442,14 @@ namespace Catch {
|
||||
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void missingCaptureInstance() {
|
||||
CATCH_INTERNAL_ERROR( "No result capture instance" );
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
IResultCapture::~IResultCapture() = default;
|
||||
}
|
||||
} // namespace Catch
|
||||
|
||||
|
||||
|
||||
@@ -3353,6 +3442,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" );
|
||||
|
||||
@@ -3507,7 +3599,11 @@ namespace {
|
||||
#endif // Windows/ ANSI/ None
|
||||
|
||||
|
||||
#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ )
|
||||
#if defined( CATCH_PLATFORM_LINUX ) \
|
||||
|| defined( CATCH_PLATFORM_MAC ) \
|
||||
|| defined( __GLIBC__ ) \
|
||||
|| defined( __FreeBSD__ ) \
|
||||
|| defined( CATCH_PLATFORM_QNX )
|
||||
# define CATCH_INTERNAL_HAS_ISATTY
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
@@ -3631,20 +3727,10 @@ namespace Catch {
|
||||
|
||||
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() {
|
||||
@@ -3749,7 +3835,7 @@ namespace Catch {
|
||||
#endif
|
||||
} // namespace Catch
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
@@ -3981,10 +4067,10 @@ namespace Catch {
|
||||
// To avoid having to handle TFE explicitly everywhere, we just
|
||||
// rethrow it so that it goes back up the caller.
|
||||
catch( TestFailureException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
return "{ nested assertion failed }";
|
||||
}
|
||||
catch( TestSkipException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
return "{ nested SKIP() called }";
|
||||
}
|
||||
catch( std::exception const& ex ) {
|
||||
return ex.what();
|
||||
@@ -4083,23 +4169,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() {
|
||||
@@ -4451,6 +4541,33 @@ namespace Detail {
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
static bool needsEscape( char c ) {
|
||||
return c == '"' || c == '\\' || c == '\b' || c == '\f' ||
|
||||
c == '\n' || c == '\r' || c == '\t';
|
||||
}
|
||||
|
||||
static Catch::StringRef makeEscapeStringRef( char c ) {
|
||||
if ( c == '"' ) {
|
||||
return "\\\""_sr;
|
||||
} else if ( c == '\\' ) {
|
||||
return "\\\\"_sr;
|
||||
} else if ( c == '\b' ) {
|
||||
return "\\b"_sr;
|
||||
} else if ( c == '\f' ) {
|
||||
return "\\f"_sr;
|
||||
} else if ( c == '\n' ) {
|
||||
return "\\n"_sr;
|
||||
} else if ( c == '\r' ) {
|
||||
return "\\r"_sr;
|
||||
} else if ( c == '\t' ) {
|
||||
return "\\t"_sr;
|
||||
}
|
||||
Catch::Detail::Unreachable();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
|
||||
for ( std::uint64_t i = 0; i < level; ++i ) {
|
||||
os << " ";
|
||||
@@ -4560,30 +4677,19 @@ namespace Catch {
|
||||
|
||||
void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
|
||||
if ( quote ) { m_os << '"'; }
|
||||
for (char c : value) {
|
||||
// Escape list taken from https://www.json.org/json-en.html,
|
||||
// string definition.
|
||||
// Note that while forward slash _can_ be escaped, it does
|
||||
// not have to be, if JSON is not further embedded somewhere
|
||||
// where forward slash is meaningful.
|
||||
if ( c == '"' ) {
|
||||
m_os << "\\\"";
|
||||
} else if ( c == '\\' ) {
|
||||
m_os << "\\\\";
|
||||
} else if ( c == '\b' ) {
|
||||
m_os << "\\b";
|
||||
} else if ( c == '\f' ) {
|
||||
m_os << "\\f";
|
||||
} else if ( c == '\n' ) {
|
||||
m_os << "\\n";
|
||||
} else if ( c == '\r' ) {
|
||||
m_os << "\\r";
|
||||
} else if ( c == '\t' ) {
|
||||
m_os << "\\t";
|
||||
} else {
|
||||
m_os << c;
|
||||
size_t current_start = 0;
|
||||
for ( size_t i = 0; i < value.size(); ++i ) {
|
||||
if ( needsEscape( value[i] ) ) {
|
||||
if ( current_start < i ) {
|
||||
m_os << value.substr( current_start, i - current_start );
|
||||
}
|
||||
m_os << makeEscapeStringRef( value[i] );
|
||||
current_start = i + 1;
|
||||
}
|
||||
}
|
||||
if ( current_start < value.size() ) {
|
||||
m_os << value.substr( current_start, value.size() - current_start );
|
||||
}
|
||||
if ( quote ) { m_os << '"'; }
|
||||
}
|
||||
|
||||
@@ -4780,17 +4886,18 @@ int main (int argc, char * argv[]) {
|
||||
|
||||
namespace Catch {
|
||||
|
||||
MessageInfo::MessageInfo( StringRef _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
ResultWas::OfType _type )
|
||||
MessageInfo::MessageInfo( StringRef _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
ResultWas::OfType _type )
|
||||
: macroName( _macroName ),
|
||||
lineInfo( _lineInfo ),
|
||||
type( _type ),
|
||||
sequence( ++globalCount )
|
||||
{}
|
||||
|
||||
// This may need protecting if threading support is added
|
||||
unsigned int MessageInfo::globalCount = 0;
|
||||
// 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
|
||||
|
||||
@@ -5540,6 +5647,7 @@ ReporterSpec::ReporterSpec(
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
@@ -5549,34 +5657,40 @@ namespace Catch {
|
||||
std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
|
||||
std::vector<std::size_t> m_unused;
|
||||
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() };
|
||||
}
|
||||
}
|
||||
|
||||
void release( std::size_t index ) {
|
||||
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
||||
m_unused.push_back(index);
|
||||
void release( std::size_t index, std::ostream* originalPtr ) {
|
||||
assert( originalPtr );
|
||||
originalPtr->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
||||
|
||||
Detail::LockGuard _( m_mutex );
|
||||
assert( originalPtr == m_streams[index].get() && "Mismatch between release index and stream ptr" );
|
||||
m_unused.push_back( index );
|
||||
}
|
||||
};
|
||||
|
||||
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("");
|
||||
m_oss->clear();
|
||||
Singleton<StringStreams>::getMutable().release( m_index );
|
||||
Singleton<StringStreams>::getMutable().release( m_index, m_oss );
|
||||
}
|
||||
|
||||
std::string ReusableStringStream::str() const {
|
||||
@@ -5743,9 +5857,6 @@ namespace Catch {
|
||||
// This also implies that messages are owned by their respective
|
||||
// threads, and should not be shared across different threads.
|
||||
//
|
||||
// For simplicity, we disallow messages in multi-threaded contexts,
|
||||
// but in the future we can enable them under this logic.
|
||||
//
|
||||
// This implies that various pieces of metadata referring to last
|
||||
// assertion result/source location/message handling, etc
|
||||
// should also be thread local. For now we just use naked globals
|
||||
@@ -5754,15 +5865,27 @@ namespace Catch {
|
||||
|
||||
// This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
|
||||
static thread_local bool g_lastAssertionPassed = false;
|
||||
// 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;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
@@ -5898,20 +6021,21 @@ namespace Catch {
|
||||
Detail::g_lastAssertionPassed = true;
|
||||
}
|
||||
|
||||
if ( Detail::g_clearMessageScopes ) {
|
||||
Detail::g_messageScopes.clear();
|
||||
Detail::g_clearMessageScopes = false;
|
||||
}
|
||||
|
||||
// From here, we are touching shared state and need mutex.
|
||||
Detail::LockGuard lock( m_assertionMutex );
|
||||
{
|
||||
if ( Detail::g_clearMessageScopes ) {
|
||||
m_messageScopes.clear();
|
||||
Detail::g_clearMessageScopes = false;
|
||||
}
|
||||
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||
updateTotalsFromAtomics();
|
||||
m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) );
|
||||
m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) );
|
||||
}
|
||||
|
||||
if ( result.getResultType() != ResultWas::Warning ) {
|
||||
m_messageScopes.clear();
|
||||
Detail::g_messageScopes.clear();
|
||||
}
|
||||
|
||||
// Reset working state. assertion info will be reset after
|
||||
@@ -6044,28 +6168,6 @@ namespace Catch {
|
||||
m_reporter->benchmarkFailed( error );
|
||||
}
|
||||
|
||||
void RunContext::pushScopedMessage(MessageInfo const & message) {
|
||||
m_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.
|
||||
m_messages.erase(
|
||||
std::find_if( m_messages.begin(),
|
||||
m_messages.end(),
|
||||
[id = message.sequence]( MessageInfo const& msg ) {
|
||||
return msg.sequence == id;
|
||||
} ) );
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
|
||||
m_messageScopes.emplace_back( CATCH_MOVE(builder) );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
@@ -6222,10 +6324,10 @@ namespace Catch {
|
||||
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messageScopes.clear();
|
||||
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?
|
||||
m_messages.clear();
|
||||
Detail::g_messages.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
@@ -6392,11 +6494,26 @@ 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_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) {
|
||||
@@ -7964,7 +8081,7 @@ namespace {
|
||||
|
||||
void hexEscapeChar(std::ostream& os, unsigned char c) {
|
||||
std::ios_base::fmtflags f(os.flags());
|
||||
os << "\\x"
|
||||
os << "\\x"_sr
|
||||
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
|
||||
<< static_cast<int>(c);
|
||||
os.flags(f);
|
||||
@@ -7983,95 +8100,111 @@ namespace {
|
||||
void XmlEncode::encodeTo( std::ostream& os ) const {
|
||||
// Apostrophe escaping not necessary if we always use " to write attributes
|
||||
// (see: http://www.w3.org/TR/xml/#syntax)
|
||||
size_t last_start = 0;
|
||||
auto write_to = [&]( size_t idx ) {
|
||||
if ( last_start < idx ) {
|
||||
os << m_str.substr( last_start, idx - last_start );
|
||||
}
|
||||
last_start = idx + 1;
|
||||
};
|
||||
|
||||
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
|
||||
unsigned char c = static_cast<unsigned char>(m_str[idx]);
|
||||
switch (c) {
|
||||
case '<': os << "<"; break;
|
||||
case '&': os << "&"; break;
|
||||
for ( std::size_t idx = 0; idx < m_str.size(); ++idx ) {
|
||||
unsigned char c = static_cast<unsigned char>( m_str[idx] );
|
||||
switch ( c ) {
|
||||
case '<':
|
||||
write_to( idx );
|
||||
os << "<"_sr;
|
||||
break;
|
||||
case '&':
|
||||
write_to( idx );
|
||||
os << "&"_sr;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
// See: http://www.w3.org/TR/xml/#syntax
|
||||
if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
|
||||
os << ">";
|
||||
else
|
||||
os << c;
|
||||
if ( idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']' ) {
|
||||
write_to( idx );
|
||||
os << ">"_sr;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
if (m_forWhat == ForAttributes)
|
||||
os << """;
|
||||
else
|
||||
os << c;
|
||||
if ( m_forWhat == ForAttributes ) {
|
||||
write_to( idx );
|
||||
os << """_sr;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Check for control characters and invalid utf-8
|
||||
|
||||
// Escape control characters in standard ascii
|
||||
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
|
||||
hexEscapeChar(os, c);
|
||||
// see
|
||||
// http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
if ( c < 0x09 || ( c > 0x0D && c < 0x20 ) || c == 0x7F ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
// Plain ASCII: Write it to stream
|
||||
if (c < 0x7F) {
|
||||
os << c;
|
||||
if ( c < 0x7F ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// UTF-8 territory
|
||||
// Check if the encoding is valid and if it is not, hex escape bytes.
|
||||
// Important: We do not check the exact decoded values for validity, only the encoding format
|
||||
// First check that this bytes is a valid lead byte:
|
||||
// This means that it is not encoded as 1111 1XXX
|
||||
// Check if the encoding is valid and if it is not, hex escape
|
||||
// bytes. Important: We do not check the exact decoded values for
|
||||
// validity, only the encoding format First check that this bytes is
|
||||
// a valid lead byte: This means that it is not encoded as 1111 1XXX
|
||||
// Or as 10XX XXXX
|
||||
if (c < 0xC0 ||
|
||||
c >= 0xF8) {
|
||||
hexEscapeChar(os, c);
|
||||
if ( c < 0xC0 || c >= 0xF8 ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
auto encBytes = trailingBytes(c);
|
||||
// Are there enough bytes left to avoid accessing out-of-bounds memory?
|
||||
if (idx + encBytes - 1 >= m_str.size()) {
|
||||
hexEscapeChar(os, c);
|
||||
auto encBytes = trailingBytes( c );
|
||||
// Are there enough bytes left to avoid accessing out-of-bounds
|
||||
// memory?
|
||||
if ( idx + encBytes - 1 >= m_str.size() ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
// The header is valid, check data
|
||||
// The next encBytes bytes must together be a valid utf-8
|
||||
// This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
|
||||
// This means: bitpattern 10XX XXXX and the extracted value is sane
|
||||
// (ish)
|
||||
bool valid = true;
|
||||
uint32_t value = headerValue(c);
|
||||
for (std::size_t n = 1; n < encBytes; ++n) {
|
||||
unsigned char nc = static_cast<unsigned char>(m_str[idx + n]);
|
||||
valid &= ((nc & 0xC0) == 0x80);
|
||||
value = (value << 6) | (nc & 0x3F);
|
||||
uint32_t value = headerValue( c );
|
||||
for ( std::size_t n = 1; n < encBytes; ++n ) {
|
||||
unsigned char nc = static_cast<unsigned char>( m_str[idx + n] );
|
||||
valid &= ( ( nc & 0xC0 ) == 0x80 );
|
||||
value = ( value << 6 ) | ( nc & 0x3F );
|
||||
}
|
||||
|
||||
if (
|
||||
// Wrong bit pattern of following bytes
|
||||
(!valid) ||
|
||||
( !valid ) ||
|
||||
// Overlong encodings
|
||||
(value < 0x80) ||
|
||||
(0x80 <= value && value < 0x800 && encBytes > 2) ||
|
||||
(0x800 < value && value < 0x10000 && encBytes > 3) ||
|
||||
( value < 0x80 ) ||
|
||||
( 0x80 <= value && value < 0x800 && encBytes > 2 ) ||
|
||||
( 0x800 < value && value < 0x10000 && encBytes > 3 ) ||
|
||||
// Encoded value out of range
|
||||
(value >= 0x110000)
|
||||
) {
|
||||
hexEscapeChar(os, c);
|
||||
( value >= 0x110000 ) ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
// If we got here, this is in fact a valid(ish) utf-8 sequence
|
||||
for (std::size_t n = 0; n < encBytes; ++n) {
|
||||
os << m_str[idx + n];
|
||||
}
|
||||
idx += encBytes - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
write_to( m_str.size() );
|
||||
}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
||||
|
@@ -6,8 +6,8 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
// Catch v3.9.0
|
||||
// Generated: 2025-07-24 22:00:24.654688
|
||||
// Catch v3.11.0
|
||||
// Generated: 2025-09-30 10:49:11.225746
|
||||
// ----------------------------------------------------------
|
||||
// This file is an amalgamation of multiple different files.
|
||||
// You probably shouldn't edit it directly.
|
||||
@@ -101,6 +101,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
|
||||
|
||||
@@ -308,13 +311,17 @@
|
||||
# endif
|
||||
|
||||
// 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
|
||||
@@ -564,11 +571,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 {
|
||||
@@ -579,21 +584,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();
|
||||
}
|
||||
@@ -958,7 +956,7 @@ namespace Detail {
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return m_ptr;
|
||||
return m_ptr != nullptr;
|
||||
}
|
||||
|
||||
friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
|
||||
@@ -1069,10 +1067,9 @@ 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 emplaceUnscopedMessage( MessageBuilder&& builder );
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
@@ -1108,7 +1105,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
|
||||
@@ -2151,9 +2159,7 @@ namespace Catch {
|
||||
auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
|
||||
BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
} CATCH_CATCH_ANON (TestFailureException const&) {
|
||||
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
|
||||
} CATCH_CATCH_ALL{
|
||||
} CATCH_CATCH_ALL {
|
||||
getResultCapture().benchmarkFailed(translateActiveException());
|
||||
// We let the exception go further up so that the
|
||||
// test case is marked as failed.
|
||||
@@ -2566,11 +2572,17 @@ namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
std::string makeExceptionHappenedString();
|
||||
|
||||
// This function dispatches all stringification requests inside of Catch.
|
||||
// Should be preferably called fully qualified, like ::Catch::Detail::stringify
|
||||
template <typename T>
|
||||
std::string stringify(const T& e) {
|
||||
return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
|
||||
std::string stringify( const T& e ) {
|
||||
CATCH_TRY {
|
||||
return ::Catch::StringMaker<
|
||||
std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
|
||||
}
|
||||
CATCH_CATCH_ALL { return makeExceptionHappenedString(); }
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
@@ -3053,17 +3065,19 @@ struct ratio_string<std::milli> {
|
||||
template<typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
|
||||
auto converted = std::chrono::system_clock::to_time_t(time_point);
|
||||
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, &converted);
|
||||
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(&converted);
|
||||
std::tm* timeInfo = std::gmtime( &as_time_t );
|
||||
#endif
|
||||
|
||||
auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
|
||||
@@ -3794,6 +3808,8 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
|
||||
std::string prematureExitGuardFilePath;
|
||||
};
|
||||
|
||||
|
||||
@@ -3821,6 +3837,8 @@ namespace Catch {
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
std::string const& getExitGuardFilePath() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
StringRef name() const override;
|
||||
@@ -3955,6 +3973,7 @@ 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" )
|
||||
@@ -3966,7 +3985,7 @@ namespace Catch {
|
||||
return sequence < other.sequence;
|
||||
}
|
||||
private:
|
||||
static unsigned int globalCount;
|
||||
static thread_local unsigned int globalCount;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
@@ -4014,13 +4033,12 @@ 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;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
@@ -4068,7 +4086,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)
|
||||
@@ -5238,10 +5256,11 @@ namespace Detail {
|
||||
*
|
||||
* 3) If a type has no linkage, we also cannot capture it by reference.
|
||||
* The solution is once again to capture them by value. We handle
|
||||
* the common cases by using `std::is_arithmetic` as the default
|
||||
* for `Catch::capture_by_value`, but that is only a some-effort
|
||||
* heuristic. But as with 2), users can specialize `capture_by_value`
|
||||
* for their own types as needed.
|
||||
* the common cases by using `std::is_arithmetic` and `std::is_enum`
|
||||
* as the default for `Catch::capture_by_value`, but that is only a
|
||||
* some-effort heuristic. These combine to capture all possible bitfield
|
||||
* bases, and also some trait-like types. As with 2), users can
|
||||
* specialize `capture_by_value` for their own types as needed.
|
||||
*
|
||||
* 4) To support C++20 and make the SFINAE on our decomposing operators
|
||||
* work, the SFINAE has to happen in return type, rather than in
|
||||
@@ -5293,13 +5312,22 @@ namespace Catch {
|
||||
using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
}
|
||||
|
||||
// Note: There is nothing that stops us from extending this,
|
||||
// e.g. to `std::is_scalar`, but the more encompassing
|
||||
// traits are usually also more expensive. For now we
|
||||
// keep this as it used to be and it can be changed later.
|
||||
// Note: This is about as much as we can currently reasonably support.
|
||||
// In an ideal world, we could capture by value small trivially
|
||||
// copyable types, but the actual `std::is_trivially_copyable`
|
||||
// trait is a huge mess with standard-violating results on
|
||||
// GCC and Clang, which are unlikely to be fixed soon due to ABI
|
||||
// concerns.
|
||||
// `std::is_scalar` also causes issues due to the `is_pointer`
|
||||
// component, which causes ambiguity issues with (references-to)
|
||||
// function pointer. If those are resolved, we still need to
|
||||
// disambiguate the overload set for arrays, through explicit
|
||||
// overload for references to sized arrays.
|
||||
template <typename T>
|
||||
struct capture_by_value
|
||||
: std::integral_constant<bool, std::is_arithmetic<T>{}> {};
|
||||
: std::integral_constant<bool,
|
||||
std::is_arithmetic<T>::value ||
|
||||
std::is_enum<T>::value> {};
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
|
||||
template <>
|
||||
@@ -6241,9 +6269,13 @@ namespace Catch {
|
||||
__assume( false );
|
||||
# elif defined( __GNUC__ )
|
||||
__builtin_unreachable();
|
||||
# endif
|
||||
# endif // ^^ NDEBUG
|
||||
# else // vv platform without known optimization hint
|
||||
std::terminate();
|
||||
# endif
|
||||
# else // ^^ NDEBUG
|
||||
// For non-release builds, we prefer termination on bug over UB
|
||||
std::terminate();
|
||||
# endif //
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
@@ -7446,7 +7478,7 @@ namespace Catch {
|
||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 9
|
||||
#define CATCH_VERSION_MINOR 11
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
@@ -7862,8 +7894,9 @@ namespace Generators {
|
||||
class FilterGenerator final : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
static_assert(!std::is_reference<Predicate>::value, "This would most likely result in a dangling reference");
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
template <typename P>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_predicate(CATCH_FORWARD(pred))
|
||||
@@ -7895,7 +7928,7 @@ namespace Generators {
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, typename std::remove_reference<Predicate>::type>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -9500,6 +9533,17 @@ namespace Catch {
|
||||
bool isDebuggerActive();
|
||||
}
|
||||
|
||||
#if !defined( CATCH_TRAP ) && defined( __clang__ ) && defined( __has_builtin )
|
||||
# if __has_builtin( __builtin_debugtrap )
|
||||
# define CATCH_TRAP() __builtin_debugtrap()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined( CATCH_TRAP ) && defined( _MSC_VER )
|
||||
# define CATCH_TRAP() __debugbreak()
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_TRAP) // If we couldn't use compiler-specific impl from above, we get into platform-specific options
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
@@ -9524,7 +9568,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.
|
||||
@@ -9535,15 +9579,15 @@ namespace Catch {
|
||||
|
||||
#define CATCH_TRAP() raise(SIGTRAP)
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#define CATCH_TRAP() __debugbreak()
|
||||
#elif defined(__MINGW32__)
|
||||
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
|
||||
#define CATCH_TRAP() DebugBreak()
|
||||
#endif
|
||||
#endif // ^^ CATCH_TRAP is not defined yet, so we define it
|
||||
|
||||
#ifndef CATCH_BREAK_INTO_DEBUGGER
|
||||
#ifdef CATCH_TRAP
|
||||
|
||||
#if !defined(CATCH_BREAK_INTO_DEBUGGER)
|
||||
#if defined(CATCH_TRAP)
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{}()
|
||||
@@ -10687,11 +10731,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;
|
||||
@@ -10742,9 +10781,6 @@ namespace Catch {
|
||||
Totals m_totals;
|
||||
Detail::AtomicCounts m_atomicAssertionCount;
|
||||
IEventListenerPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
// Owners for the UNSCOPED_X information macro
|
||||
std::vector<ScopedMessage> m_messageScopes;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
TrackerContext m_trackerContext;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
project(
|
||||
'catch2',
|
||||
'cpp',
|
||||
version: '3.9.0', # CML version placeholder, don't delete
|
||||
version: '3.11.0', # CML version placeholder, don't delete
|
||||
license: 'BSL-1.0',
|
||||
meson_version: '>=0.54.1',
|
||||
)
|
||||
|
@@ -98,6 +98,7 @@ set(IMPL_HEADERS
|
||||
${SOURCES_DIR}/internal/catch_jsonwriter.hpp
|
||||
${SOURCES_DIR}/internal/catch_lazy_expr.hpp
|
||||
${SOURCES_DIR}/internal/catch_leak_detector.hpp
|
||||
${SOURCES_DIR}/internal/catch_lifetimebound.hpp
|
||||
${SOURCES_DIR}/internal/catch_list.hpp
|
||||
${SOURCES_DIR}/internal/catch_logical_traits.hpp
|
||||
${SOURCES_DIR}/internal/catch_message_info.hpp
|
||||
|
@@ -86,9 +86,7 @@ namespace Catch {
|
||||
auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
|
||||
BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
} CATCH_CATCH_ANON (TestFailureException const&) {
|
||||
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
|
||||
} CATCH_CATCH_ALL{
|
||||
} CATCH_CATCH_ALL {
|
||||
getResultCapture().benchmarkFailed(translateActiveException());
|
||||
// We let the exception go further up so that the
|
||||
// test case is marked as failed.
|
||||
|
@@ -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>
|
||||
|
@@ -119,6 +119,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();
|
||||
}
|
||||
@@ -183,6 +185,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; }
|
||||
@@ -244,6 +248,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
|
||||
|
@@ -87,6 +87,8 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
|
||||
std::string prematureExitGuardFilePath;
|
||||
};
|
||||
|
||||
|
||||
@@ -114,6 +116,8 @@ namespace Catch {
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
std::string const& getExitGuardFilePath() const;
|
||||
|
||||
// IConfig interface
|
||||
bool allowThrows() const override;
|
||||
StringRef name() const override;
|
||||
|
@@ -19,28 +19,26 @@ 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 ) {
|
||||
auto trimmed = [&] (size_t start, size_t end) {
|
||||
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||
++start;
|
||||
@@ -86,8 +84,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,19 +94,20 @@ 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] );
|
||||
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] );
|
||||
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
|
||||
m_captured++;
|
||||
}
|
||||
|
||||
|
@@ -57,13 +57,12 @@ 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;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
@@ -111,7 +110,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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_polyfills.hpp>
|
||||
|
||||
@@ -56,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;
|
||||
@@ -113,6 +144,13 @@ namespace Detail {
|
||||
rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
std::string makeExceptionHappenedString() {
|
||||
return "{ stringification failed with an exception: \"" +
|
||||
translateActiveException() + "\" }";
|
||||
|
||||
}
|
||||
|
||||
} // end Detail namespace
|
||||
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
@@ -139,11 +135,17 @@ namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
|
||||
std::string makeExceptionHappenedString();
|
||||
|
||||
// This function dispatches all stringification requests inside of Catch.
|
||||
// Should be preferably called fully qualified, like ::Catch::Detail::stringify
|
||||
template <typename T>
|
||||
std::string stringify(const T& e) {
|
||||
return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
|
||||
std::string stringify( const T& e ) {
|
||||
CATCH_TRY {
|
||||
return ::Catch::StringMaker<
|
||||
std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
|
||||
}
|
||||
CATCH_CATCH_ALL { return makeExceptionHappenedString(); }
|
||||
}
|
||||
|
||||
template<typename E>
|
||||
@@ -405,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)
|
||||
@@ -626,29 +622,10 @@ struct ratio_string<std::milli> {
|
||||
template<typename Duration>
|
||||
struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
|
||||
auto converted = std::chrono::system_clock::to_time_t(time_point);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::tm timeInfo = {};
|
||||
const auto err = gmtime_s(&timeInfo, &converted);
|
||||
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(&converted);
|
||||
#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);
|
||||
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 );
|
||||
return ::Catch::Detail::formatTimeT( as_time_t );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 9, 0, "", 0 );
|
||||
static Version version( 3, 11, 0, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 9
|
||||
#define CATCH_VERSION_MINOR 11
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
@@ -58,8 +58,9 @@ namespace Generators {
|
||||
class FilterGenerator final : public IGenerator<T> {
|
||||
GeneratorWrapper<T> m_generator;
|
||||
Predicate m_predicate;
|
||||
static_assert(!std::is_reference<Predicate>::value, "This would most likely result in a dangling reference");
|
||||
public:
|
||||
template <typename P = Predicate>
|
||||
template <typename P>
|
||||
FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
|
||||
m_generator(CATCH_MOVE(generator)),
|
||||
m_predicate(CATCH_FORWARD(pred))
|
||||
@@ -91,7 +92,7 @@ namespace Generators {
|
||||
|
||||
template <typename T, typename Predicate>
|
||||
GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||
return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, typename std::remove_reference<Predicate>::type>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@@ -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
|
||||
|
@@ -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,9 @@ 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 emplaceUnscopedMessage( MessageBuilder&& builder );
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
@@ -101,7 +101,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
|
||||
|
@@ -305,6 +305,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" );
|
||||
|
||||
|
@@ -220,13 +220,17 @@
|
||||
# endif
|
||||
|
||||
// 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
|
||||
|
@@ -161,7 +161,11 @@ namespace {
|
||||
#endif // Windows/ ANSI/ None
|
||||
|
||||
|
||||
#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ )
|
||||
#if defined( CATCH_PLATFORM_LINUX ) \
|
||||
|| defined( CATCH_PLATFORM_MAC ) \
|
||||
|| defined( __GLIBC__ ) \
|
||||
|| defined( __FreeBSD__ ) \
|
||||
|| 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() {
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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>
|
||||
|
||||
|
@@ -14,6 +14,17 @@ namespace Catch {
|
||||
bool isDebuggerActive();
|
||||
}
|
||||
|
||||
#if !defined( CATCH_TRAP ) && defined( __clang__ ) && defined( __has_builtin )
|
||||
# if __has_builtin( __builtin_debugtrap )
|
||||
# define CATCH_TRAP() __builtin_debugtrap()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined( CATCH_TRAP ) && defined( _MSC_VER )
|
||||
# define CATCH_TRAP() __debugbreak()
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_TRAP) // If we couldn't use compiler-specific impl from above, we get into platform-specific options
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
@@ -38,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.
|
||||
@@ -49,15 +60,15 @@ namespace Catch {
|
||||
|
||||
#define CATCH_TRAP() raise(SIGTRAP)
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#define CATCH_TRAP() __debugbreak()
|
||||
#elif defined(__MINGW32__)
|
||||
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
|
||||
#define CATCH_TRAP() DebugBreak()
|
||||
#endif
|
||||
#endif // ^^ CATCH_TRAP is not defined yet, so we define it
|
||||
|
||||
#ifndef CATCH_BREAK_INTO_DEBUGGER
|
||||
#ifdef CATCH_TRAP
|
||||
|
||||
#if !defined(CATCH_BREAK_INTO_DEBUGGER)
|
||||
#if defined(CATCH_TRAP)
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() []{}()
|
||||
|
@@ -78,10 +78,11 @@
|
||||
*
|
||||
* 3) If a type has no linkage, we also cannot capture it by reference.
|
||||
* The solution is once again to capture them by value. We handle
|
||||
* the common cases by using `std::is_arithmetic` as the default
|
||||
* for `Catch::capture_by_value`, but that is only a some-effort
|
||||
* heuristic. But as with 2), users can specialize `capture_by_value`
|
||||
* for their own types as needed.
|
||||
* the common cases by using `std::is_arithmetic` and `std::is_enum`
|
||||
* as the default for `Catch::capture_by_value`, but that is only a
|
||||
* some-effort heuristic. These combine to capture all possible bitfield
|
||||
* bases, and also some trait-like types. As with 2), users can
|
||||
* specialize `capture_by_value` for their own types as needed.
|
||||
*
|
||||
* 4) To support C++20 and make the SFINAE on our decomposing operators
|
||||
* work, the SFINAE has to happen in return type, rather than in
|
||||
@@ -133,13 +134,22 @@ namespace Catch {
|
||||
using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
}
|
||||
|
||||
// Note: There is nothing that stops us from extending this,
|
||||
// e.g. to `std::is_scalar`, but the more encompassing
|
||||
// traits are usually also more expensive. For now we
|
||||
// keep this as it used to be and it can be changed later.
|
||||
// Note: This is about as much as we can currently reasonably support.
|
||||
// In an ideal world, we could capture by value small trivially
|
||||
// copyable types, but the actual `std::is_trivially_copyable`
|
||||
// trait is a huge mess with standard-violating results on
|
||||
// GCC and Clang, which are unlikely to be fixed soon due to ABI
|
||||
// concerns.
|
||||
// `std::is_scalar` also causes issues due to the `is_pointer`
|
||||
// component, which causes ambiguity issues with (references-to)
|
||||
// function pointer. If those are resolved, we still need to
|
||||
// disambiguate the overload set for arrays, through explicit
|
||||
// overload for references to sized arrays.
|
||||
template <typename T>
|
||||
struct capture_by_value
|
||||
: std::integral_constant<bool, std::is_arithmetic<T>{}> {};
|
||||
: std::integral_constant<bool,
|
||||
std::is_arithmetic<T>::value ||
|
||||
std::is_enum<T>::value> {};
|
||||
|
||||
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
|
||||
template <>
|
||||
|
@@ -59,10 +59,10 @@ namespace Catch {
|
||||
// To avoid having to handle TFE explicitly everywhere, we just
|
||||
// rethrow it so that it goes back up the caller.
|
||||
catch( TestFailureException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
return "{ nested assertion failed }";
|
||||
}
|
||||
catch( TestSkipException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
return "{ nested SKIP() called }";
|
||||
}
|
||||
catch( std::exception const& ex ) {
|
||||
return ex.what();
|
||||
|
@@ -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,8 +7,36 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/internal/catch_unreachable.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
static bool needsEscape( char c ) {
|
||||
return c == '"' || c == '\\' || c == '\b' || c == '\f' ||
|
||||
c == '\n' || c == '\r' || c == '\t';
|
||||
}
|
||||
|
||||
static Catch::StringRef makeEscapeStringRef( char c ) {
|
||||
if ( c == '"' ) {
|
||||
return "\\\""_sr;
|
||||
} else if ( c == '\\' ) {
|
||||
return "\\\\"_sr;
|
||||
} else if ( c == '\b' ) {
|
||||
return "\\b"_sr;
|
||||
} else if ( c == '\f' ) {
|
||||
return "\\f"_sr;
|
||||
} else if ( c == '\n' ) {
|
||||
return "\\n"_sr;
|
||||
} else if ( c == '\r' ) {
|
||||
return "\\r"_sr;
|
||||
} else if ( c == '\t' ) {
|
||||
return "\\t"_sr;
|
||||
}
|
||||
Catch::Detail::Unreachable();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
|
||||
for ( std::uint64_t i = 0; i < level; ++i ) {
|
||||
os << " ";
|
||||
@@ -118,30 +146,19 @@ namespace Catch {
|
||||
|
||||
void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
|
||||
if ( quote ) { m_os << '"'; }
|
||||
for (char c : value) {
|
||||
// Escape list taken from https://www.json.org/json-en.html,
|
||||
// string definition.
|
||||
// Note that while forward slash _can_ be escaped, it does
|
||||
// not have to be, if JSON is not further embedded somewhere
|
||||
// where forward slash is meaningful.
|
||||
if ( c == '"' ) {
|
||||
m_os << "\\\"";
|
||||
} else if ( c == '\\' ) {
|
||||
m_os << "\\\\";
|
||||
} else if ( c == '\b' ) {
|
||||
m_os << "\\b";
|
||||
} else if ( c == '\f' ) {
|
||||
m_os << "\\f";
|
||||
} else if ( c == '\n' ) {
|
||||
m_os << "\\n";
|
||||
} else if ( c == '\r' ) {
|
||||
m_os << "\\r";
|
||||
} else if ( c == '\t' ) {
|
||||
m_os << "\\t";
|
||||
} else {
|
||||
m_os << c;
|
||||
size_t current_start = 0;
|
||||
for ( size_t i = 0; i < value.size(); ++i ) {
|
||||
if ( needsEscape( value[i] ) ) {
|
||||
if ( current_start < i ) {
|
||||
m_os << value.substr( current_start, i - current_start );
|
||||
}
|
||||
m_os << makeEscapeStringRef( value[i] );
|
||||
current_start = i + 1;
|
||||
}
|
||||
}
|
||||
if ( current_start < value.size() ) {
|
||||
m_os << value.substr( current_start, value.size() - current_start );
|
||||
}
|
||||
if ( quote ) { m_os << '"'; }
|
||||
}
|
||||
|
||||
|
24
src/catch2/internal/catch_lifetimebound.hpp
Normal file
24
src/catch2/internal/catch_lifetimebound.hpp
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
|
@@ -10,16 +10,17 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
MessageInfo::MessageInfo( StringRef _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
ResultWas::OfType _type )
|
||||
MessageInfo::MessageInfo( StringRef _macroName,
|
||||
SourceLineInfo const& _lineInfo,
|
||||
ResultWas::OfType _type )
|
||||
: macroName( _macroName ),
|
||||
lineInfo( _lineInfo ),
|
||||
type( _type ),
|
||||
sequence( ++globalCount )
|
||||
{}
|
||||
|
||||
// This may need protecting if threading support is added
|
||||
unsigned int MessageInfo::globalCount = 0;
|
||||
// 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
|
||||
|
@@ -26,6 +26,7 @@ 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" )
|
||||
@@ -37,7 +38,7 @@ namespace Catch {
|
||||
return sequence < other.sequence;
|
||||
}
|
||||
private:
|
||||
static unsigned int globalCount;
|
||||
static thread_local unsigned int globalCount;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -7,10 +7,12 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_singletons.hpp>
|
||||
#include <catch2/internal/catch_thread_support.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
@@ -20,34 +22,40 @@ namespace Catch {
|
||||
std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
|
||||
std::vector<std::size_t> m_unused;
|
||||
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() };
|
||||
}
|
||||
}
|
||||
|
||||
void release( std::size_t index ) {
|
||||
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
||||
m_unused.push_back(index);
|
||||
void release( std::size_t index, std::ostream* originalPtr ) {
|
||||
assert( originalPtr );
|
||||
originalPtr->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
||||
|
||||
Detail::LockGuard _( m_mutex );
|
||||
assert( originalPtr == m_streams[index].get() && "Mismatch between release index and stream ptr" );
|
||||
m_unused.push_back( index );
|
||||
}
|
||||
};
|
||||
|
||||
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("");
|
||||
m_oss->clear();
|
||||
Singleton<StringStreams>::getMutable().release( m_index );
|
||||
Singleton<StringStreams>::getMutable().release( m_index, m_oss );
|
||||
}
|
||||
|
||||
std::string ReusableStringStream::str() const {
|
||||
|
@@ -172,9 +172,6 @@ namespace Catch {
|
||||
// This also implies that messages are owned by their respective
|
||||
// threads, and should not be shared across different threads.
|
||||
//
|
||||
// For simplicity, we disallow messages in multi-threaded contexts,
|
||||
// but in the future we can enable them under this logic.
|
||||
//
|
||||
// This implies that various pieces of metadata referring to last
|
||||
// assertion result/source location/message handling, etc
|
||||
// should also be thread local. For now we just use naked globals
|
||||
@@ -183,15 +180,27 @@ namespace Catch {
|
||||
|
||||
// This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
|
||||
static thread_local bool g_lastAssertionPassed = false;
|
||||
// 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;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
@@ -327,20 +336,21 @@ namespace Catch {
|
||||
Detail::g_lastAssertionPassed = true;
|
||||
}
|
||||
|
||||
if ( Detail::g_clearMessageScopes ) {
|
||||
Detail::g_messageScopes.clear();
|
||||
Detail::g_clearMessageScopes = false;
|
||||
}
|
||||
|
||||
// From here, we are touching shared state and need mutex.
|
||||
Detail::LockGuard lock( m_assertionMutex );
|
||||
{
|
||||
if ( Detail::g_clearMessageScopes ) {
|
||||
m_messageScopes.clear();
|
||||
Detail::g_clearMessageScopes = false;
|
||||
}
|
||||
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||
updateTotalsFromAtomics();
|
||||
m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) );
|
||||
m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) );
|
||||
}
|
||||
|
||||
if ( result.getResultType() != ResultWas::Warning ) {
|
||||
m_messageScopes.clear();
|
||||
Detail::g_messageScopes.clear();
|
||||
}
|
||||
|
||||
// Reset working state. assertion info will be reset after
|
||||
@@ -473,28 +483,6 @@ namespace Catch {
|
||||
m_reporter->benchmarkFailed( error );
|
||||
}
|
||||
|
||||
void RunContext::pushScopedMessage(MessageInfo const & message) {
|
||||
m_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.
|
||||
m_messages.erase(
|
||||
std::find_if( m_messages.begin(),
|
||||
m_messages.end(),
|
||||
[id = message.sequence]( MessageInfo const& msg ) {
|
||||
return msg.sequence == id;
|
||||
} ) );
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
|
||||
m_messageScopes.emplace_back( CATCH_MOVE(builder) );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
@@ -651,10 +639,10 @@ namespace Catch {
|
||||
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messageScopes.clear();
|
||||
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?
|
||||
m_messages.clear();
|
||||
Detail::g_messages.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
@@ -821,11 +809,26 @@ 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_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) {
|
||||
|
@@ -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;
|
||||
@@ -149,9 +144,6 @@ namespace Catch {
|
||||
Totals m_totals;
|
||||
Detail::AtomicCounts m_atomicAssertionCount;
|
||||
IEventListenerPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
// Owners for the UNSCOPED_X information macro
|
||||
std::vector<ScopedMessage> m_messageScopes;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
TrackerContext m_trackerContext;
|
||||
|
@@ -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>
|
||||
@@ -48,7 +49,7 @@ namespace TestCaseTracking {
|
||||
StringRef name;
|
||||
SourceLineInfo location;
|
||||
|
||||
constexpr NameAndLocationRef( StringRef name_,
|
||||
constexpr NameAndLocationRef( StringRef name_ CATCH_ATTR_LIFETIMEBOUND,
|
||||
SourceLineInfo location_ ):
|
||||
name( name_ ), location( location_ ) {}
|
||||
|
||||
|
@@ -92,7 +92,7 @@ namespace Detail {
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return m_ptr;
|
||||
return m_ptr != nullptr;
|
||||
}
|
||||
|
||||
friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
|
||||
|
@@ -39,9 +39,13 @@ namespace Catch {
|
||||
__assume( false );
|
||||
# elif defined( __GNUC__ )
|
||||
__builtin_unreachable();
|
||||
# endif
|
||||
# endif // ^^ NDEBUG
|
||||
# else // vv platform without known optimization hint
|
||||
std::terminate();
|
||||
# endif
|
||||
# else // ^^ NDEBUG
|
||||
// For non-release builds, we prefer termination on bug over UB
|
||||
std::terminate();
|
||||
# endif //
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
|
@@ -47,7 +47,7 @@ namespace {
|
||||
|
||||
void hexEscapeChar(std::ostream& os, unsigned char c) {
|
||||
std::ios_base::fmtflags f(os.flags());
|
||||
os << "\\x"
|
||||
os << "\\x"_sr
|
||||
<< std::uppercase << std::hex << std::setfill('0') << std::setw(2)
|
||||
<< static_cast<int>(c);
|
||||
os.flags(f);
|
||||
@@ -66,95 +66,111 @@ namespace {
|
||||
void XmlEncode::encodeTo( std::ostream& os ) const {
|
||||
// Apostrophe escaping not necessary if we always use " to write attributes
|
||||
// (see: http://www.w3.org/TR/xml/#syntax)
|
||||
size_t last_start = 0;
|
||||
auto write_to = [&]( size_t idx ) {
|
||||
if ( last_start < idx ) {
|
||||
os << m_str.substr( last_start, idx - last_start );
|
||||
}
|
||||
last_start = idx + 1;
|
||||
};
|
||||
|
||||
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
|
||||
unsigned char c = static_cast<unsigned char>(m_str[idx]);
|
||||
switch (c) {
|
||||
case '<': os << "<"; break;
|
||||
case '&': os << "&"; break;
|
||||
for ( std::size_t idx = 0; idx < m_str.size(); ++idx ) {
|
||||
unsigned char c = static_cast<unsigned char>( m_str[idx] );
|
||||
switch ( c ) {
|
||||
case '<':
|
||||
write_to( idx );
|
||||
os << "<"_sr;
|
||||
break;
|
||||
case '&':
|
||||
write_to( idx );
|
||||
os << "&"_sr;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
// See: http://www.w3.org/TR/xml/#syntax
|
||||
if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
|
||||
os << ">";
|
||||
else
|
||||
os << c;
|
||||
if ( idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']' ) {
|
||||
write_to( idx );
|
||||
os << ">"_sr;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
if (m_forWhat == ForAttributes)
|
||||
os << """;
|
||||
else
|
||||
os << c;
|
||||
if ( m_forWhat == ForAttributes ) {
|
||||
write_to( idx );
|
||||
os << """_sr;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Check for control characters and invalid utf-8
|
||||
|
||||
// Escape control characters in standard ascii
|
||||
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
|
||||
hexEscapeChar(os, c);
|
||||
// see
|
||||
// http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
if ( c < 0x09 || ( c > 0x0D && c < 0x20 ) || c == 0x7F ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
// Plain ASCII: Write it to stream
|
||||
if (c < 0x7F) {
|
||||
os << c;
|
||||
if ( c < 0x7F ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// UTF-8 territory
|
||||
// Check if the encoding is valid and if it is not, hex escape bytes.
|
||||
// Important: We do not check the exact decoded values for validity, only the encoding format
|
||||
// First check that this bytes is a valid lead byte:
|
||||
// This means that it is not encoded as 1111 1XXX
|
||||
// Check if the encoding is valid and if it is not, hex escape
|
||||
// bytes. Important: We do not check the exact decoded values for
|
||||
// validity, only the encoding format First check that this bytes is
|
||||
// a valid lead byte: This means that it is not encoded as 1111 1XXX
|
||||
// Or as 10XX XXXX
|
||||
if (c < 0xC0 ||
|
||||
c >= 0xF8) {
|
||||
hexEscapeChar(os, c);
|
||||
if ( c < 0xC0 || c >= 0xF8 ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
auto encBytes = trailingBytes(c);
|
||||
// Are there enough bytes left to avoid accessing out-of-bounds memory?
|
||||
if (idx + encBytes - 1 >= m_str.size()) {
|
||||
hexEscapeChar(os, c);
|
||||
auto encBytes = trailingBytes( c );
|
||||
// Are there enough bytes left to avoid accessing out-of-bounds
|
||||
// memory?
|
||||
if ( idx + encBytes - 1 >= m_str.size() ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
// The header is valid, check data
|
||||
// The next encBytes bytes must together be a valid utf-8
|
||||
// This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
|
||||
// This means: bitpattern 10XX XXXX and the extracted value is sane
|
||||
// (ish)
|
||||
bool valid = true;
|
||||
uint32_t value = headerValue(c);
|
||||
for (std::size_t n = 1; n < encBytes; ++n) {
|
||||
unsigned char nc = static_cast<unsigned char>(m_str[idx + n]);
|
||||
valid &= ((nc & 0xC0) == 0x80);
|
||||
value = (value << 6) | (nc & 0x3F);
|
||||
uint32_t value = headerValue( c );
|
||||
for ( std::size_t n = 1; n < encBytes; ++n ) {
|
||||
unsigned char nc = static_cast<unsigned char>( m_str[idx + n] );
|
||||
valid &= ( ( nc & 0xC0 ) == 0x80 );
|
||||
value = ( value << 6 ) | ( nc & 0x3F );
|
||||
}
|
||||
|
||||
if (
|
||||
// Wrong bit pattern of following bytes
|
||||
(!valid) ||
|
||||
( !valid ) ||
|
||||
// Overlong encodings
|
||||
(value < 0x80) ||
|
||||
(0x80 <= value && value < 0x800 && encBytes > 2) ||
|
||||
(0x800 < value && value < 0x10000 && encBytes > 3) ||
|
||||
( value < 0x80 ) ||
|
||||
( 0x80 <= value && value < 0x800 && encBytes > 2 ) ||
|
||||
( 0x800 < value && value < 0x10000 && encBytes > 3 ) ||
|
||||
// Encoded value out of range
|
||||
(value >= 0x110000)
|
||||
) {
|
||||
hexEscapeChar(os, c);
|
||||
( value >= 0x110000 ) ) {
|
||||
write_to( idx );
|
||||
hexEscapeChar( os, c );
|
||||
break;
|
||||
}
|
||||
|
||||
// If we got here, this is in fact a valid(ish) utf-8 sequence
|
||||
for (std::size_t n = 0; n < encBytes; ++n) {
|
||||
os << m_str[idx + n];
|
||||
}
|
||||
idx += encBytes - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
write_to( m_str.size() );
|
||||
}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
||||
|
@@ -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 };
|
||||
}
|
||||
|
||||
|
@@ -105,6 +105,7 @@ internal_headers = [
|
||||
'internal/catch_jsonwriter.hpp',
|
||||
'internal/catch_lazy_expr.hpp',
|
||||
'internal/catch_leak_detector.hpp',
|
||||
'internal/catch_lifetimebound.hpp',
|
||||
'internal/catch_list.hpp',
|
||||
'internal/catch_logical_traits.hpp',
|
||||
'internal/catch_message_info.hpp',
|
||||
|
@@ -662,5 +662,38 @@ foreach(reporterName # "Automake" - the simple .trs format does not support any
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_test(NAME "Bazel::RngSeedEnvVar::JustEnv"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
)
|
||||
set_tests_properties("Bazel::RngSeedEnvVar::JustEnv"
|
||||
PROPERTIES
|
||||
ENVIRONMENT "BAZEL_TEST=1;TEST_RANDOM_SEED=18181818"
|
||||
PASS_REGULAR_EXPRESSION "Randomness seeded to: 18181818"
|
||||
)
|
||||
|
||||
add_test(NAME "Bazel::RngSeedEnvVar::EnvHasPriorityOverCLI"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--rng-seed 17171717
|
||||
)
|
||||
set_tests_properties("Bazel::RngSeedEnvVar::EnvHasPriorityOverCLI"
|
||||
PROPERTIES
|
||||
ENVIRONMENT "BAZEL_TEST=1;TEST_RANDOM_SEED=18181818"
|
||||
PASS_REGULAR_EXPRESSION "Randomness seeded to: 18181818"
|
||||
)
|
||||
|
||||
add_test(NAME "Bazel::RngSeedEnvVar::MalformedValueIsIgnored"
|
||||
COMMAND
|
||||
$<TARGET_FILE:SelfTest> "Factorials are computed"
|
||||
--rng-seed 17171717
|
||||
)
|
||||
set_tests_properties("Bazel::RngSeedEnvVar::MalformedValueIsIgnored"
|
||||
PROPERTIES
|
||||
ENVIRONMENT "BAZEL_TEST=1;TEST_RANDOM_SEED=XOXOXOXO"
|
||||
PASS_REGULAR_EXPRESSION "Randomness seeded to: 17171717"
|
||||
)
|
||||
|
||||
|
||||
list(APPEND CATCH_TEST_TARGETS SelfTest)
|
||||
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
|
||||
|
@@ -95,7 +95,7 @@ foreach(target DisabledExceptions-DefaultHandler DisabledExceptions-CustomHandle
|
||||
target_compile_options(${target}
|
||||
PUBLIC
|
||||
$<$<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)
|
||||
endforeach()
|
||||
@@ -109,18 +109,6 @@ set_tests_properties(CATCH_CONFIG_DISABLE_EXCEPTIONS-1
|
||||
FAIL_REGULAR_EXPRESSION "abort;terminate;fatal"
|
||||
)
|
||||
|
||||
add_executable(BazelReporter ${TESTS_DIR}/X30-BazelReporter.cpp)
|
||||
target_compile_definitions(BazelReporter PRIVATE CATCH_CONFIG_BAZEL_SUPPORT)
|
||||
target_link_libraries(BazelReporter Catch2_buildall_interface)
|
||||
add_test(NAME CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
COMMAND
|
||||
Python3::Interpreter "${CATCH_DIR}/tests/TestScripts/testBazelReporter.py" $<TARGET_FILE:BazelReporter> "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
set_tests_properties(CATCH_CONFIG_BAZEL_REPORTER-1
|
||||
PROPERTIES
|
||||
LABELS "uses-python"
|
||||
)
|
||||
|
||||
# We must now test this works without the build flag.
|
||||
add_executable(BazelReporterNoCatchConfig ${TESTS_DIR}/X30-BazelReporter.cpp)
|
||||
target_link_libraries(BazelReporterNoCatchConfig Catch2WithMain)
|
||||
@@ -429,6 +417,50 @@ set_tests_properties(Reporters::CrashInJunitReporter
|
||||
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
|
||||
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") {}
|
@@ -26,6 +26,7 @@ Nor would this
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - double
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - float
|
||||
:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
:test-result: PASS #3001: Enum-based bitfields can be captured
|
||||
:test-result: XFAIL #748 - captures with unexpected exceptions
|
||||
:test-result: PASS #809
|
||||
:test-result: PASS #833
|
||||
@@ -95,6 +96,8 @@ Nor would this
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: XFAIL Assertions can be nested - CHECK
|
||||
:test-result: XFAIL Assertions can be nested - REQUIRE
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
@@ -119,6 +122,7 @@ Nor would this
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing (and stringifying) volatile pointers works
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
@@ -150,9 +154,11 @@ Nor would this
|
||||
:test-result: PASS Exception matchers that succeed
|
||||
:test-result: PASS Exception message can be matched
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: PASS Exception thrown inside stringify does not fail the test
|
||||
:test-result: PASS Exceptions matchers
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: XFAIL FAIL can be nested in assertion
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: FAIL FAIL_CHECK does not abort the test
|
||||
:test-result: PASS Factorials are computed
|
||||
@@ -408,6 +414,7 @@ b1!
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
:test-result: PASS strlen3
|
||||
:test-result: PASS system_clock timepoint with non-default duration
|
||||
:test-result: PASS tables
|
||||
:test-result: PASS tags with dots in later positions are not parsed as hidden
|
||||
:test-result: SKIP tests can be skipped dynamically at runtime
|
||||
|
@@ -24,6 +24,7 @@
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - double
|
||||
:test-result: PASS #2152 - ULP checks between differently signed values were wrong - float
|
||||
:test-result: XFAIL #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
:test-result: PASS #3001: Enum-based bitfields can be captured
|
||||
:test-result: XFAIL #748 - captures with unexpected exceptions
|
||||
:test-result: PASS #809
|
||||
:test-result: PASS #833
|
||||
@@ -93,6 +94,8 @@
|
||||
:test-result: PASS Approximate comparisons with mixed numeric types
|
||||
:test-result: PASS Arbitrary predicate matcher
|
||||
:test-result: PASS Assertion macros support bit operators and bool conversions
|
||||
:test-result: XFAIL Assertions can be nested - CHECK
|
||||
:test-result: XFAIL Assertions can be nested - REQUIRE
|
||||
:test-result: PASS Assertions then sections
|
||||
:test-result: PASS Basic use of the Contains range matcher
|
||||
:test-result: PASS Basic use of the Empty range matcher
|
||||
@@ -117,6 +120,7 @@
|
||||
:test-result: PASS Combining templated and concrete matchers
|
||||
:test-result: PASS Combining templated matchers
|
||||
:test-result: PASS Commas in various macros are allowed
|
||||
:test-result: PASS Comparing (and stringifying) volatile pointers works
|
||||
:test-result: PASS Comparing function pointers
|
||||
:test-result: PASS Comparison ops
|
||||
:test-result: PASS Comparison with explicitly convertible types
|
||||
@@ -148,9 +152,11 @@
|
||||
:test-result: PASS Exception matchers that succeed
|
||||
:test-result: PASS Exception message can be matched
|
||||
:test-result: PASS Exception messages can be tested for
|
||||
:test-result: PASS Exception thrown inside stringify does not fail the test
|
||||
:test-result: PASS Exceptions matchers
|
||||
:test-result: FAIL Expected exceptions that don't throw or unexpected exceptions fail the test
|
||||
:test-result: FAIL FAIL aborts the test
|
||||
:test-result: XFAIL FAIL can be nested in assertion
|
||||
:test-result: FAIL FAIL does not require an argument
|
||||
:test-result: FAIL FAIL_CHECK does not abort the test
|
||||
:test-result: PASS Factorials are computed
|
||||
@@ -397,6 +403,7 @@
|
||||
:test-result: PASS stringify( vectors<has_maker_and_operator> )
|
||||
:test-result: PASS stringify( vectors<has_operator> )
|
||||
:test-result: PASS strlen3
|
||||
:test-result: PASS system_clock timepoint with non-default duration
|
||||
:test-result: PASS tables
|
||||
:test-result: PASS tags with dots in later positions are not parsed as hidden
|
||||
:test-result: SKIP tests can be skipped dynamically at runtime
|
||||
|
@@ -85,6 +85,8 @@ Matchers.tests.cpp:<line number>: passed: smallest_non_zero, !WithinULP( -smalle
|
||||
Matchers.tests.cpp:<line number>: passed: smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45])
|
||||
Matchers.tests.cpp:<line number>: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00])
|
||||
Generators.tests.cpp:<line number>: failed: unexpected exception with message: 'failure to init'; expression was: {Unknown expression after the reported line}
|
||||
Compilation.tests.cpp:<line number>: passed: bf.e == 1 for: 1 == 1
|
||||
Compilation.tests.cpp:<line number>: passed: 1 == bf.e for: 1 == 1
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: {Unknown expression after the reported line}
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
||||
@@ -332,6 +334,11 @@ Compilation.tests.cpp:<line number>: passed: !(lhs & rhs) for: !(Val: 1 & Val: 2
|
||||
Compilation.tests.cpp:<line number>: passed: HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val: 1
|
||||
Compilation.tests.cpp:<line number>: passed: lhs ^ rhs for: Val: 1 ^ Val: 2
|
||||
Compilation.tests.cpp:<line number>: passed: !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
|
||||
AssertionHandler.tests.cpp:<line number>: failed: i > 10 for: 2 > 10
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
AssertionHandler.tests.cpp:<line number>: passed: true
|
||||
AssertionHandler.tests.cpp:<line number>: failed: i > 10 for: 2 > 10
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
@@ -476,6 +483,13 @@ Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<in
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr) for: !0
|
||||
Misc.tests.cpp:<line number>: passed: ptr == ptr for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr != ptr) for: !(0 != 0)
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr < ptr) for: !(0 < 0)
|
||||
Misc.tests.cpp:<line number>: passed: ptr <= ptr for: 0 <= 0
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr > ptr) for: !(0 > 0)
|
||||
Misc.tests.cpp:<line number>: passed: ptr >= ptr for: 0 >= 0
|
||||
Tricky.tests.cpp:<line number>: passed: a for: 0x<hex digits>
|
||||
Tricky.tests.cpp:<line number>: passed: a == &foo for: 0x<hex digits> == 0x<hex digits>
|
||||
RandomNumberGeneration.tests.cpp:<line number>: passed: SimplePcg32{} == SimplePcg32{} for: {?} == {?}
|
||||
@@ -628,6 +642,9 @@ Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
|
||||
ToString.tests.cpp:<line number>: passed: tos == tos for: { stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, Message( "DerivedException::what" ) for: DerivedException::what exception message matches "DerivedException::what"
|
||||
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, !Message( "derivedexception::what" ) for: DerivedException::what not exception message matches "derivedexception::what"
|
||||
Matchers.tests.cpp:<line number>: passed: throwsSpecialException( 2 ), SpecialException, !Message( "DerivedException::what" ) for: SpecialException::what not exception message matches "DerivedException::what"
|
||||
@@ -636,6 +653,8 @@ Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'e
|
||||
Exception.tests.cpp:<line number>: failed: expected exception, got none; expression was: thisDoesntThrow(), std::domain_error
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows()
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'This is a failure'
|
||||
AssertionHandler.tests.cpp:<line number>: failed: explicitly with 1 message: 'Throw a Catch::TestFailureException'
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: do_fail()
|
||||
Message.tests.cpp:<line number>: failed: explicitly
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'This is a failure'
|
||||
Message.tests.cpp:<line number>: warning: 'This message appears in the output'
|
||||
@@ -805,6 +824,10 @@ GeneratorsImpl.tests.cpp:<line number>: passed: filter([](int) { return false; }
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
@@ -2757,6 +2780,9 @@ Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 =
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 4 == 4
|
||||
ToStringChrono.tests.cpp:<line number>: passed: tp1 == tp2 for: {iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
@@ -2862,7 +2888,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
|
||||
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
test cases: 428 | 313 passed | 95 failed | 6 skipped | 14 failed as expected
|
||||
assertions: 2281 | 2089 passed | 157 failed | 35 failed as expected
|
||||
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
|
||||
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
|
||||
|
||||
|
||||
|
@@ -83,6 +83,8 @@ Matchers.tests.cpp:<line number>: passed: smallest_non_zero, !WithinULP( -smalle
|
||||
Matchers.tests.cpp:<line number>: passed: smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.0f is within 2 ULPs of -1.40129846e-45f ([-4.20389539e-45, 1.40129846e-45])
|
||||
Matchers.tests.cpp:<line number>: passed: smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00])
|
||||
Generators.tests.cpp:<line number>: failed: unexpected exception with message: 'failure to init'; expression was: {Unknown expression after the reported line}
|
||||
Compilation.tests.cpp:<line number>: passed: bf.e == 1 for: 1 == 1
|
||||
Compilation.tests.cpp:<line number>: passed: 1 == bf.e for: 1 == 1
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: {Unknown expression after the reported line}
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
||||
@@ -330,6 +332,11 @@ Compilation.tests.cpp:<line number>: passed: !(lhs & rhs) for: !(Val: 1 & Val: 2
|
||||
Compilation.tests.cpp:<line number>: passed: HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val: 1
|
||||
Compilation.tests.cpp:<line number>: passed: lhs ^ rhs for: Val: 1 ^ Val: 2
|
||||
Compilation.tests.cpp:<line number>: passed: !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
|
||||
AssertionHandler.tests.cpp:<line number>: failed: i > 10 for: 2 > 10
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
AssertionHandler.tests.cpp:<line number>: passed: true
|
||||
AssertionHandler.tests.cpp:<line number>: failed: i > 10 for: 2 > 10
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
@@ -474,6 +481,13 @@ Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<in
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
Tricky.tests.cpp:<line number>: passed: true
|
||||
Tricky.tests.cpp:<line number>: passed: std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr) for: !0
|
||||
Misc.tests.cpp:<line number>: passed: ptr == ptr for: 0 == 0
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr != ptr) for: !(0 != 0)
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr < ptr) for: !(0 < 0)
|
||||
Misc.tests.cpp:<line number>: passed: ptr <= ptr for: 0 <= 0
|
||||
Misc.tests.cpp:<line number>: passed: !(ptr > ptr) for: !(0 > 0)
|
||||
Misc.tests.cpp:<line number>: passed: ptr >= ptr for: 0 >= 0
|
||||
Tricky.tests.cpp:<line number>: passed: a for: 0x<hex digits>
|
||||
Tricky.tests.cpp:<line number>: passed: a == &foo for: 0x<hex digits> == 0x<hex digits>
|
||||
RandomNumberGeneration.tests.cpp:<line number>: passed: SimplePcg32{} == SimplePcg32{} for: {?} == {?}
|
||||
@@ -626,6 +640,9 @@ Exception.tests.cpp:<line number>: passed: thisThrows(), StartsWith( "expected"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), EndsWith( "exception" ) for: "expected exception" ends with: "exception"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
|
||||
Exception.tests.cpp:<line number>: passed: thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
|
||||
ToString.tests.cpp:<line number>: passed: tos == tos for: { stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, Message( "DerivedException::what" ) for: DerivedException::what exception message matches "DerivedException::what"
|
||||
Matchers.tests.cpp:<line number>: passed: throwsDerivedException(), DerivedException, !Message( "derivedexception::what" ) for: DerivedException::what not exception message matches "derivedexception::what"
|
||||
Matchers.tests.cpp:<line number>: passed: throwsSpecialException( 2 ), SpecialException, !Message( "DerivedException::what" ) for: SpecialException::what not exception message matches "DerivedException::what"
|
||||
@@ -634,6 +651,8 @@ Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'e
|
||||
Exception.tests.cpp:<line number>: failed: expected exception, got none; expression was: thisDoesntThrow(), std::domain_error
|
||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'expected exception'; expression was: thisThrows()
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'This is a failure'
|
||||
AssertionHandler.tests.cpp:<line number>: failed: explicitly with 1 message: 'Throw a Catch::TestFailureException'
|
||||
AssertionHandler.tests.cpp:<line number>: failed: unexpected exception with message: '{ nested assertion failed }'; expression was: do_fail()
|
||||
Message.tests.cpp:<line number>: failed: explicitly
|
||||
Message.tests.cpp:<line number>: failed: explicitly with 1 message: 'This is a failure'
|
||||
Message.tests.cpp:<line number>: warning: 'This message appears in the output'
|
||||
@@ -803,6 +822,10 @@ GeneratorsImpl.tests.cpp:<line number>: passed: filter([](int) { return false; }
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 3 for: 3 == 3
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.next() for: true
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 2 for: 2 == 2
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
|
||||
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
|
||||
@@ -2746,6 +2769,9 @@ Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 =
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 3 == 3
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: data.str.size() == data.len for: 4 == 4
|
||||
ToStringChrono.tests.cpp:<line number>: passed: tp1 == tp2 for: {iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 6 == 6
|
||||
Generators.tests.cpp:<line number>: passed: strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
@@ -2851,7 +2877,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
|
||||
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
Misc.tests.cpp:<line number>: passed:
|
||||
test cases: 428 | 313 passed | 95 failed | 6 skipped | 14 failed as expected
|
||||
assertions: 2281 | 2089 passed | 157 failed | 35 failed as expected
|
||||
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
|
||||
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
|
||||
|
||||
|
||||
|
@@ -347,6 +347,38 @@ Exception.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
unexpected exception
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - CHECK
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - REQUIRE
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Captures do not leave block with an exception
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -619,6 +651,21 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
This is a failure
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL can be nested in assertion
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Throw a Catch::TestFailureException
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL does not require an argument
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -1672,6 +1719,6 @@ due to unexpected exception with message:
|
||||
Why would you throw a std::string?
|
||||
|
||||
===============================================================================
|
||||
test cases: 428 | 331 passed | 76 failed | 7 skipped | 14 failed as expected
|
||||
assertions: 2260 | 2089 passed | 136 failed | 35 failed as expected
|
||||
test cases: 435 | 335 passed | 76 failed | 7 skipped | 17 failed as expected
|
||||
assertions: 2282 | 2105 passed | 136 failed | 41 failed as expected
|
||||
|
||||
|
@@ -772,6 +772,22 @@ Generators.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
failure to init
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#3001: Enum-based bitfields can be captured
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( bf.e == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 1 == bf.e )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -2566,6 +2582,41 @@ Compilation.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
!(Val: 1 ^ Val: 1)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - CHECK
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: PASSED:
|
||||
CHECK( true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - REQUIRE
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions then sections
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -3504,6 +3555,47 @@ Tricky.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
{ 1, 2 } == { 1, 2 }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Comparing (and stringifying) volatile pointers works
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr )
|
||||
with expansion:
|
||||
!0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr == ptr )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr != ptr )
|
||||
with expansion:
|
||||
!(0 != 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr < ptr )
|
||||
with expansion:
|
||||
!(0 < 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr <= ptr )
|
||||
with expansion:
|
||||
0 <= 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr > ptr )
|
||||
with expansion:
|
||||
!(0 > 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr >= ptr )
|
||||
with expansion:
|
||||
0 >= 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Comparing function pointers
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -4505,6 +4597,19 @@ Exception.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
"expected exception" contains: "except" (case insensitive)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Exception thrown inside stringify does not fail the test
|
||||
-------------------------------------------------------------------------------
|
||||
ToString.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToString.tests.cpp:<line number>: PASSED:
|
||||
CHECK( tos == tos )
|
||||
with expansion:
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Exceptions matchers
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -4561,6 +4666,21 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
This is a failure
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL can be nested in assertion
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Throw a Catch::TestFailureException
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL does not require an argument
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -5934,6 +6054,34 @@ GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Generators internals
|
||||
Filter generator
|
||||
Out-of-line predicates are copied into the generator
|
||||
-------------------------------------------------------------------------------
|
||||
GeneratorsImpl.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.get() == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.next() )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.get() == 3 )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( gen.next() )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Generators internals
|
||||
Take generator
|
||||
@@ -18343,6 +18491,19 @@ Generators.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
4 == 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
system_clock timepoint with non-default duration
|
||||
-------------------------------------------------------------------------------
|
||||
ToStringChrono.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToStringChrono.tests.cpp:<line number>: PASSED:
|
||||
CHECK( tp1 == tp2 )
|
||||
with expansion:
|
||||
{iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
tables
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -19134,6 +19295,6 @@ Misc.tests.cpp:<line number>
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 428 | 313 passed | 95 failed | 6 skipped | 14 failed as expected
|
||||
assertions: 2281 | 2089 passed | 157 failed | 35 failed as expected
|
||||
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
|
||||
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
|
||||
|
||||
|
@@ -770,6 +770,22 @@ Generators.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
failure to init
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#3001: Enum-based bitfields can be captured
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( bf.e == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 1 == bf.e )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -2564,6 +2580,41 @@ Compilation.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
!(Val: 1 ^ Val: 1)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - CHECK
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: PASSED:
|
||||
CHECK( true )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions can be nested - REQUIRE
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Assertions then sections
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -3502,6 +3553,47 @@ Tricky.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
{ 1, 2 } == { 1, 2 }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Comparing (and stringifying) volatile pointers works
|
||||
-------------------------------------------------------------------------------
|
||||
Misc.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr )
|
||||
with expansion:
|
||||
!0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr == ptr )
|
||||
with expansion:
|
||||
0 == 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr != ptr )
|
||||
with expansion:
|
||||
!(0 != 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr < ptr )
|
||||
with expansion:
|
||||
!(0 < 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr <= ptr )
|
||||
with expansion:
|
||||
0 <= 0
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( ptr > ptr )
|
||||
with expansion:
|
||||
!(0 > 0)
|
||||
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( ptr >= ptr )
|
||||
with expansion:
|
||||
0 >= 0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Comparing function pointers
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -4503,6 +4595,19 @@ Exception.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
"expected exception" contains: "except" (case insensitive)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Exception thrown inside stringify does not fail the test
|
||||
-------------------------------------------------------------------------------
|
||||
ToString.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToString.tests.cpp:<line number>: PASSED:
|
||||
CHECK( tos == tos )
|
||||
with expansion:
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Exceptions matchers
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -4559,6 +4664,21 @@ Message.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
This is a failure
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL can be nested in assertion
|
||||
-------------------------------------------------------------------------------
|
||||
AssertionHandler.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
explicitly with message:
|
||||
Throw a Catch::TestFailureException
|
||||
|
||||
AssertionHandler.tests.cpp:<line number>: FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
due to unexpected exception with message:
|
||||
{ nested assertion failed }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
FAIL does not require an argument
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -5932,6 +6052,34 @@ GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_THROWS_AS( filter([](int) { return false; }, values({ 1, 2, 3 })), Catch::GeneratorException )
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Generators internals
|
||||
Filter generator
|
||||
Out-of-line predicates are copied into the generator
|
||||
-------------------------------------------------------------------------------
|
||||
GeneratorsImpl.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.get() == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.next() )
|
||||
with expansion:
|
||||
true
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( gen.get() == 3 )
|
||||
with expansion:
|
||||
3 == 3
|
||||
|
||||
GeneratorsImpl.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE_FALSE( gen.next() )
|
||||
with expansion:
|
||||
!false
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Generators internals
|
||||
Take generator
|
||||
@@ -18332,6 +18480,19 @@ Generators.tests.cpp:<line number>: PASSED:
|
||||
with expansion:
|
||||
4 == 4
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
system_clock timepoint with non-default duration
|
||||
-------------------------------------------------------------------------------
|
||||
ToStringChrono.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
ToStringChrono.tests.cpp:<line number>: PASSED:
|
||||
CHECK( tp1 == tp2 )
|
||||
with expansion:
|
||||
{iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
tables
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -19123,6 +19284,6 @@ Misc.tests.cpp:<line number>
|
||||
Misc.tests.cpp:<line number>: PASSED:
|
||||
|
||||
===============================================================================
|
||||
test cases: 428 | 313 passed | 95 failed | 6 skipped | 14 failed as expected
|
||||
assertions: 2281 | 2089 passed | 157 failed | 35 failed as expected
|
||||
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
|
||||
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
|
||||
|
||||
|
@@ -772,6 +772,22 @@ Generators.tests.cpp:<line number>: FAILED:
|
||||
due to unexpected exception with message:
|
||||
failure to init
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#3001: Enum-based bitfields can be captured
|
||||
-------------------------------------------------------------------------------
|
||||
Compilation.tests.cpp:<line number>
|
||||
...............................................................................
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( bf.e == 1 )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
Compilation.tests.cpp:<line number>: PASSED:
|
||||
REQUIRE( 1 == bf.e )
|
||||
with expansion:
|
||||
1 == 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
#748 - captures with unexpected exceptions
|
||||
outside assertions
|
||||
@@ -952,6 +968,6 @@ Condition.tests.cpp:<line number>: FAILED:
|
||||
CHECK( true != true )
|
||||
|
||||
===============================================================================
|
||||
test cases: 33 | 27 passed | 3 failed | 3 failed as expected
|
||||
assertions: 102 | 94 passed | 4 failed | 4 failed as expected
|
||||
test cases: 34 | 28 passed | 3 failed | 3 failed as expected
|
||||
assertions: 104 | 96 passed | 4 failed | 4 failed as expected
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuitesloose text artifact
|
||||
>
|
||||
<testsuite name="<exe-name>" errors="17" failures="140" skipped="12" tests="2293" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="17" failures="140" skipped="12" tests="2315" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<properties>
|
||||
<property name="random-seed" value="1"/>
|
||||
<property name="filters" value=""*" ~[!nonportable] ~[!benchmark] ~[approvals]"/>
|
||||
@@ -60,6 +60,7 @@ failure to init
|
||||
at Generators.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="#3001: Enum-based bitfields can be captured" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
@@ -390,6 +391,38 @@ at Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Function pointer" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Lambdas + different type" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertion macros support bit operators and bool conversions" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions can be nested - CHECK" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure message="i > 10" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="foo( 2 ) == 2" type="CHECK">
|
||||
FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Assertions can be nested - REQUIRE" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure message="i > 10" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="foo( 2 ) == 2" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}" status="run"/>
|
||||
@@ -455,6 +488,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated and concrete matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparing (and stringifying) volatile pointers works" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparison with explicitly convertible types" time="{duration}" status="run"/>
|
||||
@@ -711,6 +745,7 @@ at Matchers.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/exact match" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/different case" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/wildcarded" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception thrown inside stringify does not fail the test" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exceptions matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Expected exceptions that don't throw or unexpected exceptions fail the test" time="{duration}" status="run">
|
||||
<error message="thisThrows(), std::string" type="CHECK_THROWS_AS">
|
||||
@@ -738,6 +773,20 @@ This is a failure
|
||||
at Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="FAIL can be nested in assertion" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure type="FAIL">
|
||||
FAILED:
|
||||
Throw a Catch::TestFailureException
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="do_fail()" type="CHECK_NOTHROW">
|
||||
FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="FAIL does not require an argument" time="{duration}" status="run">
|
||||
<failure type="FAIL">
|
||||
FAILED:
|
||||
@@ -797,6 +846,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Simple filtering" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Filter out multiple elements at the start and end" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Throws on construction if it can't get initial element" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Out-of-line predicates are copied into the generator" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take less" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take more" time="{duration}" status="run"/>
|
||||
@@ -2286,6 +2336,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="system_clock timepoint with non-default duration" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tables" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tags with dots in later positions are not parsed as hidden" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tests can be skipped dynamically at runtime" time="{duration}" status="run">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="<exe-name>" errors="17" failures="140" skipped="12" tests="2293" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<testsuite name="<exe-name>" errors="17" failures="140" skipped="12" tests="2315" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||
<properties>
|
||||
<property name="random-seed" value="1"/>
|
||||
<property name="filters" value=""*" ~[!nonportable] ~[!benchmark] ~[approvals]"/>
|
||||
@@ -59,6 +59,7 @@ failure to init
|
||||
at Generators.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="#3001: Enum-based bitfields can be captured" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="#748 - captures with unexpected exceptions/outside assertions" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
@@ -389,6 +390,38 @@ at Exception.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Function pointer" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Arbitrary predicate matcher/Lambdas + different type" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertion macros support bit operators and bool conversions" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions can be nested - CHECK" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure message="i > 10" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="foo( 2 ) == 2" type="CHECK">
|
||||
FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Assertions can be nested - REQUIRE" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure message="i > 10" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="foo( 2 ) == 2" type="REQUIRE">
|
||||
FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Assertions then sections/A section/Another section" time="{duration}" status="run"/>
|
||||
@@ -454,6 +487,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated and concrete matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Combining templated matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Commas in various macros are allowed" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparing (and stringifying) volatile pointers works" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparing function pointers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparison ops" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Comparison with explicitly convertible types" time="{duration}" status="run"/>
|
||||
@@ -710,6 +744,7 @@ at Matchers.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/exact match" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/different case" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception messages can be tested for/wildcarded" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exception thrown inside stringify does not fail the test" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Exceptions matchers" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Expected exceptions that don't throw or unexpected exceptions fail the test" time="{duration}" status="run">
|
||||
<error message="thisThrows(), std::string" type="CHECK_THROWS_AS">
|
||||
@@ -737,6 +772,20 @@ This is a failure
|
||||
at Message.tests.cpp:<line number>
|
||||
</failure>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="FAIL can be nested in assertion" time="{duration}" status="run">
|
||||
<skipped message="TEST_CASE tagged with !mayfail"/>
|
||||
<failure type="FAIL">
|
||||
FAILED:
|
||||
Throw a Catch::TestFailureException
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</failure>
|
||||
<error message="do_fail()" type="CHECK_NOTHROW">
|
||||
FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</error>
|
||||
</testcase>
|
||||
<testcase classname="<exe-name>.global" name="FAIL does not require an argument" time="{duration}" status="run">
|
||||
<failure type="FAIL">
|
||||
FAILED:
|
||||
@@ -796,6 +845,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Simple filtering" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Filter out multiple elements at the start and end" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Throws on construction if it can't get initial element" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Filter generator/Out-of-line predicates are copied into the generator" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take less" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="Generators internals/Take generator/Take more" time="{duration}" status="run"/>
|
||||
@@ -2285,6 +2335,7 @@ at Message.tests.cpp:<line number>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="strlen3" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="system_clock timepoint with non-default duration" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tables" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tags with dots in later positions are not parsed as hidden" time="{duration}" status="run"/>
|
||||
<testcase classname="<exe-name>.global" name="tests can be skipped dynamically at runtime" time="{duration}" status="run">
|
||||
|
@@ -3,6 +3,49 @@
|
||||
<testExecutions version="1"loose text artifact
|
||||
>
|
||||
<file path="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp">
|
||||
<testCase name="Assertions can be nested - CHECK" duration="{duration}">
|
||||
<skipped message="REQUIRE(i > 10)">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="CHECK(foo( 2 ) == 2)">
|
||||
FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="Assertions can be nested - REQUIRE" duration="{duration}">
|
||||
<skipped message="REQUIRE(i > 10)">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="REQUIRE(foo( 2 ) == 2)">
|
||||
FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="FAIL can be nested in assertion" duration="{duration}">
|
||||
<skipped message="FAIL()">
|
||||
FAILED:
|
||||
Throw a Catch::TestFailureException
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="CHECK_NOTHROW(do_fail())">
|
||||
FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="Incomplete AssertionHandler" duration="{duration}">
|
||||
<skipped message="REQUIRE(Dummy)">
|
||||
FAILED:
|
||||
@@ -110,6 +153,7 @@ at AssertionHandler.tests.cpp:<line number>
|
||||
<testCase name="Generators internals/Filter generator/Simple filtering" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Filter out multiple elements at the start and end" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Throws on construction if it can't get initial element" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Out-of-line predicates are copied into the generator" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator/Take less" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator/Take more" duration="{duration}"/>
|
||||
@@ -344,6 +388,7 @@ at AssertionHandler.tests.cpp:<line number>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp">
|
||||
<testCase name="Directly creating an EnumInfo" duration="{duration}"/>
|
||||
<testCase name="Exception thrown inside stringify does not fail the test" duration="{duration}"/>
|
||||
<testCase name="Range type with sentinel" duration="{duration}"/>
|
||||
<testCase name="Stringifying char arrays with statically known sizes - char" duration="{duration}"/>
|
||||
<testCase name="Stringifying char arrays with statically known sizes - signed char" duration="{duration}"/>
|
||||
@@ -612,6 +657,7 @@ at Class.tests.cpp:<line number>
|
||||
<testCase name="#1319: Sections can have description (even if it is not saved/SectionName" duration="{duration}"/>
|
||||
<testCase name="#1403" duration="{duration}"/>
|
||||
<testCase name="#1548" duration="{duration}"/>
|
||||
<testCase name="#3001: Enum-based bitfields can be captured" duration="{duration}"/>
|
||||
<testCase name="#809" duration="{duration}"/>
|
||||
<testCase name="#833" duration="{duration}"/>
|
||||
<testCase name="#872" duration="{duration}"/>
|
||||
@@ -1889,6 +1935,7 @@ at Misc.tests.cpp:<line number>
|
||||
<testCase name="A couple of nested sections followed by a failure/Outer" duration="{duration}"/>
|
||||
<testCase name="A couple of nested sections followed by a failure/Outer/Inner" duration="{duration}"/>
|
||||
<testCase name="An empty test with no assertions" duration="{duration}"/>
|
||||
<testCase name="Comparing (and stringifying) volatile pointers works" duration="{duration}"/>
|
||||
<testCase name="Factorials are computed" duration="{duration}"/>
|
||||
<testCase name="ManuallyRegistered" duration="{duration}"/>
|
||||
<testCase name="Nice descriptive name" duration="{duration}"/>
|
||||
@@ -2254,6 +2301,7 @@ at Skip.tests.cpp:<line number>
|
||||
<testCase name="Stringifying std::chrono::duration helpers" duration="{duration}"/>
|
||||
<testCase name="Stringifying std::chrono::duration with weird ratios" duration="{duration}"/>
|
||||
<testCase name="Stringifying std::chrono::time_point<system_clock>" duration="{duration}"/>
|
||||
<testCase name="system_clock timepoint with non-default duration" duration="{duration}"/>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/UsageTests/ToStringGeneral.tests.cpp">
|
||||
<testCase name="Capture and info messages" duration="{duration}"/>
|
||||
|
@@ -2,6 +2,49 @@
|
||||
<!-- filters='"*" ~[!nonportable] ~[!benchmark] ~[approvals]' rng-seed=1 -->
|
||||
<testExecutions version="1">
|
||||
<file path="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp">
|
||||
<testCase name="Assertions can be nested - CHECK" duration="{duration}">
|
||||
<skipped message="REQUIRE(i > 10)">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="CHECK(foo( 2 ) == 2)">
|
||||
FAILED:
|
||||
CHECK( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="Assertions can be nested - REQUIRE" duration="{duration}">
|
||||
<skipped message="REQUIRE(i > 10)">
|
||||
FAILED:
|
||||
REQUIRE( i > 10 )
|
||||
with expansion:
|
||||
2 > 10
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="REQUIRE(foo( 2 ) == 2)">
|
||||
FAILED:
|
||||
REQUIRE( foo( 2 ) == 2 )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="FAIL can be nested in assertion" duration="{duration}">
|
||||
<skipped message="FAIL()">
|
||||
FAILED:
|
||||
Throw a Catch::TestFailureException
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
<skipped message="CHECK_NOTHROW(do_fail())">
|
||||
FAILED:
|
||||
CHECK_NOTHROW( do_fail() )
|
||||
{ nested assertion failed }
|
||||
at AssertionHandler.tests.cpp:<line number>
|
||||
</skipped>
|
||||
</testCase>
|
||||
<testCase name="Incomplete AssertionHandler" duration="{duration}">
|
||||
<skipped message="REQUIRE(Dummy)">
|
||||
FAILED:
|
||||
@@ -109,6 +152,7 @@ at AssertionHandler.tests.cpp:<line number>
|
||||
<testCase name="Generators internals/Filter generator/Simple filtering" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Filter out multiple elements at the start and end" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Throws on construction if it can't get initial element" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Filter generator/Out-of-line predicates are copied into the generator" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator/Take less" duration="{duration}"/>
|
||||
<testCase name="Generators internals/Take generator/Take more" duration="{duration}"/>
|
||||
@@ -343,6 +387,7 @@ at AssertionHandler.tests.cpp:<line number>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp">
|
||||
<testCase name="Directly creating an EnumInfo" duration="{duration}"/>
|
||||
<testCase name="Exception thrown inside stringify does not fail the test" duration="{duration}"/>
|
||||
<testCase name="Range type with sentinel" duration="{duration}"/>
|
||||
<testCase name="Stringifying char arrays with statically known sizes - char" duration="{duration}"/>
|
||||
<testCase name="Stringifying char arrays with statically known sizes - signed char" duration="{duration}"/>
|
||||
@@ -611,6 +656,7 @@ at Class.tests.cpp:<line number>
|
||||
<testCase name="#1319: Sections can have description (even if it is not saved/SectionName" duration="{duration}"/>
|
||||
<testCase name="#1403" duration="{duration}"/>
|
||||
<testCase name="#1548" duration="{duration}"/>
|
||||
<testCase name="#3001: Enum-based bitfields can be captured" duration="{duration}"/>
|
||||
<testCase name="#809" duration="{duration}"/>
|
||||
<testCase name="#833" duration="{duration}"/>
|
||||
<testCase name="#872" duration="{duration}"/>
|
||||
@@ -1888,6 +1934,7 @@ at Misc.tests.cpp:<line number>
|
||||
<testCase name="A couple of nested sections followed by a failure/Outer" duration="{duration}"/>
|
||||
<testCase name="A couple of nested sections followed by a failure/Outer/Inner" duration="{duration}"/>
|
||||
<testCase name="An empty test with no assertions" duration="{duration}"/>
|
||||
<testCase name="Comparing (and stringifying) volatile pointers works" duration="{duration}"/>
|
||||
<testCase name="Factorials are computed" duration="{duration}"/>
|
||||
<testCase name="ManuallyRegistered" duration="{duration}"/>
|
||||
<testCase name="Nice descriptive name" duration="{duration}"/>
|
||||
@@ -2253,6 +2300,7 @@ at Skip.tests.cpp:<line number>
|
||||
<testCase name="Stringifying std::chrono::duration helpers" duration="{duration}"/>
|
||||
<testCase name="Stringifying std::chrono::duration with weird ratios" duration="{duration}"/>
|
||||
<testCase name="Stringifying std::chrono::time_point<system_clock>" duration="{duration}"/>
|
||||
<testCase name="system_clock timepoint with non-default duration" duration="{duration}"/>
|
||||
</file>
|
||||
<file path="tests/<exe-name>/UsageTests/ToStringGeneral.tests.cpp">
|
||||
<testCase name="Capture and info messages" duration="{duration}"/>
|
||||
|
@@ -166,6 +166,10 @@ ok {test-number} - smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.
|
||||
ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00])
|
||||
# #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
not ok {test-number} - unexpected exception with message: 'failure to init'; expression was: {Unknown expression after the reported line}
|
||||
# #3001: Enum-based bitfields can be captured
|
||||
ok {test-number} - bf.e == 1 for: 1 == 1
|
||||
# #3001: Enum-based bitfields can be captured
|
||||
ok {test-number} - 1 == bf.e for: 1 == 1
|
||||
# #748 - captures with unexpected exceptions
|
||||
not ok {test-number} - unexpected exception with message: 'expected exception'; expression was: {Unknown expression after the reported line}
|
||||
# #748 - captures with unexpected exceptions
|
||||
@@ -612,6 +616,16 @@ ok {test-number} - HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val
|
||||
ok {test-number} - lhs ^ rhs for: Val: 1 ^ Val: 2
|
||||
# Assertion macros support bit operators and bool conversions
|
||||
ok {test-number} - !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
|
||||
# Assertions can be nested - CHECK
|
||||
not ok {test-number} - i > 10 for: 2 > 10
|
||||
# Assertions can be nested - CHECK
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
# Assertions can be nested - CHECK
|
||||
ok {test-number} - true
|
||||
# Assertions can be nested - REQUIRE
|
||||
not ok {test-number} - i > 10 for: 2 > 10
|
||||
# Assertions can be nested - REQUIRE
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
# Assertions then sections
|
||||
ok {test-number} - true
|
||||
# Assertions then sections
|
||||
@@ -852,6 +866,20 @@ ok {test-number} - std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2
|
||||
ok {test-number} - true
|
||||
# Commas in various macros are allowed
|
||||
ok {test-number} - std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr) for: !0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr == ptr for: 0 == 0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr != ptr) for: !(0 != 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr < ptr) for: !(0 < 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr <= ptr for: 0 <= 0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr > ptr) for: !(0 > 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr >= ptr for: 0 >= 0
|
||||
# Comparing function pointers
|
||||
ok {test-number} - a for: 0x<hex digits>
|
||||
# Comparing function pointers
|
||||
@@ -1116,6 +1144,8 @@ ok {test-number} - thisThrows(), EndsWith( "exception" ) for: "expected exceptio
|
||||
ok {test-number} - thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
|
||||
# Exception messages can be tested for
|
||||
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
|
||||
# Exception thrown inside stringify does not fail the test
|
||||
ok {test-number} - tos == tos for: { stringification failed with an exception: "Invalid" } == { stringification failed with an exception: "Invalid" }
|
||||
# Exceptions matchers
|
||||
ok {test-number} - throwsDerivedException(), DerivedException, Message( "DerivedException::what" ) for: DerivedException::what exception message matches "DerivedException::what"
|
||||
# Exceptions matchers
|
||||
@@ -1132,6 +1162,10 @@ not ok {test-number} - expected exception, got none; expression was: thisDoesntT
|
||||
not ok {test-number} - unexpected exception with message: 'expected exception'; expression was: thisThrows()
|
||||
# FAIL aborts the test
|
||||
not ok {test-number} - explicitly with 1 message: 'This is a failure'
|
||||
# FAIL can be nested in assertion
|
||||
not ok {test-number} - explicitly with 1 message: 'Throw a Catch::TestFailureException'
|
||||
# FAIL can be nested in assertion
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: do_fail()
|
||||
# FAIL does not require an argument
|
||||
not ok {test-number} - explicitly
|
||||
# FAIL_CHECK does not abort the test
|
||||
@@ -1471,6 +1505,14 @@ ok {test-number} - gen.get() == 1 for: 1 == 1
|
||||
# Generators internals
|
||||
ok {test-number} - gen.next() for: true
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 3 for: 3 == 3
|
||||
# Generators internals
|
||||
ok {test-number} - !(gen.next()) for: !false
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 1 for: 1 == 1
|
||||
# Generators internals
|
||||
ok {test-number} - gen.next() for: true
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 2 for: 2 == 2
|
||||
# Generators internals
|
||||
ok {test-number} - !(gen.next()) for: !false
|
||||
@@ -4393,6 +4435,8 @@ ok {test-number} - data.str.size() == data.len for: 3 == 3
|
||||
ok {test-number} - data.str.size() == data.len for: 5 == 5
|
||||
# strlen3
|
||||
ok {test-number} - data.str.size() == data.len for: 4 == 4
|
||||
# system_clock timepoint with non-default duration
|
||||
ok {test-number} - tp1 == tp2 for: {iso8601-timestamp} == {iso8601-timestamp}
|
||||
# tables
|
||||
ok {test-number} - strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
# tables
|
||||
@@ -4583,5 +4627,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
|
||||
ok {test-number} -
|
||||
# xmlentitycheck
|
||||
ok {test-number} -
|
||||
1..2293
|
||||
1..2315
|
||||
|
||||
|
@@ -164,6 +164,10 @@ ok {test-number} - smallest_non_zero, WithinULP( -smallest_non_zero, 2 ) for: 0.
|
||||
ok {test-number} - smallest_non_zero, !WithinULP( -smallest_non_zero, 1 ) for: 0.0f not is within 1 ULPs of -1.40129846e-45f ([-2.80259693e-45, -0.00000000e+00])
|
||||
# #2615 - Throwing in constructor generator fails test case but does not abort
|
||||
not ok {test-number} - unexpected exception with message: 'failure to init'; expression was: {Unknown expression after the reported line}
|
||||
# #3001: Enum-based bitfields can be captured
|
||||
ok {test-number} - bf.e == 1 for: 1 == 1
|
||||
# #3001: Enum-based bitfields can be captured
|
||||
ok {test-number} - 1 == bf.e for: 1 == 1
|
||||
# #748 - captures with unexpected exceptions
|
||||
not ok {test-number} - unexpected exception with message: 'expected exception'; expression was: {Unknown expression after the reported line}
|
||||
# #748 - captures with unexpected exceptions
|
||||
@@ -610,6 +614,16 @@ ok {test-number} - HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val
|
||||
ok {test-number} - lhs ^ rhs for: Val: 1 ^ Val: 2
|
||||
# Assertion macros support bit operators and bool conversions
|
||||
ok {test-number} - !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
|
||||
# Assertions can be nested - CHECK
|
||||
not ok {test-number} - i > 10 for: 2 > 10
|
||||
# Assertions can be nested - CHECK
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
# Assertions can be nested - CHECK
|
||||
ok {test-number} - true
|
||||
# Assertions can be nested - REQUIRE
|
||||
not ok {test-number} - i > 10 for: 2 > 10
|
||||
# Assertions can be nested - REQUIRE
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: foo( 2 ) == 2
|
||||
# Assertions then sections
|
||||
ok {test-number} - true
|
||||
# Assertions then sections
|
||||
@@ -850,6 +864,20 @@ ok {test-number} - std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2
|
||||
ok {test-number} - true
|
||||
# Commas in various macros are allowed
|
||||
ok {test-number} - std::vector<int>{1, 2} == std::vector<int>{1, 2} for: { 1, 2 } == { 1, 2 }
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr) for: !0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr == ptr for: 0 == 0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr != ptr) for: !(0 != 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr < ptr) for: !(0 < 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr <= ptr for: 0 <= 0
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - !(ptr > ptr) for: !(0 > 0)
|
||||
# Comparing (and stringifying) volatile pointers works
|
||||
ok {test-number} - ptr >= ptr for: 0 >= 0
|
||||
# Comparing function pointers
|
||||
ok {test-number} - a for: 0x<hex digits>
|
||||
# Comparing function pointers
|
||||
@@ -1114,6 +1142,8 @@ ok {test-number} - thisThrows(), EndsWith( "exception" ) for: "expected exceptio
|
||||
ok {test-number} - thisThrows(), ContainsSubstring( "except" ) for: "expected exception" contains: "except"
|
||||
# Exception messages can be tested for
|
||||
ok {test-number} - thisThrows(), ContainsSubstring( "exCept", Catch::CaseSensitive::No ) for: "expected exception" contains: "except" (case insensitive)
|
||||
# Exception thrown inside stringify does not fail the test
|
||||
ok {test-number} - tos == tos for: { stringification failed with an exception: "Invalid" } == { stringification failed with an exception: "Invalid" }
|
||||
# Exceptions matchers
|
||||
ok {test-number} - throwsDerivedException(), DerivedException, Message( "DerivedException::what" ) for: DerivedException::what exception message matches "DerivedException::what"
|
||||
# Exceptions matchers
|
||||
@@ -1130,6 +1160,10 @@ not ok {test-number} - expected exception, got none; expression was: thisDoesntT
|
||||
not ok {test-number} - unexpected exception with message: 'expected exception'; expression was: thisThrows()
|
||||
# FAIL aborts the test
|
||||
not ok {test-number} - explicitly with 1 message: 'This is a failure'
|
||||
# FAIL can be nested in assertion
|
||||
not ok {test-number} - explicitly with 1 message: 'Throw a Catch::TestFailureException'
|
||||
# FAIL can be nested in assertion
|
||||
not ok {test-number} - unexpected exception with message: '{ nested assertion failed }'; expression was: do_fail()
|
||||
# FAIL does not require an argument
|
||||
not ok {test-number} - explicitly
|
||||
# FAIL_CHECK does not abort the test
|
||||
@@ -1469,6 +1503,14 @@ ok {test-number} - gen.get() == 1 for: 1 == 1
|
||||
# Generators internals
|
||||
ok {test-number} - gen.next() for: true
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 3 for: 3 == 3
|
||||
# Generators internals
|
||||
ok {test-number} - !(gen.next()) for: !false
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 1 for: 1 == 1
|
||||
# Generators internals
|
||||
ok {test-number} - gen.next() for: true
|
||||
# Generators internals
|
||||
ok {test-number} - gen.get() == 2 for: 2 == 2
|
||||
# Generators internals
|
||||
ok {test-number} - !(gen.next()) for: !false
|
||||
@@ -4382,6 +4424,8 @@ ok {test-number} - data.str.size() == data.len for: 3 == 3
|
||||
ok {test-number} - data.str.size() == data.len for: 5 == 5
|
||||
# strlen3
|
||||
ok {test-number} - data.str.size() == data.len for: 4 == 4
|
||||
# system_clock timepoint with non-default duration
|
||||
ok {test-number} - tp1 == tp2 for: {iso8601-timestamp} == {iso8601-timestamp}
|
||||
# tables
|
||||
ok {test-number} - strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data)) for: 5 == 5
|
||||
# tables
|
||||
@@ -4572,5 +4616,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
|
||||
ok {test-number} -
|
||||
# xmlentitycheck
|
||||
ok {test-number} -
|
||||
1..2293
|
||||
1..2315
|
||||
|
||||
|
@@ -55,6 +55,8 @@
|
||||
##teamcity[testStarted name='#2615 - Throwing in constructor generator fails test case but does not abort']
|
||||
##teamcity[testIgnored name='#2615 - Throwing in constructor generator fails test case but does not abort' message='Generators.tests.cpp:<line number>|n...............................................................................|n|nGenerators.tests.cpp:<line number>|nunexpected exception with message:|n "failure to init"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='#2615 - Throwing in constructor generator fails test case but does not abort' duration="{duration}"]
|
||||
##teamcity[testStarted name='#3001: Enum-based bitfields can be captured']
|
||||
##teamcity[testFinished name='#3001: Enum-based bitfields can be captured' duration="{duration}"]
|
||||
##teamcity[testStarted name='#748 - captures with unexpected exceptions']
|
||||
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with message:|n "expected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|ninside REQUIRE_NOTHROW|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
@@ -225,6 +227,14 @@
|
||||
##teamcity[testFinished name='Arbitrary predicate matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertion macros support bit operators and bool conversions']
|
||||
##teamcity[testFinished name='Assertion macros support bit operators and bool conversions' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions can be nested - CHECK']
|
||||
##teamcity[testIgnored name='Assertions can be nested - CHECK' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexpression failed|n REQUIRE( i > 10 )|nwith expansion:|n 2 > 10|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='Assertions can be nested - CHECK' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n CHECK( foo( 2 ) == 2 )|nwith expansion:|n foo( 2 ) == 2|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='Assertions can be nested - CHECK' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions can be nested - REQUIRE']
|
||||
##teamcity[testIgnored name='Assertions can be nested - REQUIRE' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexpression failed|n REQUIRE( i > 10 )|nwith expansion:|n 2 > 10|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='Assertions can be nested - REQUIRE' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n REQUIRE( foo( 2 ) == 2 )|nwith expansion:|n foo( 2 ) == 2|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='Assertions can be nested - REQUIRE' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions then sections']
|
||||
##teamcity[testFinished name='Assertions then sections' duration="{duration}"]
|
||||
##teamcity[testStarted name='Basic use of the Contains range matcher']
|
||||
@@ -275,6 +285,8 @@
|
||||
##teamcity[testFinished name='Combining templated matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Commas in various macros are allowed']
|
||||
##teamcity[testFinished name='Commas in various macros are allowed' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparing (and stringifying) volatile pointers works']
|
||||
##teamcity[testFinished name='Comparing (and stringifying) volatile pointers works' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparing function pointers']
|
||||
##teamcity[testFinished name='Comparing function pointers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparison ops']
|
||||
@@ -366,6 +378,8 @@
|
||||
##teamcity[testFinished name='Exception message can be matched' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exception messages can be tested for']
|
||||
##teamcity[testFinished name='Exception messages can be tested for' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exception thrown inside stringify does not fail the test']
|
||||
##teamcity[testFinished name='Exception thrown inside stringify does not fail the test' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exceptions matchers']
|
||||
##teamcity[testFinished name='Exceptions matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Expected exceptions that don|'t throw or unexpected exceptions fail the test']
|
||||
@@ -376,6 +390,10 @@
|
||||
##teamcity[testStarted name='FAIL aborts the test']
|
||||
##teamcity[testFailed name='FAIL aborts the test' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexplicit failure with message:|n "This is a failure"']
|
||||
##teamcity[testFinished name='FAIL aborts the test' duration="{duration}"]
|
||||
##teamcity[testStarted name='FAIL can be nested in assertion']
|
||||
##teamcity[testIgnored name='FAIL can be nested in assertion' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexplicit failure with message:|n "Throw a Catch::TestFailureException"- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='FAIL can be nested in assertion' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n CHECK_NOTHROW( do_fail() )|nwith expansion:|n do_fail()|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='FAIL can be nested in assertion' duration="{duration}"]
|
||||
##teamcity[testStarted name='FAIL does not require an argument']
|
||||
##teamcity[testFailed name='FAIL does not require an argument' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexplicit failure']
|
||||
##teamcity[testFinished name='FAIL does not require an argument' duration="{duration}"]
|
||||
@@ -985,6 +1003,8 @@ loose text artifact
|
||||
##teamcity[testFinished name='stringify( vectors<has_operator> )' duration="{duration}"]
|
||||
##teamcity[testStarted name='strlen3']
|
||||
##teamcity[testFinished name='strlen3' duration="{duration}"]
|
||||
##teamcity[testStarted name='system_clock timepoint with non-default duration']
|
||||
##teamcity[testFinished name='system_clock timepoint with non-default duration' duration="{duration}"]
|
||||
##teamcity[testStarted name='tables']
|
||||
##teamcity[testFinished name='tables' duration="{duration}"]
|
||||
##teamcity[testStarted name='tags with dots in later positions are not parsed as hidden']
|
||||
|
@@ -55,6 +55,8 @@
|
||||
##teamcity[testStarted name='#2615 - Throwing in constructor generator fails test case but does not abort']
|
||||
##teamcity[testIgnored name='#2615 - Throwing in constructor generator fails test case but does not abort' message='Generators.tests.cpp:<line number>|n...............................................................................|n|nGenerators.tests.cpp:<line number>|nunexpected exception with message:|n "failure to init"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='#2615 - Throwing in constructor generator fails test case but does not abort' duration="{duration}"]
|
||||
##teamcity[testStarted name='#3001: Enum-based bitfields can be captured']
|
||||
##teamcity[testFinished name='#3001: Enum-based bitfields can be captured' duration="{duration}"]
|
||||
##teamcity[testStarted name='#748 - captures with unexpected exceptions']
|
||||
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with message:|n "expected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|ninside REQUIRE_NOTHROW|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
@@ -225,6 +227,14 @@
|
||||
##teamcity[testFinished name='Arbitrary predicate matcher' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertion macros support bit operators and bool conversions']
|
||||
##teamcity[testFinished name='Assertion macros support bit operators and bool conversions' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions can be nested - CHECK']
|
||||
##teamcity[testIgnored name='Assertions can be nested - CHECK' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexpression failed|n REQUIRE( i > 10 )|nwith expansion:|n 2 > 10|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='Assertions can be nested - CHECK' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n CHECK( foo( 2 ) == 2 )|nwith expansion:|n foo( 2 ) == 2|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='Assertions can be nested - CHECK' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions can be nested - REQUIRE']
|
||||
##teamcity[testIgnored name='Assertions can be nested - REQUIRE' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexpression failed|n REQUIRE( i > 10 )|nwith expansion:|n 2 > 10|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='Assertions can be nested - REQUIRE' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n REQUIRE( foo( 2 ) == 2 )|nwith expansion:|n foo( 2 ) == 2|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='Assertions can be nested - REQUIRE' duration="{duration}"]
|
||||
##teamcity[testStarted name='Assertions then sections']
|
||||
##teamcity[testFinished name='Assertions then sections' duration="{duration}"]
|
||||
##teamcity[testStarted name='Basic use of the Contains range matcher']
|
||||
@@ -275,6 +285,8 @@
|
||||
##teamcity[testFinished name='Combining templated matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Commas in various macros are allowed']
|
||||
##teamcity[testFinished name='Commas in various macros are allowed' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparing (and stringifying) volatile pointers works']
|
||||
##teamcity[testFinished name='Comparing (and stringifying) volatile pointers works' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparing function pointers']
|
||||
##teamcity[testFinished name='Comparing function pointers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Comparison ops']
|
||||
@@ -366,6 +378,8 @@
|
||||
##teamcity[testFinished name='Exception message can be matched' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exception messages can be tested for']
|
||||
##teamcity[testFinished name='Exception messages can be tested for' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exception thrown inside stringify does not fail the test']
|
||||
##teamcity[testFinished name='Exception thrown inside stringify does not fail the test' duration="{duration}"]
|
||||
##teamcity[testStarted name='Exceptions matchers']
|
||||
##teamcity[testFinished name='Exceptions matchers' duration="{duration}"]
|
||||
##teamcity[testStarted name='Expected exceptions that don|'t throw or unexpected exceptions fail the test']
|
||||
@@ -376,6 +390,10 @@
|
||||
##teamcity[testStarted name='FAIL aborts the test']
|
||||
##teamcity[testFailed name='FAIL aborts the test' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexplicit failure with message:|n "This is a failure"']
|
||||
##teamcity[testFinished name='FAIL aborts the test' duration="{duration}"]
|
||||
##teamcity[testStarted name='FAIL can be nested in assertion']
|
||||
##teamcity[testIgnored name='FAIL can be nested in assertion' message='AssertionHandler.tests.cpp:<line number>|n...............................................................................|n|nAssertionHandler.tests.cpp:<line number>|nexplicit failure with message:|n "Throw a Catch::TestFailureException"- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testIgnored name='FAIL can be nested in assertion' message='AssertionHandler.tests.cpp:<line number>|nunexpected exception with message:|n "{ nested assertion failed }"|n CHECK_NOTHROW( do_fail() )|nwith expansion:|n do_fail()|n- failure ignore as test marked as |'ok to fail|'|n']
|
||||
##teamcity[testFinished name='FAIL can be nested in assertion' duration="{duration}"]
|
||||
##teamcity[testStarted name='FAIL does not require an argument']
|
||||
##teamcity[testFailed name='FAIL does not require an argument' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexplicit failure']
|
||||
##teamcity[testFinished name='FAIL does not require an argument' duration="{duration}"]
|
||||
@@ -984,6 +1002,8 @@
|
||||
##teamcity[testFinished name='stringify( vectors<has_operator> )' duration="{duration}"]
|
||||
##teamcity[testStarted name='strlen3']
|
||||
##teamcity[testFinished name='strlen3' duration="{duration}"]
|
||||
##teamcity[testStarted name='system_clock timepoint with non-default duration']
|
||||
##teamcity[testFinished name='system_clock timepoint with non-default duration' duration="{duration}"]
|
||||
##teamcity[testStarted name='tables']
|
||||
##teamcity[testFinished name='tables' duration="{duration}"]
|
||||
##teamcity[testStarted name='tags with dots in later positions are not parsed as hidden']
|
||||
|
@@ -681,6 +681,25 @@ Nor would this
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="#3001: Enum-based bitfields can be captured" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Original>
|
||||
bf.e == 1
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Original>
|
||||
1 == bf.e
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="#748 - captures with unexpected exceptions" tags="[!shouldfail][!throws][.][failing]" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
<Section name="outside assertions" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
<Expression success="false" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
@@ -2716,6 +2735,58 @@ Approx( 1.23399996757507324 )
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions can be nested - CHECK" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
i > 10
|
||||
</Original>
|
||||
<Expanded>
|
||||
2 > 10
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="false" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
foo( 2 ) == 2
|
||||
</Original>
|
||||
<Expanded>
|
||||
foo( 2 ) == 2
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
true
|
||||
</Original>
|
||||
<Expanded>
|
||||
true
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions can be nested - REQUIRE" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
i > 10
|
||||
</Original>
|
||||
<Expanded>
|
||||
2 > 10
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
foo( 2 ) == 2
|
||||
</Original>
|
||||
<Expanded>
|
||||
foo( 2 ) == 2
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions then sections" tags="[Tricky]" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Original>
|
||||
@@ -3810,6 +3881,65 @@ C
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Comparing (and stringifying) volatile pointers works" tags="[volatile]" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr == ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 == 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr != ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 != 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr < ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 < 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr <= ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 <= 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr > ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 > 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr >= ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 >= 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Comparing function pointers" tags="[function pointer][Tricky]" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Original>
|
||||
@@ -5050,6 +5180,19 @@ Approx( 1.30000000000000004 )
|
||||
</Section>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Exception thrown inside stringify does not fail the test" tags="[toString]" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
|
||||
<Original>
|
||||
tos == tos
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Exceptions matchers" tags="[!throws][exceptions][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
@@ -5124,6 +5267,23 @@ Approx( 1.30000000000000004 )
|
||||
</Failure>
|
||||
<OverallResult success="false" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="FAIL can be nested in assertion" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Failure filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
Throw a Catch::TestFailureException
|
||||
</Failure>
|
||||
<Expression success="false" type="CHECK_NOTHROW" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
do_fail()
|
||||
</Original>
|
||||
<Expanded>
|
||||
do_fail()
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="FAIL does not require an argument" tags="[.][failing][messages]" filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
|
||||
<Failure filename="tests/<exe-name>/UsageTests/Message.tests.cpp" />
|
||||
<OverallResult success="false" skips="0"/>
|
||||
@@ -6756,6 +6916,44 @@ Approx( 1.30000000000000004 )
|
||||
</Section>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<Section name="Filter generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Section name="Out-of-line predicates are copied into the generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.get() == 1
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.next()
|
||||
</Original>
|
||||
<Expanded>
|
||||
true
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.get() == 3
|
||||
</Original>
|
||||
<Expanded>
|
||||
3 == 3
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
!(gen.next())
|
||||
</Original>
|
||||
<Expanded>
|
||||
!false
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<Section name="Take generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Section name="Take less" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
@@ -21236,6 +21434,19 @@ Approx( -1.95996398454005449 )
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="system_clock timepoint with non-default duration" tags="[chrono][toString]" filename="tests/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
|
||||
<Original>
|
||||
tp1 == tp2
|
||||
</Original>
|
||||
<Expanded>
|
||||
{iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="tables" tags="[generators]" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
|
||||
<Original>
|
||||
@@ -22113,6 +22324,6 @@ Approx( -1.95996398454005449 )
|
||||
</Section>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="2089" failures="157" expectedFailures="35" skips="12"/>
|
||||
<OverallResultsCases successes="313" failures="95" expectedFailures="14" skips="6"/>
|
||||
<OverallResults successes="2105" failures="157" expectedFailures="41" skips="12"/>
|
||||
<OverallResultsCases successes="317" failures="95" expectedFailures="17" skips="6"/>
|
||||
</Catch2TestRun>
|
||||
|
@@ -681,6 +681,25 @@ Nor would this
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="#3001: Enum-based bitfields can be captured" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Original>
|
||||
bf.e == 1
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Compilation.tests.cpp" >
|
||||
<Original>
|
||||
1 == bf.e
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="#748 - captures with unexpected exceptions" tags="[!shouldfail][!throws][.][failing]" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
<Section name="outside assertions" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
<Expression success="false" filename="tests/<exe-name>/UsageTests/Exception.tests.cpp" >
|
||||
@@ -2716,6 +2735,58 @@ Approx( 1.23399996757507324 )
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions can be nested - CHECK" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
i > 10
|
||||
</Original>
|
||||
<Expanded>
|
||||
2 > 10
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="false" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
foo( 2 ) == 2
|
||||
</Original>
|
||||
<Expanded>
|
||||
foo( 2 ) == 2
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
true
|
||||
</Original>
|
||||
<Expanded>
|
||||
true
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions can be nested - REQUIRE" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
i > 10
|
||||
</Original>
|
||||
<Expanded>
|
||||
2 > 10
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="false" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
foo( 2 ) == 2
|
||||
</Original>
|
||||
<Expanded>
|
||||
foo( 2 ) == 2
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Assertions then sections" tags="[Tricky]" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Original>
|
||||
@@ -3810,6 +3881,65 @@ C
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Comparing (and stringifying) volatile pointers works" tags="[volatile]" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr == ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 == 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr != ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 != 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr < ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 < 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr <= ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 <= 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
!(ptr > ptr)
|
||||
</Original>
|
||||
<Expanded>
|
||||
!(0 > 0)
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Misc.tests.cpp" >
|
||||
<Original>
|
||||
ptr >= ptr
|
||||
</Original>
|
||||
<Expanded>
|
||||
0 >= 0
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Comparing function pointers" tags="[function pointer][Tricky]" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Tricky.tests.cpp" >
|
||||
<Original>
|
||||
@@ -5050,6 +5180,19 @@ Approx( 1.30000000000000004 )
|
||||
</Section>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Exception thrown inside stringify does not fail the test" tags="[toString]" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
|
||||
<Original>
|
||||
tos == tos
|
||||
</Original>
|
||||
<Expanded>
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
==
|
||||
{ stringification failed with an exception: "Invalid" }
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="Exceptions matchers" tags="[!throws][exceptions][matchers]" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE_THROWS_MATCHES" filename="tests/<exe-name>/UsageTests/Matchers.tests.cpp" >
|
||||
<Original>
|
||||
@@ -5124,6 +5267,23 @@ Approx( 1.30000000000000004 )
|
||||
</Failure>
|
||||
<OverallResult success="false" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="FAIL can be nested in assertion" tags="[!shouldfail][assertions]" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Failure filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
Throw a Catch::TestFailureException
|
||||
</Failure>
|
||||
<Expression success="false" type="CHECK_NOTHROW" filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
<Original>
|
||||
do_fail()
|
||||
</Original>
|
||||
<Expanded>
|
||||
do_fail()
|
||||
</Expanded>
|
||||
<Exception filename="tests/<exe-name>/IntrospectiveTests/AssertionHandler.tests.cpp" >
|
||||
{ nested assertion failed }
|
||||
</Exception>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="FAIL does not require an argument" tags="[.][failing][messages]" filename="tests/<exe-name>/UsageTests/Message.tests.cpp" >
|
||||
<Failure filename="tests/<exe-name>/UsageTests/Message.tests.cpp" />
|
||||
<OverallResult success="false" skips="0"/>
|
||||
@@ -6756,6 +6916,44 @@ Approx( 1.30000000000000004 )
|
||||
</Section>
|
||||
<OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<Section name="Filter generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Section name="Out-of-line predicates are copied into the generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.get() == 1
|
||||
</Original>
|
||||
<Expanded>
|
||||
1 == 1
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.next()
|
||||
</Original>
|
||||
<Expanded>
|
||||
true
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
gen.get() == 3
|
||||
</Original>
|
||||
<Expanded>
|
||||
3 == 3
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<Expression success="true" type="REQUIRE_FALSE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Original>
|
||||
!(gen.next())
|
||||
</Original>
|
||||
<Expanded>
|
||||
!false
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<OverallResults successes="4" failures="0" expectedFailures="0" skipped="false"/>
|
||||
</Section>
|
||||
<Section name="Take generator" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Section name="Take less" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/GeneratorsImpl.tests.cpp" >
|
||||
@@ -21235,6 +21433,19 @@ Approx( -1.95996398454005449 )
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="system_clock timepoint with non-default duration" tags="[chrono][toString]" filename="tests/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
|
||||
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/ToStringChrono.tests.cpp" >
|
||||
<Original>
|
||||
tp1 == tp2
|
||||
</Original>
|
||||
<Expanded>
|
||||
{iso8601-timestamp}
|
||||
==
|
||||
{iso8601-timestamp}
|
||||
</Expanded>
|
||||
</Expression>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<TestCase name="tables" tags="[generators]" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
|
||||
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/Generators.tests.cpp" >
|
||||
<Original>
|
||||
@@ -22112,6 +22323,6 @@ Approx( -1.95996398454005449 )
|
||||
</Section>
|
||||
<OverallResult success="true" skips="0"/>
|
||||
</TestCase>
|
||||
<OverallResults successes="2089" failures="157" expectedFailures="35" skips="12"/>
|
||||
<OverallResultsCases successes="313" failures="95" expectedFailures="14" skips="6"/>
|
||||
<OverallResults successes="2105" failures="157" expectedFailures="41" skips="12"/>
|
||||
<OverallResultsCases successes="317" failures="95" expectedFailures="17" skips="6"/>
|
||||
</Catch2TestRun>
|
||||
|
@@ -15,3 +15,28 @@ TEST_CASE( "Incomplete AssertionHandler", "[assertion-handler][!shouldfail]" ) {
|
||||
"Dummy",
|
||||
Catch::ResultDisposition::Normal );
|
||||
}
|
||||
|
||||
|
||||
static int foo( int i ) {
|
||||
REQUIRE( i > 10 );
|
||||
return 42;
|
||||
}
|
||||
|
||||
TEST_CASE( "Assertions can be nested - CHECK", "[assertions][!shouldfail]" ) {
|
||||
CHECK( foo( 2 ) == 2 );
|
||||
// We should hit this, because CHECK continues on failure
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assertions can be nested - REQUIRE", "[assertions][!shouldfail]" ) {
|
||||
REQUIRE( foo( 2 ) == 2 );
|
||||
// We should not hit this, because REQUIRE does not continue on failure
|
||||
CHECK( true );
|
||||
}
|
||||
|
||||
static void do_fail() { FAIL( "Throw a Catch::TestFailureException" ); }
|
||||
|
||||
TEST_CASE( "FAIL can be nested in assertion", "[assertions][!shouldfail]" ) {
|
||||
// Fails, but the error message makes sense.
|
||||
CHECK_NOTHROW( do_fail() );
|
||||
}
|
||||
|
@@ -85,6 +85,19 @@ TEST_CASE("Generators internals", "[generators][internals]") {
|
||||
filter([](int) { return false; }, values({ 1, 2, 3 })),
|
||||
Catch::GeneratorException);
|
||||
}
|
||||
|
||||
// Non-trivial usage
|
||||
SECTION("Out-of-line predicates are copied into the generator") {
|
||||
auto evilNumber = Catch::Detail::make_unique<int>(2);
|
||||
auto gen = [&]{
|
||||
const auto predicate = [&](int i) { return i != *evilNumber; };
|
||||
return filter(predicate, values({ 2, 1, 2, 3, 2, 2 }));
|
||||
}();
|
||||
REQUIRE(gen.get() == 1);
|
||||
REQUIRE(gen.next());
|
||||
REQUIRE(gen.get() == 3);
|
||||
REQUIRE_FALSE(gen.next());
|
||||
}
|
||||
}
|
||||
SECTION("Take generator") {
|
||||
SECTION("Take less") {
|
||||
|
@@ -7,6 +7,8 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_jsonwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
@@ -17,7 +19,6 @@ namespace {
|
||||
static std::ostream& operator<<( std::ostream& os, Custom const& ) {
|
||||
return os << "custom";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE( "JsonWriter", "[JSON][JsonWriter]" ) {
|
||||
|
||||
@@ -150,3 +151,28 @@ TEST_CASE( "JsonWriter escapes characters in strings properly", "[JsonWriter]" )
|
||||
REQUIRE( sstream.str() == "\"\\\\/\\t\\r\\n\"" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "JsonWriter benchmarks", "[JsonWriter][!benchmark]" ) {
|
||||
const auto input_length = GENERATE( as<size_t>{}, 10, 100, 10'000 );
|
||||
std::string test_input( input_length, 'a' );
|
||||
BENCHMARK_ADVANCED( "write string, no-escaping, len=" +
|
||||
std::to_string( input_length ) )(
|
||||
Catch::Benchmark::Chronometer meter ) {
|
||||
std::stringstream sstream;
|
||||
meter.measure( [&]( int ) {
|
||||
Catch::JsonValueWriter( sstream ).write( test_input );
|
||||
} );
|
||||
};
|
||||
|
||||
std::string escape_input( input_length, '\b' );
|
||||
BENCHMARK_ADVANCED( "write string, all-escaped, len=" +
|
||||
std::to_string( input_length ) )(
|
||||
Catch::Benchmark::Chronometer meter ) {
|
||||
std::stringstream sstream;
|
||||
meter.measure( [&]( int ) {
|
||||
Catch::JsonValueWriter( sstream ).write( escape_input );
|
||||
} );
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -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>
|
||||
|
||||
@@ -118,3 +120,47 @@ TEST_CASE( "#2944 - Stringifying dates before 1970 should not crash", "[.approva
|
||||
Equals( "gmtime from provided timepoint has failed. This "
|
||||
"happens e.g. with pre-1970 dates using Microsoft libc" ) );
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ThrowsOnStringification {
|
||||
friend bool operator==( ThrowsOnStringification,
|
||||
ThrowsOnStringification ) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct Catch::StringMaker<ThrowsOnStringification> {
|
||||
static std::string convert(ThrowsOnStringification) {
|
||||
throw std::runtime_error( "Invalid" );
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE( "Exception thrown inside stringify does not fail the test", "[toString]" ) {
|
||||
ThrowsOnStringification tos;
|
||||
CHECK( tos == tos );
|
||||
}
|
||||
|
||||
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 );
|
||||
};
|
||||
}
|
||||
|
@@ -7,13 +7,16 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
|
||||
static std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) {
|
||||
Catch::ReusableStringStream oss;
|
||||
oss << Catch::XmlEncode( str, forWhat );
|
||||
@@ -181,3 +184,20 @@ TEST_CASE("XmlWriter escapes attributes properly", "[XML][XmlWriter][approvals]"
|
||||
REQUIRE_THAT(stream.str(),
|
||||
ContainsSubstring(R"(some-attribute="Special chars need escaping: < > ' " &")"));
|
||||
}
|
||||
|
||||
TEST_CASE( "XmlWriter benchmarks", "[XML][XmlWriter][!benchmark]" ) {
|
||||
const auto input_length = GENERATE( as<size_t>{}, 10, 100, 10'000 );
|
||||
std::string test_input( input_length, 'a' );
|
||||
BENCHMARK_ADVANCED( "write string, no-escaping, len=" +
|
||||
std::to_string( input_length ) ) {
|
||||
return encode( test_input );
|
||||
};
|
||||
|
||||
std::string escape_input( input_length, '\b' );
|
||||
BENCHMARK_ADVANCED( "write string, all-escaped, len=" +
|
||||
std::to_string( input_length ) ) {
|
||||
return encode( escape_input );
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -144,6 +144,23 @@ TEST_CASE("#1027: Bitfields can be captured") {
|
||||
REQUIRE(0 == y.v);
|
||||
}
|
||||
|
||||
TEST_CASE( "#3001: Enum-based bitfields can be captured" ) {
|
||||
enum E {
|
||||
ZERO = 0,
|
||||
ONE = 1,
|
||||
TWO = 2,
|
||||
};
|
||||
|
||||
struct BF {
|
||||
E e : 2;
|
||||
};
|
||||
|
||||
BF bf{};
|
||||
bf.e = ONE;
|
||||
REQUIRE( bf.e == 1 );
|
||||
REQUIRE( 1 == bf.e );
|
||||
}
|
||||
|
||||
// Comparison operators can return non-booleans.
|
||||
// This is unusual, but should be supported.
|
||||
TEST_CASE("#1147") {
|
||||
|
@@ -562,3 +562,15 @@ TEST_CASE("Validate SEH behavior - no crash for stack unwinding", "[approvals][!
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
TEST_CASE( "Comparing (and stringifying) volatile pointers works",
|
||||
"[volatile]" ) {
|
||||
volatile int* ptr = nullptr;
|
||||
REQUIRE_FALSE( ptr );
|
||||
REQUIRE( ptr == ptr );
|
||||
REQUIRE_FALSE( ptr != ptr );
|
||||
REQUIRE_FALSE( ptr < ptr );
|
||||
REQUIRE( ptr <= ptr );
|
||||
REQUIRE_FALSE( ptr > ptr );
|
||||
REQUIRE( ptr >= ptr );
|
||||
}
|
||||
|
@@ -49,3 +49,9 @@ TEST_CASE("Stringifying std::chrono::time_point<Clock>", "[toString][chrono][!no
|
||||
auto later2 = now2 + std::chrono::minutes(2);
|
||||
REQUIRE(now2 != later2);
|
||||
}
|
||||
|
||||
TEST_CASE( "system_clock timepoint with non-default duration", "[toString][chrono]" ) {
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>
|
||||
tp1, tp2;
|
||||
CHECK( tp1 == tp2 );
|
||||
}
|
||||
|
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