Compare commits

...

36 Commits

Author SHA1 Message Date
Martin Hořeňovský 191fa38c9b v3.15.2 2026-07-07 20:44:33 +02:00
Martin Hořeňovský dd94b9a780 Fix --warn InfiniteGenerators firing even if the generator was filtered 2026-07-07 14:09:11 +02:00
Martin Hořeňovský 9f7c9f6872 Add extra test binary & test for CATCH_CONFIG_FAST_COMPILE
Closes #3100
2026-07-06 11:03:47 +02:00
Martin Hořeňovský 919385f704 Fix some test binaries in ExtraTests not having warnings enabled 2026-07-06 10:22:55 +02:00
Martin Hořeňovský 15d52830ee Fix -Wunused-parameter warning with exceptions disabled
Closes #3114
2026-07-05 12:08:06 +02:00
Martin Hořeňovský 9ec44dd62b catch_discover_tests uses tempfile to retrieve JSON from the binary
This allows it to deal with badly behaved code, where 3rd party
dependencies write into stdout during global construction.

Closes #3162
Closes #3166
2026-07-04 16:36:05 +02:00
Martin Hořeňovský 675f9eaeb1 Add LLM policy to contributing.md 2026-06-14 20:25:57 +02:00
Martin Hořeňovský bcfb10e498 v3.15.1 2026-06-14 10:57:30 +02:00
Dominic Koepke b7e0310fbe fix: move struct TestName of INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2 into the anonymous namespace 2026-06-09 19:17:14 +02:00
Dominic Koepke 6d4ea62200 fix: move struct TestName of INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2 into the anonymous namespace 2026-06-09 19:17:14 +02:00
offa 195231c59a docs: Set missing syntax language 2026-05-31 17:17:46 +02:00
offa 3a865e8c0f docs: Enable syntax coloring for code example 2026-05-31 17:17:46 +02:00
Dirk Müller 69e0473f6e Avoid a potential underflow when iterating over invalid inputs
The forward iteration logic already bounds-check for m_it != m_string->end(),
do the same for the backward iteration. The issue with the assert is
that the assert() might not be compiled in, and it is happening after
the dereference, so it was too late.
2026-05-14 10:58:09 +02:00
Martin Hořeňovský 6ee0826dca v3.15.0 2026-05-12 13:16:46 +02:00
Martin Hořeňovský 47ea57d74f Constexpr matching support in the range equals matchers 2026-05-12 11:05:33 +02:00
Martin Hořeňovský d838f88b9c Constexpr matching support in generic Contains matchers 2026-05-12 11:05:31 +02:00
Martin Hořeňovský c267b6eb4d Constexpr matching support in the quantifier matchers 2026-05-12 11:05:31 +02:00
Martin Hořeňovský 3cdae5faf0 Constexpr matching support in IsEmpty and SizeIs matchers 2026-05-12 11:05:29 +02:00
Martin Hořeňovský 651247c7f4 Support for constexpr matchers in C++20 (P0784)
To make this all work, I had to remove the stringification cache
from matchers. In theory, this can cause performance penalty in
cases where single matcher instance is stringified multiple times,
but in practice this does not happen much, and the difference is
surprisingly small anyway, because the performance of stringification
is already horrible and full of allocating strings just to throw
them away.

The matcher combinators need P2738 from C++26 to be `constexpr`.

Closes #3091
2026-05-12 11:05:02 +02:00
Martin Hořeňovský 15b9393f0f Don't check if __cplusplus is defined 2026-05-10 20:48:58 +02:00
Martin Hořeňovský a18badd10f Workaround P3168 causing ambiguous overload issues with StringMaker
P3168 turned `std::optional` into a range type, so the partial specialization
of `StringMaker` for `std::optional<T>` conflicted with the partial
specialization for range types. Ideally we will fix this in the future
to support user-provided partial specializations for range-like types,
but for now we just disable the partial specialization for `std::optional<T>`
if P3168 is implemented.
2026-05-09 22:24:12 +02:00
Martin Hořeňovský 54af40652a Add more runtime benchmark recipe TODOs 2026-05-07 21:13:11 +02:00
Martin Hořeňovský 5f47160bb2 Add benchmark for catch_test_macros.hpp inclusion 2026-05-07 20:27:09 +02:00
Martin Hořeňovský e83528c6eb Add readme to benchmarks/ with some simple examples 2026-05-07 10:43:24 +02:00
Martin Hořeňovský fd31a62547 Add benchmark for REQUIRE_THAT into runtime_assertion_benches.cpp
I also changed the names of other benchmark `TEST_CASE`s so that
they are easier to use.
2026-05-07 10:18:21 +02:00
Martin Hořeňovský 4df8fee92d IConfig derives from NonCopyable privately 2026-05-07 10:12:28 +02:00
Ole Schmidt 300c5d3eed Fix Wconversion warning in catch_reporter_helpers.cpp 2026-05-06 09:58:01 +02:00
Martin Hořeňovský 11a96e186a Cleanups from static analysis 2026-04-24 11:21:04 +02:00
Martin Hořeňovský 10f62484bf AssertionHandler uses RunContext directly to avoid virtual dispatch 2026-04-13 22:56:55 +02:00
Martin Hořeňovský be2dfb45cc Update Doxyfile 2026-04-08 15:06:36 +02:00
Martin Hořeňovský 47200ddbee Rework internals of CATCH_REGISTER_ENUM
The old internals reached into the global hub to stash the allocation(s)
for enum value -> string value there, then kept around a potentially
invalid (in case the hub was cleaned up) reference into it, going through
whole bunch of virtual dispatch in the process.

The new internals just store the data in a static variable inside the
`StringMaker` specialization. This avoids potential lifetime issues,
avoids all virtual dispatch and (almost) reduces the include bloat in
the main header path.

The reason for (almost) there is that for full include correctness,
`EnumInfo` needs `<utility>` include for `std::pair`. However, this brings
in things like `std::relops`, because the std headers in C++ are dumb.
As this was not included before, and instead we relied on `std::pair`
existing in an internal stdlib header that we transitively included, the
full include size ends up bigger than before.
2026-04-08 12:57:09 +02:00
Martin Hořeňovský e51dcdcc59 Mark TestInvoker{AsMethod,Fixture} as final 2026-04-07 14:36:08 +02:00
Martin Hořeňovský 77eae8bd2a Turn IResultCapture::lastAssertionPassed into a free function
The thread-safety changes in assertions & messages turned whether
the last assertion passed or failed into thread-local state,
instead of being member of the `RunContext`. However, this change
was not reflected in the API `CHECKED_IF`/`CHECKED_ELSE` used,
which in turn required `catch_test_macro_impl.hpp` to include
`catch_interfaces_capture.hpp` for it.

Thanks to the combination of this commit and the previous similar
commit for the message stack handling, the main include path does
not need to include `catch_interfaces_capture.hpp` anymore.
2026-04-07 14:33:39 +02:00
Martin Hořeňovský 3ab0d7cef3 Turn IResultCapture::{push,pop}*Message into free functions
The thread-safety changes in assertions & messages turned the message
stacks into thread-local state, instead of it being member of `RunContext`.
The relevant {push,pop}(Un)ScopedMessage functions were turned from member
functions into static functions, but this left `catch_message.hpp` with
dependency on `IResultCapture`'s definition for the functions, and thus
it still had to include `catch_interfaces_capture.hpp`.

With this change, `catch_message.hpp` no longer needs
`catch_interfaces_capture.hpp`.
2026-04-07 14:28:11 +02:00
Martin Hořeňovský e83218c2df Move all use of IResultCapture in AssertionHandler into the cpp file
This has two advantages

1) Removing the include of `catch_interfaces_capture.hpp` from the
   header and potentially allowing further pruning later.
2) Providing small-but-measurable 1-2% speedup for assertions.
2026-04-07 09:32:07 +02:00
Martin Hořeňovský 548e14a8c8 Mark some extra classes final 2026-04-07 00:13:17 +02:00
108 changed files with 2395 additions and 1281 deletions
+3
View File
@@ -32,6 +32,7 @@ Checks: >-
-modernize-deprecated-headers,
,# There's a lot of these and most of them are probably not useful,
-modernize-pass-by-value,
-modernize-use-string-view, # We support C++14,
performance-*,
performance-enum-size,
@@ -58,6 +59,8 @@ Checks: >-
-readability-uppercase-literal-suffix,
-readability-use-anyofallof,
-readability-avoid-return-with-void-value,
,# We prefer if defined(FOO) form because it is easier to extend later,
-readability-use-concise-preprocessor-directives,
,# time hogs,
-bugprone-throw-keyword-missing,
+1 -1
View File
@@ -35,7 +35,7 @@ if(CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
VERSION 3.14.0 # CML version placeholder, don't delete
VERSION 3.15.2 # CML version placeholder, don't delete
LANGUAGES CXX
HOMEPAGE_URL "https://github.com/catchorg/Catch2"
DESCRIPTION "A modern, C++-native, unit test framework."
+432 -266
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -9,8 +9,13 @@ add_executable(AssertionsSlowPath
assertion_listener.cpp
)
add_executable(EmptyExecutable
only_include.cpp
)
target_link_libraries(AssertionsFastPath PRIVATE Catch2::Catch2WithMain)
target_link_libraries(AssertionsSlowPath PRIVATE Catch2::Catch2WithMain)
target_link_libraries(EmptyExecutable PRIVATE Catch2::Catch2WithMain)
list(APPEND CATCH_TEST_TARGETS AssertionsFastPath AssertionsSlowPath)
list(APPEND CATCH_TEST_TARGETS AssertionsFastPath AssertionsSlowPath EmptyExecutable)
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
+16
View File
@@ -0,0 +1,16 @@
// 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
* "empty" include of catch_test_macros.hpp
*
* This file does only one thing: include `catch2/catch_test_macros.hpp`,
* so that we can measure the compilation cost of the header.
*/
#include <catch2/catch_test_macros.hpp>
+81
View File
@@ -0,0 +1,81 @@
<a id="top"></a>
# Benchmarks of Catch2
This folder holds benchmarks for Catch2. It should not be built for the
small(er) test sets, as it is only relevant for running (mainly runtime)
benchmarks.
Below you will find some practical examples using
[hyperfine](https://github.com/sharkdp/hyperfine) to determine the
performance of various scenarios. They assume two parallel checkouts, one
named `Catch2-old` and the other `Catch2-new`. You will need to change
the paths to work on your own machine.
## Runtime benchmarks
The runtime benchmarks currently consist of few different `TEST_CASE`s,
each with a simple loop over different assertion type. They are compiled
into two binaries, one for assertion slow path and one for assertion fast
path.
### Assumptions and notes about real-world usage
The basic assertion macro, `REQUIRE` (and `CHECK`) is the most common one,
by far. Thus, it is the most important one to run quickly. It is probably
followed by the matcher macro, `REQUIRE_THAT`.
The most common result of an assertion is that it passes. Even if it is
stringified and reported, that is most likely due to some listener/reporter
that wants the string representation, not because it failed.
The performance of both Debug and Release builds are important; users
will run tests in both. LTO runtime performance is not too important,
but compile time perf is.
### Examples
**Compare performance of `REQUIRE` in slow path, debug build**
```text
hyperfine --warmup 2 --shell none --parameter-list version old,new '/home/xarn/benches/Catch2-{version}/build-debug/benchmarks/AssertionsSlowPath -o /dev/null "REQUIRE"'
```
**Compare performance of `REQUIRE_THAT` in fast path, release build**
```text
hyperfine --warmup 2 --shell none --parameter-list version old,new '/home/xarn/benches/Catch2-{version}/build-release/benchmarks/AssertionsFastPath -o /dev/null "REQUIRE_THAT"'
```
**Compare performance of `REQUIRE` with stringification enabled, release build**
```text
hyperfine --warmup 2 --shell none --parameter-list version old,new '/home/xarn/benches/Catch2-{version}/build-release/benchmarks/AssertionsFastPath -s -o /dev/null "REQUIRE"'
```
_Note that we redirect the output to `/dev/null` to reduce the overhead of the actual output printing, to see just the impact of stringification._
TODO:
* Start empty binary (set up cost base)
* Start binary with X (100/1k/10k) tests (test registration cost)
* Section tracking
## Compilation benchmarks
As tests are often iterated upon and relinked, the compilation cost of
Catch2 is also important.
### Examples
**Compare overhead of including `catch_test_macros.hpp`**
```text
hyperfine --warmup 2 --shell none --parameter-list version old,new '/usr/bin/c++ -I/home/xarn/benches/Catch2-{version}/src/catch2/.. -I/home/xarn/benches/Catch2-{version}/build-debug/generated-includes -g -o /dev/null -c /home/xarn/benches/Catch2-{version}/benchmarks/only_include.cpp'
```
**Compare build time of Catch2's `SelfTest` test suite, Debug build**
```text
hyperfine --warmup 2 --parameter-list version old,vas --prepare 'find ~/benches/Catch2-{version}/tests/SelfTest -type f -name "*.cpp" -exec touch {} +' 'ninja -j 1 -C ~/benches/Catch2-{version}/build-debug'
```
TODO:
* Link-only recipe
+36 -9
View File
@@ -7,21 +7,48 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>
TEST_CASE("Simple REQUIRE - 10M") {
for (size_t i = 0; i < 10'000'000; ++i) {
REQUIRE(true);
namespace {
class MatchAllMatcher final : public Catch::Matchers::MatcherGenericBase {
public:
template <typename Any>
bool match( Any&& ) const {
return true;
}
std::string describe() const override {
using namespace std::string_literals;
return "Long string that does not fit into SSO"s;
}
};
MatchAllMatcher MatchAll() { return MatchAllMatcher(); }
TEST_CASE( "REQUIRE", "[assertions]" ) {
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( "REQUIRE_THAT", "[assertions][matchers]" ) {
for ( size_t i = 0; i < 10'000'000; ++i ) {
REQUIRE_THAT( 1, MatchAll() );
}
}
TEST_CASE("Simple THROWS - 10M") {
for (size_t i = 0; i < 10'000'000; ++i) {
REQUIRE_THROWS([]() { throw 1; }());
TEST_CASE( "REQUIRE_NOTHROW", "[assertions][exceptions]" ) {
for ( size_t i = 0; i < 10'000'000; ++i ) {
REQUIRE_NOTHROW( []() {}() );
}
}
TEST_CASE( "REQUIRE_THROWS", "[assertions][exceptions]" ) {
for ( size_t i = 0; i < 10'000'000; ++i ) {
REQUIRE_THROWS( []() { throw 1; }() );
}
}
} // namespace
+1 -1
View File
@@ -26,7 +26,7 @@ The ```CHECK``` family are equivalent but execution continues in the same test c
Evaluates the expression and records the result. If an exception is thrown, it is caught, reported, and counted as a failure. These are the macros you will use most of the time.
Examples:
```
```cpp
CHECK( str == "string value" );
CHECK( thisReturnsTrue() );
REQUIRE( i == 42 );
+15
View File
@@ -7,6 +7,8 @@
[Writing documentation](#writing-documentation)<br>
[Writing code](#writing-code)<br>
[CoC](#coc)<br>
[Using LLMs when contributing](#using-llms-when-contributing)<br>
So you want to contribute something to Catch2? That's great! Whether it's
a bug fix, a new feature, support for additional compilers - or just
@@ -332,6 +334,19 @@ When adding new `CATCH_CONFIG` option, there are multiple places to edit:
This project has a [CoC](../CODE_OF_CONDUCT.md). Please adhere to it
while contributing to Catch2.
## Using LLMs when contributing
I do not care whether you used LLM for your contribution. What I care
about is the quality of the contribution, not whether you made it through
prompting LLM, letting GAs run wild, dictated it into the computer, wrote
it using your nose or used butterflies to flip the correct bits.
The flipside of this is that I am also not going to iterate your LLM for
you. If a PR looks LLM generated and does not pass the muster to be merged
as-is, I am going to close it.
-----------
_This documentation will always be in-progress as new information comes
+37
View File
@@ -6,6 +6,7 @@
[Built-in matchers](#built-in-matchers)<br>
[Writing custom matchers (old style)](#writing-custom-matchers-old-style)<br>
[Writing custom matchers (new style)](#writing-custom-matchers-new-style)<br>
[Constexpr matchers](#constexpr-matchers)<br>
Matchers, as popularized by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest)
framework are an alternative way to write assertions, useful for tests
@@ -471,6 +472,42 @@ and new style matchers arbitrarily.
> `MatcherGenericBase` lives in `catch2/matchers/catch_matchers_templated.hpp`
## Constexpr matchers
> Support for constexpr matchers was introduced in Catch2 3.15.0
When compiled for C++20, the new-style matchers (can) support `constexpr`
matching, albeit not `constexpr` stringification. The matcher combinators
require C++26 (or at least P2738) to be `constexpr` compatible.
This can be used together with the `STATIC_REQUIRE_THAT` macro to write
matcher-based static assertions like this:
```cpp
TEST_CASE("Constexpr support for matchers", "[constexpr][matchers]") {
STATIC_REQUIRE_THAT( 1, MatchAll() );
STATIC_REQUIRE_THAT( 1, MatchAll() || MatchAll() );
STATIC_REQUIRE_THAT( 1, !!MatchAll() );
}
```
### First party constexpr matchers
Some (but not all) of Catch2's generic matchers support `constexpr`
matching. Currently, this includes:
* `IsEmpty()`
* `SizeIs(size_t target_size)`, `SizeIs(Matcher size_matcher)`
* `AllMatch(Matcher element_matcher)`
* `AnyMatch(Matcher element_matcher)`
* `NoneMatch(Matcher element_matcher)`
* `AllTrue()`, `AnyTrue()`, `NoneTrue()`
* `Contains(T&& target_element, Comparator = std::equal_to<>{})`
* `Contains(Matcher element_matcher)`
* `RangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})`
* `UnorderedRangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})`
---
[Home](Readme.md#top)
+24
View File
@@ -91,6 +91,30 @@ TEST_CASE("STATIC_CHECK showcase", "[traits]") {
}
```
* `STATIC_REQUIRE_THAT` and `STATIC_CHECK_THAT`
> `STATIC_REQUIRE_THAT` and `STATIC_CHECK_THAT` was introduced in Catch2 3.15.0
`STATIC_{REQUIRE,CHECK}_THAT` are analogous to `STATIC_{REQUIRE,CHECK}`,
but for matchers. They are always defined, even if the current compiler
does not support `constexpr` matchers, but in that case the compilation
will always fail.
Just like `STATIC_{REQUIRE,CHECK}`, `STATIC_{REQUIRE,CHECK}_THAT` can be
delayed into runtime through the `CATCH_CONFIG_RUNTIME_STATIC_REQUIRE`
configuration option.
Example:
```cpp
TEST_CASE("Constexpr support for matchers", "[constexpr][matchers]") {
STATIC_REQUIRE_THAT( 1, MatchAll() );
STATIC_REQUIRE_THAT( 1, MatchAll() && MatchAll() );
STATIC_REQUIRE_THAT( 1, MatchAll() || MatchAll() );
STATIC_REQUIRE_THAT( 1, !!MatchAll() );
}
```
## Test case related macros
* `REGISTER_TEST_CASE`
+36
View File
@@ -2,6 +2,9 @@
# Release notes
**Contents**<br>
[3.15.2](#3152)<br>
[3.15.1](#3151)<br>
[3.15.0](#3150)<br>
[3.14.0](#3140)<br>
[3.13.0](#3130)<br>
[3.12.0](#3120)<br>
@@ -74,6 +77,39 @@
[Even Older versions](#even-older-versions)<br>
## 3.15.2
### Fixes
* Fixed `--warn InfiniteGenerators` triggering even if the generator was limited to specific element via path filtering.
* Fixed `-Wunused-parameter` triggering in `-fnoexceptions` builds.
### Improvements
* `catch_discover_tests` can handle cases where the binary prints out non-Catch2 output due to global constructors (#3162)
## 3.15.1
### Fixes
* Fixed potential OOB access when looking for start of broken UTF-8 sequence during linebreaking (#3096)
* Fixed `TEMPLATE_LIST_TEST_CASE_METHOD` and `CATCH_TEMPLATE_PRODUCT_TEST_CASE` potentially causing ODR violations (#3161)
## 3.15.0
### Fixes
* Fixed ambiguous overload issue with `std::optional<T>` in C++26. (#3095)
* Since `std::optional` was turned into a range, the partial specialization of `StringMaker` for range-like types and for `std::optional<T>` were in conflict.
### Improvements
* Simplified `CATCH_REGISTER_ENUM` internals for faster compilation and retrieval.
* Successful assertion are slightly (1-2%) faster.
* Generic (new-style) matchers support constexpr matching in C++20.
* Combining matchers requires C++26.
* Catch2-provided generic matchers are all constexpr enabled.
* Added `STATIC_REQUIRE_THAT` for compile-time matcher assertions.
* This requires the compiler to support enough `constexpr` for matchers, see above.
## 3.14.0
### Fixes
+6 -4
View File
@@ -36,10 +36,12 @@ Tags allow an arbitrary number of additional strings to be associated with a tes
As an example - given the following test cases:
TEST_CASE( "A", "[widget]" ) { /* ... */ }
TEST_CASE( "B", "[widget]" ) { /* ... */ }
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
```cpp
TEST_CASE( "A", "[widget]" ) { /* ... */ }
TEST_CASE( "B", "[widget]" ) { /* ... */ }
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
```
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
+2 -2
View File
@@ -44,7 +44,7 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
with the ``--list-tests --reporter json`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
@@ -67,7 +67,7 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
pass to the Catch executable when listing the tests.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
+46 -1
View File
@@ -16,6 +16,42 @@ function(add_command NAME)
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Generates random filename in the temp folder.
# Temp folder is retrieved by checking env vars from various platforms.
function(make_temp_file_path OUT_VARIABLE FALLBACK_PATH)
set(TEMP_DIR "")
set(ENV_VARS
# From XDG base dir specification
XDG_RUNTIME_DIR
# From POSIX standard
TMPDIR
# From Windows
TMP
TEMP
)
foreach(var ${ENV_VARS})
message(NOTICE "Checking ${var} env var")
if(DEFINED ENV{${var}} AND NOT "$ENV{${var}}" STREQUAL "")
set(TEMP_DIR "$ENV{${var}}")
break()
endif()
endforeach()
# If all checks fail, we use the fallback path
if(TEMP_DIR STREQUAL "")
set(TEMP_DIR "${FALLBACK_PATH}")
endif()
file(TO_CMAKE_PATH "${TEMP_DIR}" TEMP_DIR)
# Generate the random file name
string(RANDOM LENGTH 8 RAND_ID)
set(FINAL_TEMP_PATH "${TEMP_DIR}/Catch2-test-listing.${RAND_ID}.json")
set(${OUT_VARIABLE} "${FINAL_TEMP_PATH}" PARENT_SCOPE)
endfunction()
function(catch_discover_tests_impl)
cmake_parse_arguments(
@@ -72,8 +108,13 @@ function(catch_discover_tests_impl)
set(ENV{DYLD_FRAMEWORK_PATH} "${paths}")
endif()
make_temp_file_path(listing_output_path "${_TEST_WORKING_DIR}")
execute_process(
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --reporter json
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec}
--list-tests
--reporter json
--out "${listing_output_path}"
OUTPUT_VARIABLE listing_output
RESULT_VARIABLE result
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
@@ -86,6 +127,10 @@ function(catch_discover_tests_impl)
)
endif()
# Read the JSON output back from the output file (and then get rid of the file)
file(READ ${listing_output_path} listing_output)
file(REMOVE ${listing_output_path})
# Prepare reporter
if(reporter)
set(reporter_arg "--reporter ${reporter}")
+121 -112
View File
@@ -6,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
// Catch v3.14.0
// Generated: 2026-04-05 15:03:01.631668
// Catch v3.15.2
// Generated: 2026-07-07 20:39:49.445081
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -74,11 +74,11 @@ namespace Catch {
samples.data(), samples.data() + samples.size() );
auto wrap_estimate = [](Estimate<double> e) {
return Estimate<FDuration> {
FDuration(e.point),
FDuration(e.lower_bound),
FDuration(e.upper_bound),
e.confidence_interval,
return Estimate<FDuration>{
FDuration( e.point ),
FDuration( e.lower_bound ),
FDuration( e.upper_bound ),
e.confidence_interval,
};
};
std::vector<FDuration> samples2;
@@ -147,7 +147,7 @@ namespace Catch {
namespace Catch {
namespace Benchmark {
namespace Detail {
struct optimized_away_error : std::exception {
struct optimized_away_error final : std::exception {
const char* what() const noexcept override;
};
@@ -995,6 +995,7 @@ namespace Catch {
#include <cassert>
#include <stack>
@@ -1007,7 +1008,7 @@ namespace Catch {
m_messageId( builder.m_info.sequence ) {
MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str();
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
Detail::pushScopedMessage( CATCH_MOVE( info ) );
}
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
@@ -1016,7 +1017,7 @@ namespace Catch {
}
ScopedMessage::~ScopedMessage() {
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
if ( !m_moved ) { Detail::popScopedMessage( m_messageId ); }
}
@@ -1088,7 +1089,7 @@ namespace Catch {
assert( m_captured == m_messages.size() );
if ( m_isScoped ) {
for ( auto const& message : m_messages ) {
IResultCapture::popScopedMessage( message.sequence );
Detail::popScopedMessage( message.sequence );
}
}
}
@@ -1097,9 +1098,9 @@ namespace Catch {
assert( index < m_messages.size() );
m_messages[index].message += value;
if ( m_isScoped ) {
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
Detail::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
} else {
IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
Detail::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
}
m_captured++;
}
@@ -1160,9 +1161,6 @@ namespace Catch {
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
#endif
}
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
return m_enumValuesRegistry;
}
private:
TestRegistry m_testCaseRegistry;
@@ -1170,7 +1168,6 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}
@@ -2397,7 +2394,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 14, 0, "", 0 );
static Version version( 3, 15, 2, "", 0 );
return version;
}
@@ -2686,13 +2683,17 @@ namespace Catch {
namespace Catch {
void AssertionHandler::finishIncomplete() {
m_resultCapture.handleIncomplete( m_assertionInfo );
}
AssertionHandler::AssertionHandler
( StringRef macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() )
m_resultCapture( static_cast<RunContext&>(getResultCapture()) )
{
m_resultCapture.notifyAssertionStarted( m_assertionInfo );
}
@@ -4088,12 +4089,11 @@ namespace Catch {
#include <cassert>
namespace Catch {
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
namespace Detail {
namespace {
@@ -4119,9 +4119,7 @@ namespace Catch {
return parsed;
}
EnumInfo::~EnumInfo() = default;
StringRef EnumInfo::lookup( int value ) const {
StringRef EnumInfo::lookup( int64_t value ) const {
for( auto const& valueToName : m_values ) {
if( valueToName.first == value )
return valueToName.second;
@@ -4129,25 +4127,20 @@ namespace Catch {
return "{** unexpected enum value **}"_sr;
}
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
enumInfo->m_name = enumName;
enumInfo->m_values.reserve( values.size() );
EnumInfo makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int64_t> const& values ) {
EnumInfo enumInfo;
enumInfo.m_name = enumName;
enumInfo.m_values.reserve( values.size() );
const auto valueNames = Catch::Detail::parseEnums( allValueNames );
assert( valueNames.size() == values.size() );
std::size_t i = 0;
for( auto value : values )
enumInfo->m_values.emplace_back(value, valueNames[i++]);
for (size_t i = 0; i < values.size(); ++i) {
enumInfo.m_values.emplace_back( values[i], valueNames[i] );
}
return enumInfo;
}
EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
return *m_enumInfos.back();
}
} // Detail
} // Catch
@@ -5072,7 +5065,7 @@ namespace Catch {
namespace {
//! A no-op implementation, used if no reporter wants output
//! redirection.
class NoopRedirect : public OutputRedirect {
class NoopRedirect final : public OutputRedirect {
void activateImpl() override {}
void deactivateImpl() override {}
std::string getStdout() override { return {}; }
@@ -5109,7 +5102,7 @@ namespace Catch {
* Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
* but does not touch the actual `stdout`/`stderr` file descriptors.
*/
class StreamRedirect : public OutputRedirect {
class StreamRedirect final : public OutputRedirect {
ReusableStringStream m_redirectedOut, m_redirectedErr;
RedirectedStreamNew m_cout, m_cerr, m_clog;
@@ -5220,7 +5213,7 @@ namespace Catch {
* Works by replacing the file descriptors numbered 1 and 2
* with an open temporary file.
*/
class FileRedirect : public OutputRedirect {
class FileRedirect final : public OutputRedirect {
TempFile m_outFile, m_errFile;
int m_originalOut = -1;
int m_originalErr = -1;
@@ -6023,6 +6016,8 @@ namespace Catch {
auto getGenerator() const -> GeneratorBasePtr const& override {
return m_generator;
}
bool isFilteredImpl() const override { return m_isFiltered; }
};
} // namespace
}
@@ -6136,6 +6131,25 @@ namespace Catch {
}
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
void pushScopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) );
}
void popScopedMessage( unsigned int messageId ) {
Detail::g_messageHolder().removeMessage( messageId );
}
void emplaceUnscopedMessage( MessageBuilder&& builder ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
}
void addUnscopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
}
bool lastAssertionPassed() { return Detail::g_lastAssertionPassed; }
} // namespace Detail
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
@@ -6269,14 +6283,13 @@ namespace Catch {
Detail::g_lastAssertionPassed = true;
} else if (!result.succeeded()) {
Detail::g_lastAssertionPassed = false;
if (result.isOk()) {
}
else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine
if (result.isOk()) {}
else if( m_activeTestCase->getTestCaseInfo().okToFail() ) { // Read from a shared state established before the threads could start, this is fine
m_atomicAssertionCount.failedButOk++;
else
} else {
m_atomicAssertionCount.failed++;
}
else {
}
} else {
Detail::g_lastAssertionPassed = true;
}
@@ -6349,17 +6362,6 @@ namespace Catch {
SourceLineInfo lineInfo,
Generators::GeneratorBasePtr&& generator ) {
// TBD: Do we want to avoid the warning if the generator is filtered?
if ( m_config->warnAboutInfiniteGenerators() &&
!generator->isFinite() ) {
// We want the semantics of `FAIL()`, but we inline it
// to avoid issues with conditionally prefixed macros
INTERNAL_CATCH_MSG( "FAIL",
Catch::ResultWas::ExplicitFailure,
Catch::ResultDisposition::Normal,
"GENERATE() would run infinitely" );
}
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
auto& currentTracker = m_trackerContext.currentTracker();
assert(
@@ -6372,11 +6374,24 @@ namespace Catch {
m_trackerContext,
&currentTracker,
CATCH_MOVE( generator ) );
auto ret = newTracker.get();
// The warning shouldn't fire if the generator is infinite, **but** filtered down.
if ( m_config->warnAboutInfiniteGenerators() &&
!newTracker->m_generator->isFinite() &&
!newTracker->isFiltered() ) {
// We want the semantics of `FAIL()`, but we inline it
// to avoid issues with conditionally prefixed macros
INTERNAL_CATCH_MSG( "FAIL",
Catch::ResultWas::ExplicitFailure,
Catch::ResultDisposition::Normal,
"GENERATE() would run infinitely" );
}
auto returnPtr = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
ret->open();
return ret;
returnPtr->open();
return returnPtr;
}
bool RunContext::testForMissingAssertions(Counts& assertions) {
@@ -6458,7 +6473,7 @@ namespace Catch {
// and since IResultCapture::getLastResult is deprecated,
// we will leave it as is, until it is finally removed.
Detail::LockGuard _( m_assertionMutex );
return &(*m_lastResult);
return &*m_lastResult;
}
void RunContext::exceptionEarlyReported() {
@@ -6532,10 +6547,6 @@ namespace Catch {
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
}
bool RunContext::lastAssertionPassed() {
return Detail::g_lastAssertionPassed;
}
void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) {
// We want to save the line info for better experience with unexpected assertions
Detail::g_lastKnownLineInfo = lineInfo;
@@ -6714,7 +6725,7 @@ namespace Catch {
}
void RunContext::populateReaction( AssertionReaction& reaction,
bool has_normal_disposition ) {
bool has_normal_disposition ) const {
reaction.shouldDebugBreak = m_shouldDebugBreak;
reaction.shouldThrow = aborting() || has_normal_disposition;
}
@@ -6765,22 +6776,6 @@ namespace Catch {
}
}
void IResultCapture::pushScopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) );
}
void IResultCapture::popScopedMessage( unsigned int messageId ) {
Detail::g_messageHolder().removeMessage( messageId );
}
void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
}
void IResultCapture::addUnscopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
}
void seedRng(IConfig const& config) {
sharedRng().seed(config.rngSeed());
}
@@ -7112,10 +7107,11 @@ namespace Catch {
TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
auto it = m_registry.find( alias );
if( it != m_registry.end() )
return &(it->second);
else
if ( it != m_registry.end() ) {
return &it->second;
} else {
return nullptr;
}
}
std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
@@ -7478,6 +7474,28 @@ namespace TestCaseTracking {
m_ctx.setCurrentTracker( this );
}
bool SectionTracker::isFilteredImpl() const {
// TBD: This is currently _very_ similar to the block in `isComplete`.
// Is this neccessarily that way, or just accident of current semantics?
const size_t filterIndex =
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
if ( filterIndex < m_filterRef->size() ) {
// 1) New style filter must explicitly target section
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
PathFilter::For::Section ) {
return true;
}
// 2) Both style filters must match the trimmed name exactly
if ( m_trimmed_name !=
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
return true;
}
}
return false;
}
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
@@ -7562,7 +7580,7 @@ namespace Catch {
void throw_test_failure_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw TestFailureException{};
throw TestFailureException{}; //NOLINT(bugprone-std-exception-baseclass)
#else
CATCH_ERROR( "Test failure requires aborting test!" );
#endif
@@ -7570,7 +7588,7 @@ namespace Catch {
void throw_test_skip_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw Catch::TestSkipException();
throw Catch::TestSkipException(); //NOLINT(bugprone-std-exception-baseclass)
#else
CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
#endif
@@ -8024,8 +8042,8 @@ namespace Catch {
m_it--;
}
// Skip back over UTF-8 continuation bytes to the leading byte
while ( isUtf8ContinuationByte( *m_it ) ) {
assert( m_it != m_string->begin() );
while ( m_it != m_string->begin() &&
isUtf8ContinuationByte( *m_it ) ) {
m_it--;
}
}
@@ -8674,13 +8692,13 @@ namespace Catch {
namespace Matchers {
std::string MatcherUntypedBase::toString() const {
if (m_cachedToString.empty()) {
m_cachedToString = describe();
}
return m_cachedToString;
return describe();
}
MatcherUntypedBase::~MatcherUntypedBase() = default;
std::string MatcherUntypedBase::describe() const {
using namespace std::string_literals;
return "Undescribed matcher"s;
}
} // namespace Matchers
} // namespace Catch
@@ -8701,14 +8719,6 @@ namespace Matchers {
return sstr.str();
}
IsEmptyMatcher IsEmpty() {
return {};
}
HasSizeMatcher SizeIs(std::size_t sz) {
return HasSizeMatcher{ sz };
}
} // end namespace Matchers
} // end namespace Catch
@@ -8962,17 +8972,13 @@ std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc
namespace Catch {
namespace Matchers {
std::string AllTrueMatcher::describe() const { return "contains only true"; }
AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
std::string AllTrueMatcher::describe() const { return "contains only true"; }
std::string NoneTrueMatcher::describe() const { return "contains no true"; }
NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
} // namespace Matchers
} // namespace Catch
@@ -9085,7 +9091,11 @@ namespace Matchers {
namespace Catch {
namespace Matchers {
MatcherGenericBase::~MatcherGenericBase() = default;
std::string MatcherGenericBase::describe() const {
using namespace std::string_literals;
return "Undescribed generic matcher"s;
}
namespace Detail {
@@ -10108,9 +10118,8 @@ namespace Catch {
bool operator()(
Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
node ) const {
return (
( node->stats.sectionInfo.name == m_other.name ) &&
( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
return node->stats.sectionInfo.name == m_other.name
&& node->stats.sectionInfo.lineInfo == m_other.lineInfo;
}
void operator=( BySectionInfo const& ) = delete;
@@ -10464,7 +10473,7 @@ namespace Catch {
}
// minimum whitespace to pad tag counts, possibly overwritten below
size_t maxTagCountLen = 2;
int maxTagCountLen = 2;
// determine necessary padding for tag count column
if ( ! tags.empty() ) {
@@ -10479,7 +10488,7 @@ namespace Catch {
// more padding necessary for 3+ digits
if (maxTagCount >= 100) {
auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
maxTagCountLen = static_cast<size_t>( numDigits );
maxTagCountLen = static_cast<int>( numDigits );
}
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -8,7 +8,7 @@
project(
'catch2',
'cpp',
version: '3.14.0', # CML version placeholder, don't delete
version: '3.15.2', # CML version placeholder, don't delete
license: 'BSL-1.0',
meson_version: '>=0.54.1',
)
+2 -3
View File
@@ -87,7 +87,7 @@ set(IMPL_HEADERS
${SOURCES_DIR}/internal/catch_decomposer.hpp
${SOURCES_DIR}/internal/catch_deprecation_macro.hpp
${SOURCES_DIR}/internal/catch_enforce.hpp
${SOURCES_DIR}/internal/catch_enum_values_registry.hpp
${SOURCES_DIR}/internal/catch_enum_info.hpp
${SOURCES_DIR}/internal/catch_errno_guard.hpp
${SOURCES_DIR}/internal/catch_exception_translator_registry.hpp
${SOURCES_DIR}/internal/catch_fatal_condition_handler.hpp
@@ -181,7 +181,7 @@ set(IMPL_SOURCES
${SOURCES_DIR}/internal/catch_debugger.cpp
${SOURCES_DIR}/internal/catch_decomposer.cpp
${SOURCES_DIR}/internal/catch_enforce.cpp
${SOURCES_DIR}/internal/catch_enum_values_registry.cpp
${SOURCES_DIR}/internal/catch_enum_info.cpp
${SOURCES_DIR}/internal/catch_errno_guard.cpp
${SOURCES_DIR}/internal/catch_exception_translator_registry.cpp
${SOURCES_DIR}/internal/catch_fatal_condition_handler.cpp
@@ -227,7 +227,6 @@ set(INTERFACE_HEADERS
${SOURCES_DIR}/interfaces/catch_interfaces_all.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_capture.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_config.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_enum_values_registry.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_exception.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp
@@ -36,11 +36,11 @@ namespace Catch {
samples.data(), samples.data() + samples.size() );
auto wrap_estimate = [](Estimate<double> e) {
return Estimate<FDuration> {
FDuration(e.point),
FDuration(e.lower_bound),
FDuration(e.upper_bound),
e.confidence_interval,
return Estimate<FDuration>{
FDuration( e.point ),
FDuration( e.lower_bound ),
FDuration( e.upper_bound ),
e.confidence_interval,
};
};
std::vector<FDuration> samples2;
@@ -41,7 +41,7 @@ namespace Catch {
callable& operator=(callable&&) = default;
};
template <typename Fun>
struct model : public callable {
struct model final : public callable {
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
model(Fun const& fun_) : fun(fun_) {}
@@ -14,7 +14,7 @@
namespace Catch {
namespace Benchmark {
namespace Detail {
struct optimized_away_error : std::exception {
struct optimized_away_error final : std::exception {
const char* what() const noexcept override;
};
+1 -1
View File
@@ -68,7 +68,7 @@
#include <catch2/internal/catch_decomposer.hpp>
#include <catch2/internal/catch_deprecation_macro.hpp>
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_errno_guard.hpp>
#include <catch2/internal/catch_exception_translator_registry.hpp>
#include <catch2/internal/catch_fatal_condition_handler.hpp>
+6 -6
View File
@@ -5,8 +5,8 @@
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_message.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
@@ -22,7 +22,7 @@ namespace Catch {
m_messageId( builder.m_info.sequence ) {
MessageInfo info( CATCH_MOVE( builder.m_info ) );
info.message = builder.m_stream.str();
IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
Detail::pushScopedMessage( CATCH_MOVE( info ) );
}
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
@@ -31,7 +31,7 @@ namespace Catch {
}
ScopedMessage::~ScopedMessage() {
if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
if ( !m_moved ) { Detail::popScopedMessage( m_messageId ); }
}
@@ -103,7 +103,7 @@ namespace Catch {
assert( m_captured == m_messages.size() );
if ( m_isScoped ) {
for ( auto const& message : m_messages ) {
IResultCapture::popScopedMessage( message.sequence );
Detail::popScopedMessage( message.sequence );
}
}
}
@@ -112,9 +112,9 @@ namespace Catch {
assert( index < m_messages.size() );
m_messages[index].message += value;
if ( m_isScoped ) {
IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
Detail::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
} else {
IResultCapture::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
Detail::addUnscopedMessage( CATCH_MOVE( m_messages[index] ) );
}
m_captured++;
}
+15 -3
View File
@@ -13,16 +13,28 @@
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_stream_end_stop.hpp>
#include <catch2/internal/catch_message_info.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/catch_tostring.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <string>
#include <vector>
namespace Catch {
struct MessageInfo;
struct MessageBuilder;
namespace Detail {
// The message state affecting functions have to be defined in
// the TU where the thread-local message holders are defined.
// Currently this is catch_run_context.cpp
void pushScopedMessage( MessageInfo&& message );
void popScopedMessage( unsigned int messageId );
void addUnscopedMessage( MessageInfo&& message );
void emplaceUnscopedMessage( MessageBuilder&& builder );
} // namespace Detail
struct SourceLineInfo;
class IResultCapture;
struct MessageStream {
@@ -112,7 +124,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
Catch::Detail::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
-5
View File
@@ -15,7 +15,6 @@
#include <catch2/internal/catch_tag_alias_registry.hpp>
#include <catch2/internal/catch_startup_exception_registry.hpp>
#include <catch2/internal/catch_singletons.hpp>
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/catch_test_case_info.hpp>
#include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
@@ -72,9 +71,6 @@ namespace Catch {
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
#endif
}
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
return m_enumValuesRegistry;
}
private:
TestRegistry m_testCaseRegistry;
@@ -82,7 +78,6 @@ namespace Catch {
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
TagAliasRegistry m_tagAliasRegistry;
StartupExceptionRegistry m_exceptionRegistry;
Detail::EnumValuesRegistry m_enumValuesRegistry;
};
}
+1
View File
@@ -21,6 +21,7 @@
#include <catch2/reporters/catch_reporter_multi.hpp>
#include <catch2/internal/catch_reporter_registry.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_stdstreams.hpp>
#include <catch2/internal/catch_istream.hpp>
+21 -13
View File
@@ -18,7 +18,8 @@
#include <catch2/internal/catch_config_wchar.hpp>
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_void_type.hpp>
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
#include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_stringref.hpp>
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
#include <string_view>
@@ -383,7 +384,10 @@ namespace Catch {
}
#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
#if defined( CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER ) && \
defined( CATCH_CONFIG_CPP17_OPTIONAL ) && \
/* P3168 turned optional into a range, making this ambigous with the range support */ \
!defined( __cpp_lib_optional_range_support )
#include <optional>
namespace Catch {
template<typename T>
@@ -630,17 +634,21 @@ struct ratio_string<std::milli> {
};
}
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
namespace Catch { \
template<> struct StringMaker<enumName> { \
static std::string convert( enumName value ) { \
static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
} \
}; \
}
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
namespace Catch { \
template <> \
struct StringMaker<enumName> { \
static std::string convert( enumName value ) { \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
static const auto enumInfo = ::Catch::Detail::makeEnumInfo( \
#enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
return static_cast<std::string>( \
enumInfo.lookup( static_cast<int64_t>( value ) ) ); \
} \
}; \
}
#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
+3 -1
View File
@@ -22,7 +22,7 @@ namespace Catch {
class ExceptionTranslatorRegistrar {
template<typename T>
class ExceptionTranslator : public IExceptionTranslator {
class ExceptionTranslator final : public IExceptionTranslator {
public:
constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) )
@@ -41,6 +41,8 @@ namespace Catch {
return m_translateFunction( ex );
}
#else
(void)it;
(void)itEnd;
return "You should never get here!";
#endif
}
+1 -1
View File
@@ -36,7 +36,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 3, 14, 0, "", 0 );
static Version version( 3, 15, 2, "", 0 );
return version;
}
+2 -2
View File
@@ -9,7 +9,7 @@
#define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 14
#define CATCH_VERSION_PATCH 0
#define CATCH_VERSION_MINOR 15
#define CATCH_VERSION_PATCH 2
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
+1 -2
View File
@@ -179,8 +179,7 @@ namespace Generators {
bool isFinite() const override {
for (auto const& gen : m_generators) {
if (!gen.isFinite()) { return false;
}
if (!gen.isFinite()) { return false; }
}
return true;
}
@@ -24,7 +24,6 @@
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
#include <catch2/interfaces/catch_interfaces_exception.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
@@ -22,8 +22,6 @@ namespace Catch {
struct AssertionInfo;
struct SectionInfo;
struct SectionEndInfo;
struct MessageInfo;
struct MessageBuilder;
struct Counts;
struct AssertionReaction;
struct SourceLineInfo;
@@ -63,11 +61,6 @@ namespace Catch {
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
virtual void benchmarkFailed( StringRef error ) = 0;
static void pushScopedMessage( MessageInfo&& message );
static void popScopedMessage( unsigned int messageId );
static void addUnscopedMessage( MessageInfo&& message );
static void emplaceUnscopedMessage( MessageBuilder&& builder );
virtual void handleFatalErrorCondition( StringRef message ) = 0;
virtual void handleExpr
@@ -93,9 +86,6 @@ namespace Catch {
ResultWas::OfType resultType,
AssertionReaction &reaction ) = 0;
virtual bool lastAssertionPassed() = 0;
// Deprecated, do not use:
virtual std::string getCurrentTestName() const = 0;
virtual const AssertionResult* getLastResult() const = 0;
@@ -64,7 +64,7 @@ namespace Catch {
class IStream;
struct PathFilter;
class IConfig : public Detail::NonCopyable {
class IConfig : Detail::NonCopyable {
public:
virtual ~IConfig();
@@ -1,47 +0,0 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#include <catch2/internal/catch_stringref.hpp>
#include <vector>
namespace Catch {
namespace Detail {
struct EnumInfo {
StringRef m_name;
std::vector<std::pair<int, StringRef>> m_values;
~EnumInfo();
StringRef lookup( int value ) const;
};
} // namespace Detail
class IMutableEnumValuesRegistry {
public:
virtual ~IMutableEnumValuesRegistry(); // = default;
virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
template<typename E>
Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
std::vector<int> intValues;
intValues.reserve( values.size() );
for( auto enumValue : values )
intValues.push_back( static_cast<int>( enumValue ) );
return registerEnum( enumName, allEnums, intValues );
}
};
} // Catch
#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
@@ -53,7 +53,6 @@ namespace Catch {
virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
virtual void registerStartupException() noexcept = 0;
virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
};
IRegistryHub const& getRegistryHub();
@@ -6,21 +6,28 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/interfaces/catch_interfaces_capture.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_debugger.hpp>
#include <catch2/internal/catch_run_context.hpp>
#include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
namespace Catch {
void AssertionHandler::finishIncomplete() {
m_resultCapture.handleIncomplete( m_assertionInfo );
}
AssertionHandler::AssertionHandler
( StringRef macroName,
SourceLineInfo const& lineInfo,
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() )
m_resultCapture( static_cast<RunContext&>(getResultCapture()) )
{
m_resultCapture.notifyAssertionStarted( m_assertionInfo );
}
@@ -10,12 +10,13 @@
#include <catch2/catch_assertion_info.hpp>
#include <catch2/internal/catch_decomposer.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <string>
namespace Catch {
class RunContext;
struct AssertionReaction {
bool shouldDebugBreak = false;
bool shouldThrow = false;
@@ -26,7 +27,12 @@ namespace Catch {
AssertionInfo m_assertionInfo;
AssertionReaction m_reaction;
bool m_completed = false;
IResultCapture& m_resultCapture;
// Since all uses are hidden in the .cpp file, we can directly use
// the final type and avoid going through virtual dispatch, without
// massive compilation time overhead.
RunContext& m_resultCapture;
void finishIncomplete();
public:
AssertionHandler
@@ -35,9 +41,9 @@ namespace Catch {
StringRef capturedExpression,
ResultDisposition::Flags resultDisposition );
~AssertionHandler() {
if ( !m_completed ) {
m_resultCapture.handleIncomplete( m_assertionInfo );
}
// We want the common fast path inlinable, and the virtual
// dispatch in a function in single TU.
if ( !m_completed ) { finishIncomplete(); }
}
@@ -27,16 +27,24 @@
#include <catch2/internal/catch_platform.hpp>
#include <catch2/catch_user_config.hpp>
#ifdef __cplusplus
#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# define CATCH_CPP17_OR_GREATER
#endif
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# define CATCH_CPP17_OR_GREATER
# endif
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
# define CATCH_CPP20_OR_GREATER
# endif
#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
# define CATCH_CPP20_OR_GREATER
#endif
// Matchers are only constexpr-able in C++20
#if defined( CATCH_CPP20_OR_GREATER ) && \
defined( __cpp_constexpr_dynamic_alloc ) && \
__cpp_constexpr_dynamic_alloc >= 201907L && \
/* GCC < 13 define the feature macro, but compiler bugs stop us from using it */ \
( !defined( __GNUC__ ) || __GNUC__ >= 13 || defined(__clang__) )
# define CATCH_INTERNAL_CONSTEXPR_MATCHERS_ENABLED
# define CATCH_DESTRUCTOR_CONSTEXPR constexpr
#else
# define CATCH_DESTRUCTOR_CONSTEXPR
#endif
// Only GCC compiler should be used in this block, so other compilers trying to
+2 -2
View File
@@ -193,7 +193,7 @@ namespace Catch {
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
template<typename LhsT, typename RhsT>
class BinaryExpr : public ITransientExpression {
class BinaryExpr final : public ITransientExpression {
LhsT m_lhs;
StringRef m_op;
RhsT m_rhs;
@@ -269,7 +269,7 @@ namespace Catch {
};
template<typename LhsT>
class UnaryExpr : public ITransientExpression {
class UnaryExpr final : public ITransientExpression {
LhsT m_lhs;
void streamReconstructedExpression( std::ostream &os ) const override {
@@ -5,15 +5,14 @@
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#include <catch2/internal/catch_enum_values_registry.hpp>
#include <catch2/internal/catch_enum_info.hpp>
#include <catch2/internal/catch_string_manip.hpp>
#include <cassert>
namespace Catch {
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
namespace Detail {
namespace {
@@ -39,9 +38,7 @@ namespace Catch {
return parsed;
}
EnumInfo::~EnumInfo() = default;
StringRef EnumInfo::lookup( int value ) const {
StringRef EnumInfo::lookup( int64_t value ) const {
for( auto const& valueToName : m_values ) {
if( valueToName.first == value )
return valueToName.second;
@@ -49,25 +46,20 @@ namespace Catch {
return "{** unexpected enum value **}"_sr;
}
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
enumInfo->m_name = enumName;
enumInfo->m_values.reserve( values.size() );
EnumInfo makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int64_t> const& values ) {
EnumInfo enumInfo;
enumInfo.m_name = enumName;
enumInfo.m_values.reserve( values.size() );
const auto valueNames = Catch::Detail::parseEnums( allValueNames );
assert( valueNames.size() == values.size() );
std::size_t i = 0;
for( auto value : values )
enumInfo->m_values.emplace_back(value, valueNames[i++]);
for (size_t i = 0; i < values.size(); ++i) {
enumInfo.m_values.emplace_back( values[i], valueNames[i] );
}
return enumInfo;
}
EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
return *m_enumInfos.back();
}
} // Detail
} // Catch
+48
View File
@@ -0,0 +1,48 @@
// 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_ENUM_INFO_HPP_INCLUDED
#define CATCH_ENUM_INFO_HPP_INCLUDED
#include <catch2/internal/catch_stringref.hpp>
#include <cstdint>
#include <utility>
#include <vector>
namespace Catch {
namespace Detail {
struct EnumInfo {
StringRef m_name;
std::vector<std::pair<int64_t, StringRef>> m_values;
StringRef lookup( int64_t value ) const;
};
EnumInfo makeEnumInfo( StringRef enumName,
StringRef allValueNames,
std::vector<int64_t> const& values );
template <typename E>
Detail::EnumInfo makeEnumInfo( StringRef enumName,
StringRef allEnums,
std::initializer_list<E> values ) {
static_assert( sizeof( int64_t ) >= sizeof( E ),
"Cannot serialize enum to int64_t" );
std::vector<int64_t> intValues;
intValues.reserve( values.size() );
for ( auto enumValue : values )
intValues.push_back( static_cast<int64_t>( enumValue ) );
return makeEnumInfo( enumName, allEnums, intValues );
}
std::vector<StringRef> parseEnums( StringRef enums );
} // namespace Detail
} // namespace Catch
#endif // CATCH_ENUM_INFO_HPP_INCLUDED
@@ -1,36 +0,0 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_enum_values_registry.hpp>
#include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <vector>
namespace Catch {
namespace Detail {
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
class EnumValuesRegistry : public IMutableEnumValuesRegistry {
std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
};
std::vector<StringRef> parseEnums( StringRef enums );
} // Detail
} // Catch
#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
@@ -15,7 +15,7 @@
namespace Catch {
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
class ExceptionTranslatorRegistry final : public IExceptionTranslatorRegistry {
public:
~ExceptionTranslatorRegistry() override;
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
@@ -33,7 +33,7 @@ namespace Catch {
namespace {
//! A no-op implementation, used if no reporter wants output
//! redirection.
class NoopRedirect : public OutputRedirect {
class NoopRedirect final : public OutputRedirect {
void activateImpl() override {}
void deactivateImpl() override {}
std::string getStdout() override { return {}; }
@@ -70,7 +70,7 @@ namespace Catch {
* Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
* but does not touch the actual `stdout`/`stderr` file descriptors.
*/
class StreamRedirect : public OutputRedirect {
class StreamRedirect final : public OutputRedirect {
ReusableStringStream m_redirectedOut, m_redirectedErr;
RedirectedStreamNew m_cout, m_cerr, m_clog;
@@ -181,7 +181,7 @@ namespace Catch {
* Works by replacing the file descriptors numbered 1 and 2
* with an open temporary file.
*/
class FileRedirect : public OutputRedirect {
class FileRedirect final : public OutputRedirect {
TempFile m_outFile, m_errFile;
int m_originalOut = -1;
int m_originalErr = -1;
+45 -42
View File
@@ -11,6 +11,7 @@
#include <catch2/generators/catch_generators_throw.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_context.hpp>
@@ -195,6 +196,8 @@ namespace Catch {
auto getGenerator() const -> GeneratorBasePtr const& override {
return m_generator;
}
bool isFilteredImpl() const override { return m_isFiltered; }
};
} // namespace
}
@@ -308,6 +311,25 @@ namespace Catch {
}
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
void pushScopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) );
}
void popScopedMessage( unsigned int messageId ) {
Detail::g_messageHolder().removeMessage( messageId );
}
void emplaceUnscopedMessage( MessageBuilder&& builder ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
}
void addUnscopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
}
bool lastAssertionPassed() { return Detail::g_lastAssertionPassed; }
} // namespace Detail
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
@@ -441,14 +463,13 @@ namespace Catch {
Detail::g_lastAssertionPassed = true;
} else if (!result.succeeded()) {
Detail::g_lastAssertionPassed = false;
if (result.isOk()) {
}
else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine
if (result.isOk()) {}
else if( m_activeTestCase->getTestCaseInfo().okToFail() ) { // Read from a shared state established before the threads could start, this is fine
m_atomicAssertionCount.failedButOk++;
else
} else {
m_atomicAssertionCount.failed++;
}
else {
}
} else {
Detail::g_lastAssertionPassed = true;
}
@@ -521,17 +542,6 @@ namespace Catch {
SourceLineInfo lineInfo,
Generators::GeneratorBasePtr&& generator ) {
// TBD: Do we want to avoid the warning if the generator is filtered?
if ( m_config->warnAboutInfiniteGenerators() &&
!generator->isFinite() ) {
// We want the semantics of `FAIL()`, but we inline it
// to avoid issues with conditionally prefixed macros
INTERNAL_CATCH_MSG( "FAIL",
Catch::ResultWas::ExplicitFailure,
Catch::ResultDisposition::Normal,
"GENERATE() would run infinitely" );
}
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
auto& currentTracker = m_trackerContext.currentTracker();
assert(
@@ -544,11 +554,24 @@ namespace Catch {
m_trackerContext,
&currentTracker,
CATCH_MOVE( generator ) );
auto ret = newTracker.get();
// The warning shouldn't fire if the generator is infinite, **but** filtered down.
if ( m_config->warnAboutInfiniteGenerators() &&
!newTracker->m_generator->isFinite() &&
!newTracker->isFiltered() ) {
// We want the semantics of `FAIL()`, but we inline it
// to avoid issues with conditionally prefixed macros
INTERNAL_CATCH_MSG( "FAIL",
Catch::ResultWas::ExplicitFailure,
Catch::ResultDisposition::Normal,
"GENERATE() would run infinitely" );
}
auto returnPtr = newTracker.get();
currentTracker.addChild( CATCH_MOVE( newTracker ) );
ret->open();
return ret;
returnPtr->open();
return returnPtr;
}
bool RunContext::testForMissingAssertions(Counts& assertions) {
@@ -630,7 +653,7 @@ namespace Catch {
// and since IResultCapture::getLastResult is deprecated,
// we will leave it as is, until it is finally removed.
Detail::LockGuard _( m_assertionMutex );
return &(*m_lastResult);
return &*m_lastResult;
}
void RunContext::exceptionEarlyReported() {
@@ -704,10 +727,6 @@ namespace Catch {
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
}
bool RunContext::lastAssertionPassed() {
return Detail::g_lastAssertionPassed;
}
void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) {
// We want to save the line info for better experience with unexpected assertions
Detail::g_lastKnownLineInfo = lineInfo;
@@ -886,7 +905,7 @@ namespace Catch {
}
void RunContext::populateReaction( AssertionReaction& reaction,
bool has_normal_disposition ) {
bool has_normal_disposition ) const {
reaction.shouldDebugBreak = m_shouldDebugBreak;
reaction.shouldThrow = aborting() || has_normal_disposition;
}
@@ -937,22 +956,6 @@ namespace Catch {
}
}
void IResultCapture::pushScopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addScopedMessage( CATCH_MOVE( message ) );
}
void IResultCapture::popScopedMessage( unsigned int messageId ) {
Detail::g_messageHolder().removeMessage( messageId );
}
void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( builder ) );
}
void IResultCapture::addUnscopedMessage( MessageInfo&& message ) {
Detail::g_messageHolder().addUnscopedMessage( CATCH_MOVE( message ) );
}
void seedRng(IConfig const& config) {
sharedRng().seed(config.rngSeed());
}
+1 -3
View File
@@ -102,8 +102,6 @@ namespace Catch {
void handleFatalErrorCondition( StringRef message ) override;
bool lastAssertionPassed() override;
public:
// !TBD We need to do this another way!
bool aborting() const;
@@ -125,7 +123,7 @@ namespace Catch {
ITransientExpression const *expr,
bool negated );
void populateReaction( AssertionReaction& reaction, bool has_normal_disposition );
void populateReaction( AssertionReaction& reaction, bool has_normal_disposition ) const;
// Creates dummy info for unexpected exceptions/fatal errors,
// where we do not have the access to one, but we still need
+1 -1
View File
@@ -20,7 +20,7 @@ namespace Catch {
template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
class Singleton : SingletonImplT, public ISingleton {
class Singleton final : SingletonImplT, public ISingleton {
static auto getInternal() -> Singleton* {
static Singleton* s_instance = nullptr;
@@ -16,10 +16,11 @@ namespace Catch {
TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
auto it = m_registry.find( alias );
if( it != m_registry.end() )
return &(it->second);
else
if ( it != m_registry.end() ) {
return &it->second;
} else {
return nullptr;
}
}
std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
@@ -17,7 +17,7 @@
namespace Catch {
struct SourceLineInfo;
class TagAliasRegistry : public ITagAliasRegistry {
class TagAliasRegistry final : public ITagAliasRegistry {
public:
~TagAliasRegistry() override;
TagAlias const* find( std::string const& alias ) const override;
@@ -245,42 +245,42 @@
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
namespace {\
template<typename TestType> \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
namespace {\
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
INTERNAL_CATCH_TYPE_GEN \
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types>\
struct TestNameClass{\
void reg_tests(){\
std::size_t index = 0;\
using expander = std::size_t[];\
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
}\
};\
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
TestInit t;\
t.reg_tests();\
return 0;\
}(); \
}\
}\
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
INTERNAL_CATCH_TYPE_GEN \
INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
template<typename...Types>\
struct TestNameClass{\
void reg_tests(){\
std::size_t index = 0;\
using expander = std::size_t[];\
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
}\
};\
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
TestInit t;\
t.reg_tests();\
return 0;\
}(); \
}\
}\
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
@@ -298,37 +298,37 @@
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
namespace {\
template<typename TestType> \
struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
void test();\
};\
namespace {\
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
INTERNAL_CATCH_TYPE_GEN\
template<typename...Types>\
struct TestNameClass{\
void reg_tests(){\
size_t index = 0;\
using expander = size_t[];\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = typename convert<TestNameClass, TmplList>::type;\
TestInit t;\
t.reg_tests();\
return 0;\
}(); \
}}\
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
INTERNAL_CATCH_TYPE_GEN\
template<typename...Types>\
struct TestNameClass{\
void reg_tests(){\
size_t index = 0;\
using expander = size_t[];\
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
}\
};\
static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
using TestInit = typename convert<TestNameClass, TmplList>::type;\
TestInit t;\
t.reg_tests();\
return 0;\
}(); \
}}\
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
template<typename TestType> \
void TestName<TestType>::test()
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
@@ -28,7 +28,7 @@ namespace Catch {
std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
class TestRegistry : public ITestCaseRegistry {
class TestRegistry final : public ITestCaseRegistry {
public:
void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );
@@ -167,6 +167,28 @@ namespace TestCaseTracking {
m_ctx.setCurrentTracker( this );
}
bool SectionTracker::isFilteredImpl() const {
// TBD: This is currently _very_ similar to the block in `isComplete`.
// Is this neccessarily that way, or just accident of current semantics?
const size_t filterIndex =
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
if ( filterIndex < m_filterRef->size() ) {
// 1) New style filter must explicitly target section
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
PathFilter::For::Section ) {
return true;
}
// 2) Both style filters must match the trimmed name exactly
if ( m_trimmed_name !=
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
return true;
}
}
return false;
}
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
@@ -12,6 +12,7 @@
#include <catch2/internal/catch_source_line_info.hpp>
#include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_path_filter.hpp>
#include <string>
#include <vector>
@@ -81,6 +82,8 @@ namespace TestCaseTracking {
using Children = std::vector<ITrackerPtr>;
virtual bool isFilteredImpl() const = 0;
protected:
enum CycleState {
NotStarted,
@@ -178,6 +181,20 @@ namespace TestCaseTracking {
* for internal debug checks.
*/
virtual bool isGeneratorTracker() const;
/**
* Returns true if the concrete tracker instance has a filter that applies to it.
*/
bool isFiltered() const {
// Fast path: are there even filters for tracker in this position?
const size_t filter_depth =
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
if ( m_filterRef->size() <= filter_depth ) { return false; }
// Slow path: If there are filters, ask the concrete tracker.
// This handles things like match-all filters for that tracker.
return isFilteredImpl();
}
};
class TrackerContext {
@@ -233,6 +250,8 @@ namespace TestCaseTracking {
// to not own the name, the name still has to outlive the `ITracker` parent, so
// this should still be safe.
StringRef m_trimmed_name;
bool isFilteredImpl() const override;
public:
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
@@ -14,7 +14,7 @@ namespace Catch {
void throw_test_failure_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw TestFailureException{};
throw TestFailureException{}; //NOLINT(bugprone-std-exception-baseclass)
#else
CATCH_ERROR( "Test failure requires aborting test!" );
#endif
@@ -22,7 +22,7 @@ namespace Catch {
void throw_test_skip_exception() {
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
throw Catch::TestSkipException();
throw Catch::TestSkipException(); //NOLINT(bugprone-std-exception-baseclass)
#else
CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
#endif
@@ -11,10 +11,16 @@
#include <catch2/catch_user_config.hpp>
#include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_source_line_info.hpp>
namespace Catch {
namespace Detail {
// Defined in catch_run_context.cpp, where the thread-local data lives.
bool lastAssertionPassed();
}
}
// We need this suppression to leak, because it took until GCC 10
// for the front end to handle local suppression via _Pragma properly
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
@@ -57,12 +63,12 @@
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( Catch::getResultCapture().lastAssertionPassed() )
if( Catch::Detail::lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
if( !Catch::getResultCapture().lastAssertionPassed() )
if( !Catch::Detail::lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
+3 -3
View File
@@ -29,7 +29,7 @@
namespace Catch {
template<typename C>
class TestInvokerAsMethod : public ITestInvoker {
class TestInvokerAsMethod final : public ITestInvoker {
void (C::*m_testAsMethod)();
public:
constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept:
@@ -49,7 +49,7 @@ Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
}
template <typename C>
class TestInvokerFixture : public ITestInvoker {
class TestInvokerFixture final : public ITestInvoker {
void ( C::*m_testAsMethod )() const;
Detail::unique_ptr<C> m_fixture = nullptr;
@@ -124,7 +124,7 @@ struct AutoReg : Detail::NonCopyable {
namespace Catch {
namespace Detail {
struct DummyUse {
DummyUse( void ( * )( int ), Catch::NameAndTags const& );
DummyUse( void ( * )( int ), Catch::NameAndTags const& ) noexcept;
};
} // namespace Detail
} // namespace Catch
+2 -2
View File
@@ -148,8 +148,8 @@ namespace Catch {
m_it--;
}
// Skip back over UTF-8 continuation bytes to the leading byte
while ( isUtf8ContinuationByte( *m_it ) ) {
assert( m_it != m_string->begin() );
while ( m_it != m_string->begin() &&
isUtf8ContinuationByte( *m_it ) ) {
m_it--;
}
}
+5 -5
View File
@@ -13,13 +13,13 @@ namespace Catch {
namespace Matchers {
std::string MatcherUntypedBase::toString() const {
if (m_cachedToString.empty()) {
m_cachedToString = describe();
}
return m_cachedToString;
return describe();
}
MatcherUntypedBase::~MatcherUntypedBase() = default;
std::string MatcherUntypedBase::describe() const {
using namespace std::string_literals;
return "Undescribed matcher"s;
}
} // namespace Matchers
} // namespace Catch
+38 -6
View File
@@ -20,10 +20,10 @@ namespace Matchers {
class MatcherUntypedBase {
public:
MatcherUntypedBase() = default;
constexpr MatcherUntypedBase() = default;
MatcherUntypedBase(MatcherUntypedBase const&) = default;
MatcherUntypedBase(MatcherUntypedBase&&) = default;
constexpr MatcherUntypedBase(MatcherUntypedBase const&) = default;
constexpr MatcherUntypedBase(MatcherUntypedBase&&) = default;
MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
@@ -31,9 +31,9 @@ namespace Matchers {
std::string toString() const;
protected:
virtual ~MatcherUntypedBase(); // = default;
virtual std::string describe() const = 0;
mutable std::string m_cachedToString;
CATCH_DESTRUCTOR_CONSTEXPR virtual ~MatcherUntypedBase() = default;
//! Should be overridden, but we provide default "undescribed" impl
virtual std::string describe() const;
};
@@ -215,6 +215,19 @@ namespace Matchers {
#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) \
static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \
CATCH_SUCCEED( #matcher ".match( " #arg " )" )
#define CATCH_STATIC_CHECK_THAT( arg, matcher ) \
static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \
CATCH_SUCCEED( #matcher ".match( " #arg " )" )
#else
#define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) CATCH_REQUIRE_THAT( arg, matcher )
#define CATCH_STATIC_CHECK_THAT( arg, matcher ) CATCH_CHECK_THAT( arg, matcher )
#endif
#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
@@ -226,6 +239,9 @@ namespace Matchers {
#define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
#define CATCH_STATIC_REQUIRE_THAT( arg, matcher ) (void)(0)
#define CATCH_STATIC_CHECK_THAT( arg, matcher ) (void)(0)
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
@@ -237,6 +253,19 @@ namespace Matchers {
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
#define STATIC_REQUIRE_THAT( arg, matcher ) \
static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \
SUCCEED( #matcher ".match( " #arg " )" )
#define STATIC_CHECK_THAT( arg, matcher ) \
static_assert( ( matcher ).match( arg ), #matcher ".match( " #arg " )"); \
SUCCEED( #matcher ".match( " #arg " )" )
#else
#define STATIC_REQUIRE_THAT( arg, matcher ) REQUIRE_THAT( arg, matcher )
#define STATIC_CHECK_THAT( arg, matcher ) CHECK_THAT( arg, matcher )
#endif
#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
@@ -248,6 +277,9 @@ namespace Matchers {
#define CHECK_THAT( arg, matcher ) (void)(0)
#define REQUIRE_THAT( arg, matcher ) (void)(0)
#define STATIC_REQUIRE_THAT( arg, matcher ) (void)(0)
#define STATIC_CHECK_THAT( arg, matcher ) (void)(0)
#endif // end of user facing macro declarations
#endif // CATCH_MATCHERS_HPP_INCLUDED
@@ -22,13 +22,5 @@ namespace Matchers {
return sstr.str();
}
IsEmptyMatcher IsEmpty() {
return {};
}
HasSizeMatcher SizeIs(std::size_t sz) {
return HasSizeMatcher{ sz };
}
} // end namespace Matchers
} // end namespace Catch
@@ -18,7 +18,7 @@ namespace Catch {
class IsEmptyMatcher final : public MatcherGenericBase {
public:
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::empty;
#else
@@ -33,12 +33,12 @@ namespace Catch {
class HasSizeMatcher final : public MatcherGenericBase {
std::size_t m_target_size;
public:
explicit HasSizeMatcher(std::size_t target_size):
constexpr explicit HasSizeMatcher(std::size_t target_size):
m_target_size(target_size)
{}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size;
#else
@@ -54,12 +54,12 @@ namespace Catch {
class SizeMatchesMatcher final : public MatcherGenericBase {
Matcher m_matcher;
public:
explicit SizeMatchesMatcher(Matcher m):
constexpr explicit SizeMatchesMatcher(Matcher m):
m_matcher(CATCH_MOVE(m))
{}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
using Catch::Detail::size;
#else
@@ -75,11 +75,13 @@ namespace Catch {
//! Creates a matcher that accepts empty ranges/containers
IsEmptyMatcher IsEmpty();
inline CATCH_DESTRUCTOR_CONSTEXPR IsEmptyMatcher IsEmpty() { return {}; }
//! Creates a matcher that accepts ranges/containers with specific size
HasSizeMatcher SizeIs(std::size_t sz);
inline CATCH_DESTRUCTOR_CONSTEXPR HasSizeMatcher SizeIs( std::size_t sz ) {
return HasSizeMatcher{ sz };
}
template <typename Matcher>
std::enable_if_t<Detail::is_matcher_v<Matcher>,
constexpr std::enable_if_t<Detail::is_matcher_v<Matcher>,
SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
}
@@ -23,7 +23,7 @@ namespace Catch {
Equality m_eq;
public:
template <typename T2, typename Equality2>
ContainsElementMatcher(T2&& target, Equality2&& predicate):
constexpr ContainsElementMatcher(T2&& target, Equality2&& predicate):
m_desired(CATCH_FORWARD(target)),
m_eq(CATCH_FORWARD(predicate))
{}
@@ -33,7 +33,7 @@ namespace Catch {
}
template <typename RangeLike>
bool match( RangeLike&& rng ) const {
constexpr bool match( RangeLike&& rng ) const {
for ( auto&& elem : rng ) {
if ( m_eq( elem, m_desired ) ) { return true; }
}
@@ -49,12 +49,12 @@ namespace Catch {
// Note that we do a copy+move to avoid having to SFINAE this
// constructor (and also avoid some perfect forwarding failure
// cases)
ContainsMatcherMatcher(Matcher matcher):
constexpr ContainsMatcherMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher))
{}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (m_matcher.match(elem)) {
return true;
@@ -74,14 +74,14 @@ namespace Catch {
* Uses `std::equal_to` to do the comparison
*/
template <typename T>
std::enable_if_t<!Detail::is_matcher_v<T>,
constexpr std::enable_if_t<!Detail::is_matcher_v<T>,
ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
return { CATCH_FORWARD(elem), std::equal_to<>{} };
}
//! Creates a matcher that checks whether a range contains element matching a matcher
template <typename Matcher>
std::enable_if_t<Detail::is_matcher_v<Matcher>,
constexpr std::enable_if_t<Detail::is_matcher_v<Matcher>,
ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) };
}
@@ -92,7 +92,7 @@ namespace Catch {
* Uses `eq` to do the comparisons, the element is provided on the rhs
*/
template <typename T, typename Equality>
ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
constexpr ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
}
@@ -9,16 +9,12 @@
namespace Catch {
namespace Matchers {
std::string AllTrueMatcher::describe() const { return "contains only true"; }
AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
std::string AllTrueMatcher::describe() const { return "contains only true"; }
std::string NoneTrueMatcher::describe() const { return "contains no true"; }
NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
} // namespace Matchers
} // namespace Catch
@@ -18,7 +18,7 @@ namespace Catch {
class AllMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher;
public:
AllMatchMatcher(Matcher matcher):
constexpr AllMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher))
{}
@@ -27,7 +27,7 @@ namespace Catch {
}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (!m_matcher.match(elem)) {
return false;
@@ -42,7 +42,7 @@ namespace Catch {
class NoneMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher;
public:
NoneMatchMatcher(Matcher matcher):
constexpr NoneMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher))
{}
@@ -51,7 +51,7 @@ namespace Catch {
}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (m_matcher.match(elem)) {
return false;
@@ -66,7 +66,7 @@ namespace Catch {
class AnyMatchMatcher final : public MatcherGenericBase {
Matcher m_matcher;
public:
AnyMatchMatcher(Matcher matcher):
constexpr AnyMatchMatcher(Matcher matcher):
m_matcher(CATCH_MOVE(matcher))
{}
@@ -75,7 +75,7 @@ namespace Catch {
}
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (m_matcher.match(elem)) {
return true;
@@ -91,7 +91,7 @@ namespace Catch {
std::string describe() const override;
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (!elem) {
return false;
@@ -107,7 +107,7 @@ namespace Catch {
std::string describe() const override;
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (elem) {
return false;
@@ -123,7 +123,7 @@ namespace Catch {
std::string describe() const override;
template <typename RangeLike>
bool match(RangeLike&& rng) const {
constexpr bool match(RangeLike&& rng) const {
for (auto&& elem : rng) {
if (elem) {
return true;
@@ -133,32 +133,35 @@ namespace Catch {
}
};
// Creates a matcher that checks whether all elements in a range match a matcher
//! Creates a matcher that checks whether all elements in a range match a matcher
template <typename Matcher>
AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
constexpr AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) };
}
// Creates a matcher that checks whether no element in a range matches a matcher.
//! Creates a matcher that checks whether no element in a range matches a matcher.
template <typename Matcher>
NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
constexpr NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) };
}
// Creates a matcher that checks whether any element in a range matches a matcher.
//! Creates a matcher that checks whether any element in a range matches a matcher.
template <typename Matcher>
AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
constexpr AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
return { CATCH_FORWARD(matcher) };
}
// Creates a matcher that checks whether all elements in a range are true
AllTrueMatcher AllTrue();
//! Creates a matcher that checks whether all elements in a range are true
inline CATCH_DESTRUCTOR_CONSTEXPR
AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
// Creates a matcher that checks whether no element in a range is true
NoneTrueMatcher NoneTrue();
//! Creates a matcher that checks whether no element in a range is true
inline CATCH_DESTRUCTOR_CONSTEXPR
NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
// Creates a matcher that checks whether any element in a range is true
AnyTrueMatcher AnyTrue();
//! Creates a matcher that checks whether any element in a range is true
inline CATCH_DESTRUCTOR_CONSTEXPR
AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
}
}
@@ -9,7 +9,11 @@
namespace Catch {
namespace Matchers {
MatcherGenericBase::~MatcherGenericBase() = default;
std::string MatcherGenericBase::describe() const {
using namespace std::string_literals;
return "Undescribed generic matcher"s;
}
namespace Detail {
@@ -22,12 +22,12 @@
namespace Catch {
namespace Matchers {
class MatcherGenericBase : public MatcherUntypedBase {
std::string describe() const override;
public:
MatcherGenericBase() = default;
~MatcherGenericBase() override; // = default;
constexpr MatcherGenericBase() = default;
MatcherGenericBase(MatcherGenericBase const&) = default;
MatcherGenericBase(MatcherGenericBase&&) = default;
constexpr MatcherGenericBase(MatcherGenericBase const&) = default;
constexpr MatcherGenericBase(MatcherGenericBase&&) = default;
MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
@@ -36,7 +36,9 @@ namespace Matchers {
namespace Detail {
template<std::size_t N, std::size_t M>
std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
constexpr std::array<void const*, N + M>
array_cat( std::array<void const*, N>&& lhs,
std::array<void const*, M>&& rhs ) {
std::array<void const*, N + M> arr{};
std::copy_n(lhs.begin(), N, arr.begin());
std::copy_n(rhs.begin(), M, arr.begin() + N);
@@ -44,7 +46,8 @@ namespace Matchers {
}
template<std::size_t N>
std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
constexpr std::array<void const*, N + 1>
array_cat( std::array<void const*, N>&& lhs, void const* rhs ) {
std::array<void const*, N+1> arr{};
std::copy_n(lhs.begin(), N, arr.begin());
arr[N] = rhs;
@@ -52,7 +55,8 @@ namespace Matchers {
}
template<std::size_t N>
std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
constexpr std::array<void const*, N + 1>
array_cat( void const* lhs, std::array<void const*, N>&& rhs ) {
std::array<void const*, N + 1> arr{ {lhs} };
std::copy_n(rhs.begin(), N, arr.begin() + 1);
return arr;
@@ -75,23 +79,31 @@ namespace Matchers {
template<std::size_t N, typename Arg>
bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
constexpr bool match_all_of( Arg&&,
std::array<void const*, N> const&,
std::index_sequence<> ) {
return true;
}
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
constexpr bool match_all_of( Arg&& arg,
std::array<void const*, N> const& matchers,
std::index_sequence<Idx, Indices...> ) {
return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
}
template<std::size_t N, typename Arg>
bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
constexpr bool match_any_of( Arg&&,
std::array<void const*, N> const&,
std::index_sequence<> ) {
return false;
}
template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
constexpr bool match_any_of( Arg&& arg,
std::array<void const*, N> const& matchers,
std::index_sequence<Idx, Indices...> ) {
return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
}
@@ -112,15 +124,18 @@ namespace Matchers {
public:
MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
constexpr MatchAllOfGeneric( MatchAllOfGeneric&& ) = default;
constexpr MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
MatchAllOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND)
constexpr MatchAllOfGeneric(
MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND )
: m_matchers{ {std::addressof(matchers)...} } {}
explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
constexpr explicit MatchAllOfGeneric(
std::array<void const*, sizeof...( MatcherTs )> matchers ):
m_matchers{ matchers } {}
template<typename Arg>
bool match(Arg&& arg) const {
constexpr bool match( Arg&& arg ) const {
return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
}
@@ -136,7 +151,7 @@ namespace Matchers {
//! Avoids type nesting for `GenericAllOf && GenericAllOf` case
template<typename... MatchersRHS>
friend
constexpr friend
MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAllOfGeneric<MatchersRHS...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -145,7 +160,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAllOf && some matcher` case
template<typename MatcherRHS>
friend std::enable_if_t<is_matcher_v<MatcherRHS>,
constexpr friend std::enable_if_t<
is_matcher_v<MatcherRHS>,
MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
MatchAllOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -154,7 +170,8 @@ namespace Matchers {
//! Avoids type nesting for `some matcher && GenericAllOf` case
template<typename MatcherLHS>
friend std::enable_if_t<is_matcher_v<MatcherLHS>,
constexpr friend std::enable_if_t<
is_matcher_v<MatcherLHS>,
MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAllOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -168,15 +185,18 @@ namespace Matchers {
public:
MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
constexpr MatchAnyOfGeneric( MatchAnyOfGeneric&& ) = default;
constexpr MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
MatchAnyOfGeneric(MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND)
constexpr MatchAnyOfGeneric(
MatcherTs const&... matchers CATCH_ATTR_LIFETIMEBOUND )
: m_matchers{ {std::addressof(matchers)...} } {}
explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
constexpr explicit MatchAnyOfGeneric(
std::array<void const*, sizeof...( MatcherTs )> matchers ):
m_matchers{ matchers } {}
template<typename Arg>
bool match(Arg&& arg) const {
constexpr bool match( Arg&& arg ) const {
return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
}
@@ -192,7 +212,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
template<typename... MatchersRHS>
friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
constexpr friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>
operator||(
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))};
@@ -200,7 +221,8 @@ namespace Matchers {
//! Avoids type nesting for `GenericAnyOf || some matcher` case
template<typename MatcherRHS>
friend std::enable_if_t<is_matcher_v<MatcherRHS>,
constexpr friend std::enable_if_t<
is_matcher_v<MatcherRHS>,
MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
MatchAnyOfGeneric<MatcherTs...>&& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
@@ -209,7 +231,8 @@ namespace Matchers {
//! Avoids type nesting for `some matcher || GenericAnyOf` case
template<typename MatcherLHS>
friend std::enable_if_t<is_matcher_v<MatcherLHS>,
constexpr friend std::enable_if_t<
is_matcher_v<MatcherLHS>,
MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatchAnyOfGeneric<MatcherTs...>&& rhs CATCH_ATTR_LIFETIMEBOUND) {
@@ -225,14 +248,15 @@ namespace Matchers {
public:
MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
constexpr MatchNotOfGeneric( MatchNotOfGeneric&& ) = default;
constexpr MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
explicit MatchNotOfGeneric(MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND)
constexpr explicit MatchNotOfGeneric(
MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND )
: m_matcher{matcher} {}
template<typename Arg>
bool match(Arg&& arg) const {
constexpr bool match( Arg&& arg ) const {
return !m_matcher.match(arg);
}
@@ -241,7 +265,7 @@ namespace Matchers {
}
//! Negating negation can just unwrap and return underlying matcher
friend MatcherT const&
constexpr friend MatcherT const&
operator!( MatchNotOfGeneric<MatcherT> const& matcher
CATCH_ATTR_LIFETIMEBOUND ) {
return matcher.m_matcher;
@@ -252,14 +276,18 @@ 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>>
constexpr std::enable_if_t<
Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>,
Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
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>>
constexpr std::enable_if_t<
Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>,
Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
operator||( MatcherLHS const& lhs CATCH_ATTR_LIFETIMEBOUND,
MatcherRHS const& rhs CATCH_ATTR_LIFETIMEBOUND ) {
return { lhs, rhs };
@@ -267,7 +295,8 @@ namespace Matchers {
//! Wrap provided generic matcher in generic negator
template<typename MatcherT>
std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>, Detail::MatchNotOfGeneric<MatcherT>>
constexpr std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>,
Detail::MatchNotOfGeneric<MatcherT>>
operator!( MatcherT const& matcher CATCH_ATTR_LIFETIMEBOUND ) {
return Detail::MatchNotOfGeneric<MatcherT>{matcher};
}
@@ -29,7 +29,7 @@ namespace Catch {
#endif
template<typename ArgT, typename MatcherT>
class MatchExpr : public ITransientExpression {
class MatchExpr final : public ITransientExpression {
ArgT && m_arg;
MatcherT const& m_matcher;
public:
+2 -3
View File
@@ -65,7 +65,6 @@ internal_headers = [
'interfaces/catch_interfaces_all.hpp',
'interfaces/catch_interfaces_capture.hpp',
'interfaces/catch_interfaces_config.hpp',
'interfaces/catch_interfaces_enum_values_registry.hpp',
'interfaces/catch_interfaces_exception.hpp',
'interfaces/catch_interfaces_generatortracker.hpp',
'interfaces/catch_interfaces_registry_hub.hpp',
@@ -95,7 +94,7 @@ internal_headers = [
'internal/catch_decomposer.hpp',
'internal/catch_deprecation_macro.hpp',
'internal/catch_enforce.hpp',
'internal/catch_enum_values_registry.hpp',
'internal/catch_enum_info.hpp',
'internal/catch_errno_guard.hpp',
'internal/catch_exception_translator_registry.hpp',
'internal/catch_fatal_condition_handler.hpp',
@@ -224,7 +223,7 @@ internal_sources = files(
'internal/catch_debugger.cpp',
'internal/catch_decomposer.cpp',
'internal/catch_enforce.cpp',
'internal/catch_enum_values_registry.cpp',
'internal/catch_enum_info.cpp',
'internal/catch_errno_guard.cpp',
'internal/catch_exception_translator_registry.cpp',
'internal/catch_fatal_condition_handler.cpp',
@@ -20,9 +20,8 @@ namespace Catch {
bool operator()(
Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
node ) const {
return (
( node->stats.sectionInfo.name == m_other.name ) &&
( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
return node->stats.sectionInfo.name == m_other.name
&& node->stats.sectionInfo.lineInfo == m_other.lineInfo;
}
void operator=( BySectionInfo const& ) = delete;
@@ -199,7 +199,7 @@ namespace Catch {
}
// minimum whitespace to pad tag counts, possibly overwritten below
size_t maxTagCountLen = 2;
int maxTagCountLen = 2;
// determine necessary padding for tag count column
if ( ! tags.empty() ) {
@@ -214,7 +214,7 @@ namespace Catch {
// more padding necessary for 3+ digits
if (maxTagCount >= 100) {
auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
maxTagCountLen = static_cast<size_t>( numDigits );
maxTagCountLen = static_cast<int>( numDigits );
}
}
+1
View File
@@ -62,6 +62,7 @@ cc_test(
"SelfTest/UsageTests/Exception.tests.cpp",
"SelfTest/UsageTests/Generators.tests.cpp",
"SelfTest/UsageTests/Matchers.tests.cpp",
"SelfTest/UsageTests/MatchersConstexpr.tests.cpp",
"SelfTest/UsageTests/MatchersRanges.tests.cpp",
"SelfTest/UsageTests/Message.tests.cpp",
"SelfTest/UsageTests/Misc.tests.cpp",
+2 -1
View File
@@ -124,8 +124,9 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
${SELF_TEST_DIR}/UsageTests/MatchersRanges.tests.cpp
${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
${SELF_TEST_DIR}/UsageTests/MatchersConstexpr.tests.cpp
${SELF_TEST_DIR}/UsageTests/MatchersRanges.tests.cpp
)
set(TEST_HEADERS
+81 -25
View File
@@ -174,7 +174,7 @@ target_compile_definitions(DeferredStaticChecks PRIVATE "CATCH_CONFIG_RUNTIME_ST
add_test(NAME DeferredStaticChecks COMMAND DeferredStaticChecks -r compact)
set_tests_properties(DeferredStaticChecks
PROPERTIES
PASS_REGULAR_EXPRESSION "test cases: 1 \\| 1 failed\nassertions: 3 \\| 3 failed"
PASS_REGULAR_EXPRESSION "test cases: 1 \\| 1 failed\nassertions: 3 \\| 3 failed;test cases: 1 \\| 1 failed\nassertions: 4 \\| 4 failed"
)
add_executable(MixingClearedAndUnclearedMessages ${TESTS_DIR}/X06-MixingClearedAndUnclearedMessages.cpp)
@@ -526,29 +526,18 @@ set_tests_properties(TestSpecs::SkippingAllTestsFails
WILL_FAIL ON
)
set(EXTRA_TEST_BINARIES
AllSkipped
PrefixedMacros
DisabledMacros
DisabledExceptions-DefaultHandler
DisabledExceptions-CustomHandler
FallbackStringifier
DisableStringification
PartialTestCaseEvents
DuplicatedTestCases-SameNameAndTags
DuplicatedTestCases-SameNameDifferentTags
DuplicatedTestCases-DuplicatedTestCaseMethods
NoTests
ListenersGetEventsBeforeReporters
MixingClearedAndUnclearedMessages
# DebugBreakMacros
)
add_executable(FastCompileMacros ${TESTS_DIR}/X07-FastCompileMacros.cpp)
target_link_libraries(FastCompileMacros PRIVATE Catch2_buildall_interface)
target_compile_definitions(FastCompileMacros PRIVATE CATCH_CONFIG_FAST_COMPILE)
# Notice that we are modifying EXTRA_TEST_BINARIES destructively, do not
# use it after this point!
list(FILTER EXTRA_TEST_BINARIES EXCLUDE REGEX "DisabledExceptions.*")
list(APPEND CATCH_TEST_TARGETS ${EXTRA_TEST_BINARIES})
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
add_test(
NAME CompileConfiguration::FastCompile
COMMAND $<TARGET_FILE:FastCompileMacros>
)
set_tests_properties(CompileConfiguration::FastCompile
PROPERTIES
PASS_REGULAR_EXPRESSION "test cases: 6 \\| 1 passed \\| 1 failed \\| 4 failed as expected\nassertions: 13 \\| 6 passed \\| 2 failed \\| 5 failed as expected"
)
# This sets up a one-off executable that compiles against the amalgamated
# files, and then runs it for a super simple check that the amalgamated
@@ -594,12 +583,79 @@ add_executable(InfiniteGenerators ${TESTS_DIR}/X95-InfiniteGenerators.cpp)
target_link_libraries(InfiniteGenerators PRIVATE Catch2::Catch2WithMain)
add_test(
NAME Warnings::InfiniteGenerators
NAME Warnings::InfiniteGenerators::NoFilterWarns
COMMAND $<TARGET_FILE:InfiniteGenerators> --warn InfiniteGenerators
)
set_tests_properties(Warnings::InfiniteGenerators
set_tests_properties(Warnings::InfiniteGenerators::NoFilterWarns
PROPERTIES
# One test case fails with infinite generator, but the other one runs
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
TIMEOUT 5
)
add_test(
NAME Warnings::InfiniteGenerators::MatchAllFilterWarns
COMMAND $<TARGET_FILE:InfiniteGenerators>
--warn InfiniteGenerators
--path-filter g:*
)
set_tests_properties(Warnings::InfiniteGenerators::MatchAllFilterWarns
PROPERTIES
# One test case fails with infinite generator, but the other one runs
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
TIMEOUT 5
)
add_test(
NAME Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
COMMAND $<TARGET_FILE:InfiniteGenerators>
--warn InfiniteGenerators
--path-filter g:1
)
set_tests_properties(Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
PROPERTIES
# One test case fails with infinite generator, but the other one runs
PASS_REGULAR_EXPRESSION "All tests passed \\(1 assertion in 2 test cases\\)"
TIMEOUT 5
)
add_test(
NAME Warnings::InfiniteGenerators::SectionFilterWarns
COMMAND $<TARGET_FILE:InfiniteGenerators>
--warn InfiniteGenerators
--section FooBarBaz
)
set_tests_properties(Warnings::InfiniteGenerators::SectionFilterWarns
PROPERTIES
# One test case fails with infinite generator, but the other one runs
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
TIMEOUT 5
)
set(EXTRA_TEST_BINARIES
AllSkipped
PrefixedMacros
DisabledMacros
DisabledExceptions-DefaultHandler
DisabledExceptions-CustomHandler
FallbackStringifier
DisableStringification
PartialTestCaseEvents
DuplicatedTestCases-SameNameAndTags
DuplicatedTestCases-SameNameDifferentTags
DuplicatedTestCases-DuplicatedTestCaseMethods
NoTests
ListenersGetEventsBeforeReporters
MixingClearedAndUnclearedMessages
FastCompileMacros
InfiniteGenerators
ThreadSafetyTests
# DebugBreakMacros
)
# Notice that we are modifying EXTRA_TEST_BINARIES destructively, do not
# use it after this point!
list(FILTER EXTRA_TEST_BINARIES EXCLUDE REGEX "DisabledExceptions.*")
list(APPEND CATCH_TEST_TARGETS ${EXTRA_TEST_BINARIES})
set(CATCH_TEST_TARGETS ${CATCH_TEST_TARGETS} PARENT_SCOPE)
-1
View File
@@ -3,7 +3,6 @@ yet:
CATCH_CONFIG_COUNTER // Use __COUNTER__ to generate unique names for test cases
CATCH_CONFIG_WINDOWS_SEH // Enable SEH handling on Windows
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
CATCH_CONFIG_DEFAULT_REPORTER
+2
View File
@@ -53,6 +53,8 @@ TEST_CASE( "Disabled Macros" ) {
REQUIRE_THAT( 1,
Catch::Matchers::Predicate( []( int ) { return false; } ) );
BENCHMARK( "Disabled benchmark" ) { REQUIRE( 1 == 2 ); };
STATIC_REQUIRE_THAT( 1, Catch::Matchers::Predicate( []( int ) { return false; } ) );
}
struct DisabledFixture {};
@@ -12,10 +12,36 @@
*/
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>
#if defined( CATCH_INTERNAL_CONSTEXPR_MATCHERS_ENABLED )
namespace {
struct MatchNoneMatcher final : public Catch::Matchers::MatcherGenericBase {
public:
template <typename Any>
constexpr bool match( Any&& ) const {
return false;
}
std::string describe() const override {
using namespace std::string_literals;
return "Matches anything"s;
}
};
constexpr MatchNoneMatcher MatchNone() { return MatchNoneMatcher(); }
} // namespace
#endif
TEST_CASE("Deferred static checks") {
STATIC_CHECK(1 == 2);
STATIC_CHECK_FALSE(1 != 2);
#if defined(CATCH_INTERNAL_CONSTEXPR_MATCHERS_ENABLED)
STATIC_CHECK_THAT(1, MatchNone());
#endif
// This last assertion must be executed too
CHECK(1 == 2);
}
@@ -0,0 +1,63 @@
// 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
* Test that various basic macros work with CATCH_CONFIG_FAST_COMPILE.
*
* Note that the current checking is rather loose. We check that the
* macros compile, and that the test cases (don't) fail as they are
* supposed to.
*/
#include <catch2/catch_test_macros.hpp>
#include <stdexcept>
namespace {
[[noreturn]]
static void throws() {
throw std::runtime_error{ "sup" };
}
static void doesnt_throw() {}
[[noreturn]]
static int throws_i() {
throw std::runtime_error{ "sup" };
}
} // namespace
TEST_CASE( "Passing macros work" ) {
REQUIRE( 1 != 2 );
CHECK( 2 == 2 );
REQUIRE_THROWS( throws() );
REQUIRE_NOTHROW( doesnt_throw() );
}
TEST_CASE( "Failing macros work", "[!shouldfail]" ) {
CHECK( 1 != 2 );
CHECK( 2 == 2 );
CHECK( 3 == 2 );
}
TEST_CASE( "Failing NOTHROW works", "[!shouldfail]" ) {
REQUIRE_NOTHROW( throws() );
}
TEST_CASE( "Failing THROW works", "[!shouldfail]" ) {
REQUIRE_THROWS( doesnt_throw() );
}
TEST_CASE( "Unexpected exception in REQUIRE gets inverted properly",
"[!shouldfail]" ) {
REQUIRE( throws_i() == 1 );
}
TEST_CASE( "Unexpected exception in REQUIRE fails properly" ) {
REQUIRE( throws_i() == 2 );
}
@@ -33,6 +33,7 @@ namespace {
TEST_CASE() {
auto _ = GENERATE( make_infinite_generator() );
(void)_;
}
TEST_CASE() {
@@ -144,6 +144,7 @@ Nor would this
:test-result: SKIP Empty generators can SKIP in constructor
:test-result: PASS Empty stream name opens cout stream
:test-result: FAIL EndsWith string matcher
:test-result: PASS Enum backed by larger underlying type
:test-result: PASS Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
:test-result: PASS Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM
:test-result: PASS Epsilon only applies to Approx's value
@@ -142,6 +142,7 @@
:test-result: SKIP Empty generators can SKIP in constructor
:test-result: PASS Empty stream name opens cout stream
:test-result: FAIL EndsWith string matcher
:test-result: PASS Enum backed by larger underlying type
:test-result: PASS Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
:test-result: PASS Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM
:test-result: PASS Epsilon only applies to Approx's value
@@ -576,15 +576,18 @@ Approx.tests.cpp:<line number>: passed: 101.000001 != Approx(100).epsilon(0.01)
Approx.tests.cpp:<line number>: passed: std::pow(10, -5) != Approx(std::pow(10, -7)) for: 0.00001 != Approx( 0.0000001 )
Message.tests.cpp:<line number>: passed: true with 1 message: 'a'
Message.tests.cpp:<line number>: failed: false with 1 message: 'b'
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(0) == "Value1" for: Value1 == "Value1"
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(1) == "Value2" for: Value2 == "Value2"
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **}
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(0) == "Value1" for: Value1 == "Value1"
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(1) == "Value2" for: Value2 == "Value2"
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **}
==
"{** unexpected enum value **}"
Skip.tests.cpp:<line number>: skipped: 'This generator is empty'
Stream.tests.cpp:<line number>: passed: Catch::makeStream( "" )->isConsole() for: true
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag1 ) == "Flag1" for: "Flag1" == "Flag1"
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag2 ) == "Flag2" for: "Flag2" == "Flag2"
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag5 ) == "Flag5" for: "Flag5" == "Flag5"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value2 ) == "Value2" for: "Value2" == "Value2"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value3 ) == "Value3" for: "Value3" == "Value3"
@@ -2755,13 +2758,13 @@ Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }"
==
"{ { 42, "Arthur" }, { "Ford", 24 } }"
ToString.tests.cpp:<line number>: passed: parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) for: { } Equals: { }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) for: { Value1, Value2 } Equals: { Value1, Value2 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) for: { } Equals: { }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) for: { Value1, Value2 } Equals: { Value1, Value2 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen IF info is printed for passing assertions'
Message.tests.cpp:<line number>: failed: false with 2 messages: 'this SHOULD be seen' and 'this SHOULD also be seen'
@@ -2997,7 +3000,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: 450 | 330 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2413 | 2212 passed | 158 failed | 43 failed as expected
test cases: 451 | 331 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2416 | 2215 passed | 158 failed | 43 failed as expected
@@ -574,15 +574,18 @@ Approx.tests.cpp:<line number>: passed: 101.000001 != Approx(100).epsilon(0.01)
Approx.tests.cpp:<line number>: passed: std::pow(10, -5) != Approx(std::pow(10, -7)) for: 0.00001 != Approx( 0.0000001 )
Message.tests.cpp:<line number>: passed: true with 1 message: 'a'
Message.tests.cpp:<line number>: failed: false with 1 message: 'b'
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(0) == "Value1" for: Value1 == "Value1"
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(1) == "Value2" for: Value2 == "Value2"
ToString.tests.cpp:<line number>: passed: enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **}
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(0) == "Value1" for: Value1 == "Value1"
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(1) == "Value2" for: Value2 == "Value2"
EnumToString.tests.cpp:<line number>: passed: enumInfo.lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **}
==
"{** unexpected enum value **}"
Skip.tests.cpp:<line number>: skipped: 'This generator is empty'
Stream.tests.cpp:<line number>: passed: Catch::makeStream( "" )->isConsole() for: true
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring"
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag1 ) == "Flag1" for: "Flag1" == "Flag1"
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag2 ) == "Flag2" for: "Flag2" == "Flag2"
EnumToString.tests.cpp:<line number>: passed: stringify( LargeEnum::Flag5 ) == "Flag5" for: "Flag5" == "Flag5"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value2 ) == "Value2" for: "Value2" == "Value2"
EnumToString.tests.cpp:<line number>: passed: stringify( EnumClass3::Value3 ) == "Value3" for: "Value3" == "Value3"
@@ -2744,13 +2747,13 @@ Tricky.tests.cpp:<line number>: passed: ptr.get() == 0 for: 0 == 0
ToStringPair.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( pair ) == "{ { 42, \"Arthur\" }, { \"Ford\", 24 } }" for: "{ { 42, "Arthur" }, { "Ford", 24 } }"
==
"{ { 42, "Arthur" }, { "Ford", 24 } }"
ToString.tests.cpp:<line number>: passed: parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) for: { } Equals: { }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) for: { Value1, Value2 } Equals: { Value1, Value2 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
ToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) for: { } Equals: { }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) for: { Value1 } Equals: { Value1 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) for: { Value1, Value2 } Equals: { Value1, Value2 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
EnumToString.tests.cpp:<line number>: passed: parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) for: { Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
Tricky.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
Message.tests.cpp:<line number>: passed: true with 1 message: 'this MAY be seen IF info is printed for passing assertions'
Message.tests.cpp:<line number>: failed: false with 2 messages: 'this SHOULD be seen' and 'this SHOULD also be seen'
@@ -2986,7 +2989,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: 450 | 330 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2413 | 2212 passed | 158 failed | 43 failed as expected
test cases: 451 | 331 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2416 | 2215 passed | 158 failed | 43 failed as expected
@@ -1743,6 +1743,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
test cases: 450 | 348 passed | 76 failed | 7 skipped | 19 failed as expected
assertions: 2391 | 2212 passed | 136 failed | 43 failed as expected
test cases: 451 | 349 passed | 76 failed | 7 skipped | 19 failed as expected
assertions: 2394 | 2215 passed | 136 failed | 43 failed as expected
@@ -4241,21 +4241,21 @@ with message:
-------------------------------------------------------------------------------
Directly creating an EnumInfo
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(0) == "Value1" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(0) == "Value1" )
with expansion:
Value1 == "Value1"
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(1) == "Value2" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(1) == "Value2" )
with expansion:
Value2 == "Value2"
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(3) == "{** unexpected enum value **}" )
with expansion:
{** unexpected enum value **}
==
@@ -4299,6 +4299,27 @@ with expansion:
"this string contains 'abc' as a substring" ends with: "this" (case
insensitive)
-------------------------------------------------------------------------------
Enum backed by larger underlying type
-------------------------------------------------------------------------------
EnumToString.tests.cpp:<line number>
...............................................................................
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag1 ) == "Flag1" )
with expansion:
"Flag1" == "Flag1"
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag2 ) == "Flag2" )
with expansion:
"Flag2" == "Flag2"
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag5 ) == "Flag5" )
with expansion:
"Flag5" == "Flag5"
-------------------------------------------------------------------------------
Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
-------------------------------------------------------------------------------
@@ -18383,10 +18404,10 @@ with expansion:
parseEnums
No enums
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) )
with expansion:
{ } Equals: { }
@@ -18395,20 +18416,20 @@ with expansion:
parseEnums
One enum value
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
@@ -18417,20 +18438,20 @@ with expansion:
parseEnums
Multiple enum values
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) )
with expansion:
{ Value1, Value2 } Equals: { Value1, Value2 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
with expansion:
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
with expansion:
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
@@ -20113,6 +20134,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 450 | 330 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2413 | 2212 passed | 158 failed | 43 failed as expected
test cases: 451 | 331 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2416 | 2215 passed | 158 failed | 43 failed as expected
@@ -4239,21 +4239,21 @@ with message:
-------------------------------------------------------------------------------
Directly creating an EnumInfo
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(0) == "Value1" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(0) == "Value1" )
with expansion:
Value1 == "Value1"
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(1) == "Value2" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(1) == "Value2" )
with expansion:
Value2 == "Value2"
ToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo->lookup(3) == "{** unexpected enum value **}" )
EnumToString.tests.cpp:<line number>: PASSED:
CHECK( enumInfo.lookup(3) == "{** unexpected enum value **}" )
with expansion:
{** unexpected enum value **}
==
@@ -4297,6 +4297,27 @@ with expansion:
"this string contains 'abc' as a substring" ends with: "this" (case
insensitive)
-------------------------------------------------------------------------------
Enum backed by larger underlying type
-------------------------------------------------------------------------------
EnumToString.tests.cpp:<line number>
...............................................................................
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag1 ) == "Flag1" )
with expansion:
"Flag1" == "Flag1"
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag2 ) == "Flag2" )
with expansion:
"Flag2" == "Flag2"
EnumToString.tests.cpp:<line number>: PASSED:
REQUIRE( stringify( LargeEnum::Flag5 ) == "Flag5" )
with expansion:
"Flag5" == "Flag5"
-------------------------------------------------------------------------------
Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
-------------------------------------------------------------------------------
@@ -18372,10 +18393,10 @@ with expansion:
parseEnums
No enums
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "" ), Equals( std::vector<Catch::StringRef>{} ) )
with expansion:
{ } Equals: { }
@@ -18384,20 +18405,20 @@ with expansion:
parseEnums
One enum value
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "Value1" ), Equals( std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "EnumName::Value1" ), Equals(std::vector<Catch::StringRef>{"Value1"} ) )
with expansion:
{ Value1 } Equals: { Value1 }
@@ -18406,20 +18427,20 @@ with expansion:
parseEnums
Multiple enum values
-------------------------------------------------------------------------------
ToString.tests.cpp:<line number>
EnumToString.tests.cpp:<line number>
...............................................................................
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2"} ) )
with expansion:
{ Value1, Value2 } Equals: { Value1, Value2 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
with expansion:
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
ToString.tests.cpp:<line number>: PASSED:
EnumToString.tests.cpp:<line number>: PASSED:
CHECK_THAT( parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector<Catch::StringRef>{"Value1", "Value2", "Value3"} ) )
with expansion:
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
@@ -20102,6 +20123,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED:
===============================================================================
test cases: 450 | 330 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2413 | 2212 passed | 158 failed | 43 failed as expected
test cases: 451 | 331 passed | 96 failed | 6 skipped | 18 failed as expected
assertions: 2416 | 2215 passed | 158 failed | 43 failed as expected
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact
>
<testsuite name="<exe-name>" errors="17" failures="141" skipped="12" tests="2425" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="141" skipped="12" tests="2428" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
@@ -506,6 +506,7 @@ with expansion:
at Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Enum backed by larger underlying type" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Epsilon only applies to Approx's value" time="{duration}" status="run"/>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="<exe-name>" errors="17" failures="141" skipped="12" tests="2425" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<testsuite name="<exe-name>" errors="17" failures="141" skipped="12" tests="2428" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties>
<property name="random-seed" value="1"/>
<property name="filters" value="&quot;*&quot; ~[!nonportable] ~[!benchmark] ~[approvals]"/>
@@ -505,6 +505,7 @@ with expansion:
at Matchers.tests.cpp:<line number>
</failure>
</testcase>
<testcase classname="<exe-name>.global" name="Enum backed by larger underlying type" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM" time="{duration}" status="run"/>
<testcase classname="<exe-name>.global" name="Epsilon only applies to Approx's value" time="{duration}" status="run"/>
@@ -422,16 +422,11 @@ at AssertionHandler.tests.cpp:<line number>
<testCase name="Parsing tags with non-alphabetical characters is pass-through" duration="{duration}"/>
</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}"/>
<testCase name="Stringifying char arrays with statically known sizes - unsigned char" duration="{duration}"/>
<testCase name="parseEnums" duration="{duration}"/>
<testCase name="parseEnums/No enums" duration="{duration}"/>
<testCase name="parseEnums/One enum value" duration="{duration}"/>
<testCase name="parseEnums/Multiple enum values" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/IntrospectiveTests/UniquePtr.tests.cpp">
<testCase name="Upcasting special member functions" duration="{duration}"/>
@@ -1079,8 +1074,14 @@ at Decomposition.tests.cpp:<line number>
</testCase>
</file>
<file path="tests/<exe-name>/UsageTests/EnumToString.tests.cpp">
<testCase name="Directly creating an EnumInfo" duration="{duration}"/>
<testCase name="Enum backed by larger underlying type" duration="{duration}"/>
<testCase name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" duration="{duration}"/>
<testCase name="Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM" duration="{duration}"/>
<testCase name="parseEnums" duration="{duration}"/>
<testCase name="parseEnums/No enums" duration="{duration}"/>
<testCase name="parseEnums/One enum value" duration="{duration}"/>
<testCase name="parseEnums/Multiple enum values" duration="{duration}"/>
<testCase name="toString(enum class w/operator&lt;&lt;)" duration="{duration}"/>
<testCase name="toString(enum class)" duration="{duration}"/>
<testCase name="toString(enum w/operator&lt;&lt;)" duration="{duration}"/>
@@ -421,16 +421,11 @@ at AssertionHandler.tests.cpp:<line number>
<testCase name="Parsing tags with non-alphabetical characters is pass-through" duration="{duration}"/>
</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}"/>
<testCase name="Stringifying char arrays with statically known sizes - unsigned char" duration="{duration}"/>
<testCase name="parseEnums" duration="{duration}"/>
<testCase name="parseEnums/No enums" duration="{duration}"/>
<testCase name="parseEnums/One enum value" duration="{duration}"/>
<testCase name="parseEnums/Multiple enum values" duration="{duration}"/>
</file>
<file path="tests/<exe-name>/IntrospectiveTests/UniquePtr.tests.cpp">
<testCase name="Upcasting special member functions" duration="{duration}"/>
@@ -1078,8 +1073,14 @@ at Decomposition.tests.cpp:<line number>
</testCase>
</file>
<file path="tests/<exe-name>/UsageTests/EnumToString.tests.cpp">
<testCase name="Directly creating an EnumInfo" duration="{duration}"/>
<testCase name="Enum backed by larger underlying type" duration="{duration}"/>
<testCase name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" duration="{duration}"/>
<testCase name="Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM" duration="{duration}"/>
<testCase name="parseEnums" duration="{duration}"/>
<testCase name="parseEnums/No enums" duration="{duration}"/>
<testCase name="parseEnums/One enum value" duration="{duration}"/>
<testCase name="parseEnums/Multiple enum values" duration="{duration}"/>
<testCase name="toString(enum class w/operator&lt;&lt;)" duration="{duration}"/>
<testCase name="toString(enum class)" duration="{duration}"/>
<testCase name="toString(enum w/operator&lt;&lt;)" duration="{duration}"/>
+10 -4
View File
@@ -1053,11 +1053,11 @@ ok {test-number} - true with 1 message: 'a'
# Delayed unscoped message clearing does not catch newly inserted messages
not ok {test-number} - false with 1 message: 'b'
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(0) == "Value1" for: Value1 == "Value1"
ok {test-number} - enumInfo.lookup(0) == "Value1" for: Value1 == "Value1"
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(1) == "Value2" for: Value2 == "Value2"
ok {test-number} - enumInfo.lookup(1) == "Value2" for: Value2 == "Value2"
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}"
ok {test-number} - enumInfo.lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}"
# Empty generators can SKIP in constructor
ok {test-number} - # SKIP 'This generator is empty'
# Empty stream name opens cout stream
@@ -1066,6 +1066,12 @@ ok {test-number} - Catch::makeStream( "" )->isConsole() for: true
not ok {test-number} - testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring"
# EndsWith string matcher
not ok {test-number} - testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag1 ) == "Flag1" for: "Flag1" == "Flag1"
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag2 ) == "Flag2" for: "Flag2" == "Flag2"
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag5 ) == "Flag5" for: "Flag5" == "Flag5"
# Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
ok {test-number} - stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1"
# Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
@@ -4845,5 +4851,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2425
1..2428
@@ -1051,11 +1051,11 @@ ok {test-number} - true with 1 message: 'a'
# Delayed unscoped message clearing does not catch newly inserted messages
not ok {test-number} - false with 1 message: 'b'
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(0) == "Value1" for: Value1 == "Value1"
ok {test-number} - enumInfo.lookup(0) == "Value1" for: Value1 == "Value1"
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(1) == "Value2" for: Value2 == "Value2"
ok {test-number} - enumInfo.lookup(1) == "Value2" for: Value2 == "Value2"
# Directly creating an EnumInfo
ok {test-number} - enumInfo->lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}"
ok {test-number} - enumInfo.lookup(3) == "{** unexpected enum value **}" for: {** unexpected enum value **} == "{** unexpected enum value **}"
# Empty generators can SKIP in constructor
ok {test-number} - # SKIP 'This generator is empty'
# Empty stream name opens cout stream
@@ -1064,6 +1064,12 @@ ok {test-number} - Catch::makeStream( "" )->isConsole() for: true
not ok {test-number} - testStringForMatching(), EndsWith( "Substring" ) for: "this string contains 'abc' as a substring" ends with: "Substring"
# EndsWith string matcher
not ok {test-number} - testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) for: "this string contains 'abc' as a substring" ends with: "this" (case insensitive)
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag1 ) == "Flag1" for: "Flag1" == "Flag1"
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag2 ) == "Flag2" for: "Flag2" == "Flag2"
# Enum backed by larger underlying type
ok {test-number} - stringify( LargeEnum::Flag5 ) == "Flag5" for: "Flag5" == "Flag5"
# Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
ok {test-number} - stringify( EnumClass3::Value1 ) == "Value1" for: "Value1" == "Value1"
# Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM
@@ -4834,5 +4840,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} -
# xmlentitycheck
ok {test-number} -
1..2425
1..2428
@@ -338,6 +338,8 @@
##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:<line number>|n...............................................................................|n|nMatchers.tests.cpp:<line number>|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n']
##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:<line number>|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n']
##teamcity[testFinished name='EndsWith string matcher' duration="{duration}"]
##teamcity[testStarted name='Enum backed by larger underlying type']
##teamcity[testFinished name='Enum backed by larger underlying type' duration="{duration}"]
##teamcity[testStarted name='Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM']
##teamcity[testFinished name='Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM' duration="{duration}"]
##teamcity[testStarted name='Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM']
@@ -338,6 +338,8 @@
##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:<line number>|n...............................................................................|n|nMatchers.tests.cpp:<line number>|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "Substring" ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "Substring"|n']
##teamcity[testFailed name='EndsWith string matcher' message='Matchers.tests.cpp:<line number>|nexpression failed|n CHECK_THAT( testStringForMatching(), EndsWith( "this", Catch::CaseSensitive::No ) )|nwith expansion:|n "this string contains |'abc|' as a substring" ends with: "this" (case insensitive)|n']
##teamcity[testFinished name='EndsWith string matcher' duration="{duration}"]
##teamcity[testStarted name='Enum backed by larger underlying type']
##teamcity[testFinished name='Enum backed by larger underlying type' duration="{duration}"]
##teamcity[testStarted name='Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM']
##teamcity[testFinished name='Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM' duration="{duration}"]
##teamcity[testStarted name='Enums in namespaces can quickly have stringification enabled using CATCH_REGISTER_ENUM']
+47 -20
View File
@@ -4743,26 +4743,26 @@ C
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Directly creating an EnumInfo" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<TestCase name="Directly creating an EnumInfo" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(0) == "Value1"
enumInfo.lookup(0) == "Value1"
</Original>
<Expanded>
Value1 == "Value1"
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(1) == "Value2"
enumInfo.lookup(1) == "Value2"
</Original>
<Expanded>
Value2 == "Value2"
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(3) == "{** unexpected enum value **}"
enumInfo.lookup(3) == "{** unexpected enum value **}"
</Original>
<Expanded>
{** unexpected enum value **}
@@ -4808,6 +4808,33 @@ C
</Expression>
<OverallResult success="false" skips="0"/>
</TestCase>
<TestCase name="Enum backed by larger underlying type" tags="[enum][toString]" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag1 ) == "Flag1"
</Original>
<Expanded>
"Flag1" == "Flag1"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag2 ) == "Flag2"
</Original>
<Expanded>
"Flag2" == "Flag2"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag5 ) == "Flag5"
</Original>
<Expanded>
"Flag5" == "Flag5"
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
@@ -21361,9 +21388,9 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="parseEnums" tags="[enums][Strings]" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="No enums" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<TestCase name="parseEnums" tags="[enums][Strings]" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Section name="No enums" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "" ), Equals( std::vector&lt;Catch::StringRef>{} )
</Original>
@@ -21373,8 +21400,8 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="One enum value" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="One enum value" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21382,7 +21409,7 @@ Approx( -1.95996398454005449 )
{ Value1 } Equals: { Value1 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "Value1" ), Equals( std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21390,7 +21417,7 @@ Approx( -1.95996398454005449 )
{ Value1 } Equals: { Value1 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21400,8 +21427,8 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Multiple enum values" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="Multiple enum values" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2"} )
</Original>
@@ -21409,7 +21436,7 @@ Approx( -1.95996398454005449 )
{ Value1, Value2 } Equals: { Value1, Value2 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
</Original>
@@ -21417,7 +21444,7 @@ Approx( -1.95996398454005449 )
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
</Original>
@@ -23358,6 +23385,6 @@ Approx( -1.95996398454005449 )
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<OverallResults successes="2212" failures="158" expectedFailures="43" skips="12"/>
<OverallResultsCases successes="330" failures="96" expectedFailures="18" skips="6"/>
<OverallResults successes="2215" failures="158" expectedFailures="43" skips="12"/>
<OverallResultsCases successes="331" failures="96" expectedFailures="18" skips="6"/>
</Catch2TestRun>
@@ -4743,26 +4743,26 @@ C
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Directly creating an EnumInfo" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<TestCase name="Directly creating an EnumInfo" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(0) == "Value1"
enumInfo.lookup(0) == "Value1"
</Original>
<Expanded>
Value1 == "Value1"
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(1) == "Value2"
enumInfo.lookup(1) == "Value2"
</Original>
<Expanded>
Value2 == "Value2"
</Expanded>
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
enumInfo->lookup(3) == "{** unexpected enum value **}"
enumInfo.lookup(3) == "{** unexpected enum value **}"
</Original>
<Expanded>
{** unexpected enum value **}
@@ -4808,6 +4808,33 @@ C
</Expression>
<OverallResult success="false" skips="0"/>
</TestCase>
<TestCase name="Enum backed by larger underlying type" tags="[enum][toString]" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag1 ) == "Flag1"
</Original>
<Expanded>
"Flag1" == "Flag1"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag2 ) == "Flag2"
</Original>
<Expanded>
"Flag2" == "Flag2"
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
stringify( LargeEnum::Flag5 ) == "Flag5"
</Original>
<Expanded>
"Flag5" == "Flag5"
</Expanded>
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="Enums can quickly have stringification enabled using CATCH_REGISTER_ENUM" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
@@ -21360,9 +21387,9 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResult success="true" skips="0"/>
</TestCase>
<TestCase name="parseEnums" tags="[enums][Strings]" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="No enums" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<TestCase name="parseEnums" tags="[enums][Strings]" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Section name="No enums" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "" ), Equals( std::vector&lt;Catch::StringRef>{} )
</Original>
@@ -21372,8 +21399,8 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="One enum value" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="One enum value" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21381,7 +21408,7 @@ Approx( -1.95996398454005449 )
{ Value1 } Equals: { Value1 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "Value1" ), Equals( std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21389,7 +21416,7 @@ Approx( -1.95996398454005449 )
{ Value1 } Equals: { Value1 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "EnumName::Value1" ), Equals(std::vector&lt;Catch::StringRef>{"Value1"} )
</Original>
@@ -21399,8 +21426,8 @@ Approx( -1.95996398454005449 )
</Expression>
<OverallResults successes="3" failures="0" expectedFailures="0" skipped="false"/>
</Section>
<Section name="Multiple enum values" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Section name="Multiple enum values" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2"} )
</Original>
@@ -21408,7 +21435,7 @@ Approx( -1.95996398454005449 )
{ Value1, Value2 } Equals: { Value1, Value2 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1, ClassName::EnumName::Value2, ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
</Original>
@@ -21416,7 +21443,7 @@ Approx( -1.95996398454005449 )
{ Value1, Value2, Value3 } Equals: { Value1, Value2, Value3 }
</Expanded>
</Expression>
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/IntrospectiveTests/ToString.tests.cpp" >
<Expression success="true" type="CHECK_THAT" filename="tests/<exe-name>/UsageTests/EnumToString.tests.cpp" >
<Original>
parseEnums( "ClassName::EnumName::Value1,ClassName::EnumName::Value2 , ClassName::EnumName::Value3" ), Equals( std::vector&lt;Catch::StringRef>{"Value1", "Value2", "Value3"} )
</Original>
@@ -23357,6 +23384,6 @@ Approx( -1.95996398454005449 )
</Section>
<OverallResult success="true" skips="0"/>
</TestCase>
<OverallResults successes="2212" failures="158" expectedFailures="43" skips="12"/>
<OverallResultsCases successes="330" failures="96" expectedFailures="18" skips="6"/>
<OverallResults successes="2215" failures="158" expectedFailures="43" skips="12"/>
<OverallResultsCases successes="331" failures="96" expectedFailures="18" skips="6"/>
</Catch2TestRun>
@@ -39,8 +39,8 @@ namespace {
// -------------------------
// | a | b | c | d |
#define CarryBits( x ) ( x >> 32 )
#define Digits( x ) ( x & 0xFF'FF'FF'FF )
#define CarryBits( x ) ( (x) >> 32 )
#define Digits( x ) ( (x) & 0xFF'FF'FF'FF )
auto r2l2 = Digits( rhs ) * Digits( lhs );
auto r2l1 = Digits( rhs ) * CarryBits( lhs );
@@ -12,6 +12,7 @@
#include <catch2/catch_config.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_console_colour.hpp>
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_list.hpp>
@@ -437,6 +437,25 @@ TEST_CASE( "TextFlow::AnsiSkippingString iterates UTF-8 codepoints",
}
}
TEST_CASE( "TextFlow::AnsiSkippingString handles invalid UTF-8",
"[TextFlow][ansiskippingstring][approvals]" ) {
SECTION( "Continuation byte at the start" ) {
// 0x80 is a continuation byte
AnsiSkippingString str( "\x80" );
auto it = str.end();
--it;
CHECK( it == str.begin() );
CHECK( *it == static_cast<char>( 0x80 ) );
}
SECTION( "Multiple continuation bytes at the start" ) {
AnsiSkippingString str( "\x80\x80\x80" );
auto it = str.end();
--it;
CHECK( it == str.begin() );
CHECK( *it == static_cast<char>( 0x80 ) );
}
}
TEST_CASE( "TextFlow::Column wraps UTF-8 text correctly",
"[TextFlow][column][approvals]" ) {
// "äöü äöü äöü" = 11 codepoints, 17 bytes

Some files were not shown because too many files have changed in this diff Show More