mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 16:35:40 +02:00
Compare commits
97 Commits
v3.2.1
...
devel-refa
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5db31e587e | ||
![]() |
f3960c02ce | ||
![]() |
02ce0a2eec | ||
![]() |
cf4d84a349 | ||
![]() |
cfe859e0f3 | ||
![]() |
31b291ba26 | ||
![]() |
ceb7ab6b20 | ||
![]() |
2598116aa6 | ||
![]() |
173aa3f1f4 | ||
![]() |
28437e1214 | ||
![]() |
3c8fb6bbb2 | ||
![]() |
72f3ce4db5 | ||
![]() |
62167d756e | ||
![]() |
6783411349 | ||
![]() |
7b4dd326c0 | ||
![]() |
1dfaa8abe7 | ||
![]() |
ba94278bdd | ||
![]() |
8e5a4b6f70 | ||
![]() |
9b884d8107 | ||
![]() |
8a1b3b81cb | ||
![]() |
e5aabb6714 | ||
![]() |
3a1ef14097 | ||
![]() |
13fae1e2ff | ||
![]() |
3220ae6d4a | ||
![]() |
0a0ebf5003 | ||
![]() |
69f35a5ac8 | ||
![]() |
3f0283de7a | ||
![]() |
6fbb3f0723 | ||
![]() |
9ff3cde87b | ||
![]() |
4d802ca58f | ||
![]() |
13711be7cf | ||
![]() |
27ba26f743 | ||
![]() |
a209bcfb54 | ||
![]() |
584973a485 | ||
![]() |
4f7c8cb28a | ||
![]() |
e1dbad4c9e | ||
![]() |
2befd98da2 | ||
![]() |
00f259aeb2 | ||
![]() |
fed1436246 | ||
![]() |
0477326ad9 | ||
![]() |
f04c93462b | ||
![]() |
1af351cea1 | ||
![]() |
dcc9fa3f38 | ||
![]() |
bf6a15a69a | ||
![]() |
6135a78c31 | ||
![]() |
e8ba329b6c | ||
![]() |
4aa88299af | ||
![]() |
4ff9be3bc5 | ||
![]() |
76cdaa3b51 | ||
![]() |
644294df60 | ||
![]() |
cefa8fcf32 | ||
![]() |
772fa3f790 | ||
![]() |
f3c0a3cd09 | ||
![]() |
42d9d4533e | ||
![]() |
618d44c448 | ||
![]() |
388f7e1737 | ||
![]() |
2ab20a0e00 | ||
![]() |
60264b8807 | ||
![]() |
65ffee5189 | ||
![]() |
43f02027e4 | ||
![]() |
906552f8c8 | ||
![]() |
356dfc1439 | ||
![]() |
e5d1eb757f | ||
![]() |
2403f5620e | ||
![]() |
d58491c85a | ||
![]() |
c837cb4a8a | ||
![]() |
8359a6b244 | ||
![]() |
adf43494e1 | ||
![]() |
efca9a0f18 | ||
![]() |
dd36f83b88 | ||
![]() |
baab9e8d28 | ||
![]() |
2d3c9713a3 | ||
![]() |
956f915e31 | ||
![]() |
aa8da505ec | ||
![]() |
e27bb7198d | ||
![]() |
3486f8ed9e | ||
![]() |
b5be642042 | ||
![]() |
d59572f46f | ||
![]() |
16f48f8c7c | ||
![]() |
367c2cb248 | ||
![]() |
d548be26e3 | ||
![]() |
52066dbc2a | ||
![]() |
cdf604f30e | ||
![]() |
04382af4c6 | ||
![]() |
ac93f19437 | ||
![]() |
72b60dfd28 | ||
![]() |
0c62167fea | ||
![]() |
1be954ff70 | ||
![]() |
78bb4fda05 | ||
![]() |
e6ec1c238b | ||
![]() |
477c1f5152 | ||
![]() |
f8b9f77259 | ||
![]() |
77fbacb03f | ||
![]() |
e3fc97dffb | ||
![]() |
9c0533a905 | ||
![]() |
ed02710b83 | ||
![]() |
8b84438be4 |
@@ -4,41 +4,42 @@ Standard: c++14
|
||||
|
||||
# Note that we cannot use IncludeIsMainRegex functionality, because it
|
||||
# does not support includes in angle brackets (<>)
|
||||
SortIncludes: True
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '<catch2/.*\.hpp>'
|
||||
- Regex: <catch2/.*\.hpp>
|
||||
Priority: 1
|
||||
- Regex: '<.*/.*\.hpp>'
|
||||
- Regex: <.*/.*\.hpp>
|
||||
Priority: 2
|
||||
- Regex: '<.*>'
|
||||
- Regex: <.*>
|
||||
Priority: 3
|
||||
|
||||
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
|
||||
AccessModifierOffset: '-4'
|
||||
AccessModifierOffset: "-4"
|
||||
AlignEscapedNewlines: Left
|
||||
AllowAllConstructorInitializersOnNextLine: 'true'
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
AllowAllConstructorInitializersOnNextLine: "true"
|
||||
BinPackArguments: "false"
|
||||
BinPackParameters: "false"
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
DerivePointerAlignment: 'false'
|
||||
FixNamespaceComments: 'true'
|
||||
IndentCaseLabels: 'false'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: "true"
|
||||
DerivePointerAlignment: "false"
|
||||
FixNamespaceComments: "true"
|
||||
IndentCaseLabels: "false"
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: '4'
|
||||
IndentWidth: "4"
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Left
|
||||
SpaceBeforeCtorInitializerColon: 'false'
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesInParentheses: 'true'
|
||||
TabWidth: '4'
|
||||
SpaceBeforeCtorInitializerColon: "false"
|
||||
SpaceInEmptyParentheses: "false"
|
||||
SpacesInParentheses: "true"
|
||||
TabWidth: "4"
|
||||
UseTab: Never
|
||||
|
||||
...
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SortUsingDeclarations: true
|
||||
ReflowComments: true
|
||||
|
37
.github/workflows/windows-simple-builds.yml
vendored
Normal file
37
.github/workflows/windows-simple-builds.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Windows builds (basic)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{matrix.os}}, ${{matrix.std}}, ${{matrix.build_type}}, ${{matrix.platform}}
|
||||
runs-on: ${{matrix.os}}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-2019, windows-2022]
|
||||
platform: [Win32, x64]
|
||||
build_type: [Debug, Release]
|
||||
std: [14, 17]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Configure build
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: |
|
||||
cmake -S $Env:GITHUB_WORKSPACE `
|
||||
-B ${{runner.workspace}}/build `
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} `
|
||||
-A ${{matrix.platform}} `
|
||||
--preset all-tests
|
||||
|
||||
- name: Build tests
|
||||
working-directory: ${{runner.workspace}}
|
||||
run: cmake --build build --config ${{matrix.build_type}} --parallel %NUMBER_OF_PROCESSORS%
|
||||
shell: cmd
|
||||
|
||||
- name: Run tests
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest -C ${{matrix.build_type}} -j %NUMBER_OF_PROCESSORS%
|
||||
shell: cmd
|
@@ -31,7 +31,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
endif()
|
||||
|
||||
project(Catch2
|
||||
VERSION 3.2.1 # CML version placeholder, don't delete
|
||||
VERSION 3.3.2 # CML version placeholder, don't delete
|
||||
LANGUAGES CXX
|
||||
# HOMEPAGE_URL is not supported until CMake version 3.12, which
|
||||
# we do not target yet.
|
||||
@@ -148,6 +148,8 @@ if (NOT_SUBPROJECT)
|
||||
"extras/ParseAndAddCatchTests.cmake"
|
||||
"extras/Catch.cmake"
|
||||
"extras/CatchAddTests.cmake"
|
||||
"extras/CatchShardTests.cmake"
|
||||
"extras/CatchShardTestsImpl.cmake"
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
2
Doxyfile
2
Doxyfile
@@ -1319,7 +1319,7 @@ CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
|
||||
# The GENERATE_CHI flag controls if a separate .chi index file is generated
|
||||
# (YES) or that it should be included in the master .chm file (NO).
|
||||
# (YES) or that it should be included in the main .chm file (NO).
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
||||
|
||||
|
20
README.md
20
README.md
@@ -47,24 +47,28 @@ TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
||||
#include <cstdint>
|
||||
|
||||
uint64_t fibonacci(uint64_t number) {
|
||||
return number < 2 ? 1 : fibonacci(number - 1) + fibonacci(number - 2);
|
||||
return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark Fibonacci", "[!benchmark]") {
|
||||
REQUIRE(Fibonacci(5) == 5);
|
||||
REQUIRE(fibonacci(5) == 5);
|
||||
|
||||
REQUIRE(Fibonacci(20) == 6'765);
|
||||
BENCHMARK("Fibonacci 20") {
|
||||
return Fibonacci(20);
|
||||
REQUIRE(fibonacci(20) == 6'765);
|
||||
BENCHMARK("fibonacci 20") {
|
||||
return fibonacci(20);
|
||||
};
|
||||
|
||||
REQUIRE(Fibonacci(25) == 75'025);
|
||||
BENCHMARK("Fibonacci 25") {
|
||||
return Fibonacci(25);
|
||||
REQUIRE(fibonacci(25) == 75'025);
|
||||
BENCHMARK("fibonacci 25") {
|
||||
return fibonacci(25);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
_Note that benchmarks are not run by default, so you need to run it explicitly
|
||||
with the `[!benchmark]` tag._
|
||||
|
||||
|
||||
## Catch2 v3 has been released!
|
||||
|
||||
You are on the `devel` branch, where the v3 version is being developed.
|
||||
|
@@ -4,12 +4,13 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
sha256 = "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz",
|
||||
],
|
||||
sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506",
|
||||
)
|
||||
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
|
||||
bazel_skylib_workspace()
|
||||
|
48
appveyor.yml
48
appveyor.yml
@@ -51,18 +51,6 @@ test_script:
|
||||
# build explicitly.
|
||||
environment:
|
||||
matrix:
|
||||
- FLAVOR: VS 2019 x64 Debug Surrogates Configure Tests
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
surrogates: 1
|
||||
configure_tests: 1
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2019 x64 Release
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
platform: x64
|
||||
configuration: Release
|
||||
|
||||
- FLAVOR: VS 2019 x64 Debug Coverage Examples
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
examples: 1
|
||||
@@ -77,11 +65,6 @@ environment:
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2019 Win32 Debug
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2019 x64 Debug Latest Strict
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
@@ -92,38 +75,9 @@ environment:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2017 x64 Release
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: x64
|
||||
configuration: Release
|
||||
|
||||
- FLAVOR: VS 2017 x64 Release Coverage
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
coverage: 1
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2017 Win32 Debug
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2017 Win32 Debug Examples
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
examples: 1
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2017 Win32 Debug WMain
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
wmain: 1
|
||||
additional_flags: "/D_UNICODE /DUNICODE"
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
|
||||
- FLAVOR: VS 2017 x64 Debug Latest Strict
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
configuration: Debug
|
@@ -11,6 +11,7 @@ Once you're up and running consider the following reference material.
|
||||
* [Logging macros](logging.md#top)
|
||||
* [Test cases and sections](test-cases-and-sections.md#top)
|
||||
* [Test fixtures](test-fixtures.md#top)
|
||||
* [Explicitly skipping, passing, and failing tests at runtime](skipping-passing-failing.md#top)
|
||||
* [Reporters (output customization)](reporters.md#top)
|
||||
* [Event Listeners](event-listeners.md#top)
|
||||
* [Data Generators (value parameterized tests)](generators.md#top)
|
||||
|
@@ -90,12 +90,12 @@ cmake_minimum_required(VERSION 3.5)
|
||||
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||
|
||||
find_package(Catch2 REQUIRED)
|
||||
add_executable(foo test.cpp)
|
||||
target_link_libraries(foo PRIVATE Catch2::Catch2)
|
||||
add_executable(tests test.cpp)
|
||||
target_link_libraries(tests PRIVATE Catch2::Catch2)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(foo)
|
||||
catch_discover_tests(tests)
|
||||
```
|
||||
|
||||
When using `FetchContent`, `include(Catch)` will fail unless
|
||||
@@ -108,7 +108,7 @@ directory.
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests()
|
||||
catch_discover_tests(tests)
|
||||
```
|
||||
|
||||
#### Customization
|
||||
@@ -222,12 +222,12 @@ cmake_minimum_required(VERSION 3.5)
|
||||
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||
|
||||
find_package(Catch2 REQUIRED)
|
||||
add_executable(foo test.cpp)
|
||||
target_link_libraries(foo PRIVATE Catch2::Catch2)
|
||||
add_executable(tests test.cpp)
|
||||
target_link_libraries(tests PRIVATE Catch2::Catch2)
|
||||
|
||||
include(CTest)
|
||||
include(ParseAndAddCatchTests)
|
||||
ParseAndAddCatchTests(foo)
|
||||
ParseAndAddCatchTests(tests)
|
||||
```
|
||||
|
||||
|
||||
|
@@ -148,7 +148,7 @@ validity, and throw an error if they are wrong._
|
||||
> Support for passing arguments to reporters through the `-r`, `--reporter` flag was introduced in Catch2 3.0.1
|
||||
|
||||
There are multiple built-in reporters, you can see what they do by using the
|
||||
[`--list-reporter`](command-line.md#listing-available-tests-tags-or-reporters)
|
||||
[`--list-reporters`](command-line.md#listing-available-tests-tags-or-reporters)
|
||||
flag. If you need a reporter providing custom format outside of the already
|
||||
provided ones, look at the ["write your own reporter" part of the reporter
|
||||
documentation](reporters.md#writing-your-own-reporter).
|
||||
@@ -507,10 +507,13 @@ start of the first section.</br>
|
||||
## Filenames as tags
|
||||
<pre>-#, --filenames-as-tags</pre>
|
||||
|
||||
When this option is used then every test is given an additional tag which is formed of the unqualified
|
||||
filename it is found in, with any extension stripped, prefixed with the `#` character.
|
||||
This option adds an extra tag to all test cases. The tag is `#` followed
|
||||
by the unqualified filename the test case is defined in, with the _last_
|
||||
extension stripped out.
|
||||
|
||||
For example, tests within the file `tests\SelfTest\UsageTests\BDD.tests.cpp`
|
||||
will be given the `[#BDD.tests]` tag.
|
||||
|
||||
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
||||
|
||||
<a id="colour-mode"></a>
|
||||
## Override output colouring
|
||||
@@ -561,10 +564,10 @@ processes, as is done with the [Bazel test sharding](https://docs.bazel.build/ve
|
||||
|
||||
> Introduced in Catch2 3.0.1.
|
||||
|
||||
By default, Catch2 test binaries return non-0 exit code if no tests were
|
||||
run, e.g. if the binary was compiled with no tests, or the provided test
|
||||
spec matched no tests. This flag overrides that, so a test run with no
|
||||
tests still returns 0.
|
||||
By default, Catch2 test binaries return non-0 exit code if no tests were run,
|
||||
e.g. if the binary was compiled with no tests, the provided test spec matched no
|
||||
tests, or all tests [were skipped at runtime](skipping-passing-failing.md#top). This flag
|
||||
overrides that, so a test run with no tests still returns 0.
|
||||
|
||||
## Output verbosity
|
||||
```
|
||||
|
@@ -55,6 +55,15 @@ tests from `SelfTest` through a specific reporter and then compare the
|
||||
generated output with a known good output ("Baseline"). By default, new
|
||||
tests should be placed here.
|
||||
|
||||
To configure a Catch2 build with just the basic tests, use the `basic-tests`
|
||||
preset, like so:
|
||||
|
||||
```
|
||||
# Assuming you are in Catch2's root folder
|
||||
|
||||
cmake -B basic-test-build -S . -DCMAKE_BUILD_TYPE=Debug --preset basic-tests
|
||||
```
|
||||
|
||||
However, not all tests can be written as plain unit tests. For example,
|
||||
checking that Catch2 orders tests randomly when asked to, and that this
|
||||
random ordering is subset-invariant, is better done as an integration
|
||||
@@ -76,21 +85,23 @@ configuration and require separate compilation.
|
||||
Finally, CMake config tests test that you set Catch2's compile-time
|
||||
configuration options through CMake, using CMake options of the same name.
|
||||
|
||||
None of these tests are enabled by default. To enable them, add
|
||||
These test categories can be enabled one by one, by passing
|
||||
`-DCATCH_BUILD_EXAMPLES=ON`, `-DCATCH_BUILD_EXTRA_TESTS=ON`, and
|
||||
`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuration the CMake build.
|
||||
`-DCATCH_ENABLE_CONFIGURE_TESTS=ON` when configuring the build.
|
||||
|
||||
Bringing this all together, the steps below should configure, build,
|
||||
and run all tests in the `Debug` compilation.
|
||||
Catch2 also provides a preset that promises to enable _all_ test types,
|
||||
`all-tests`.
|
||||
|
||||
The snippet below will build & run all tests, in `Debug` compilation mode.
|
||||
|
||||
<!-- snippet: catch2-build-and-test -->
|
||||
<a id='snippet-catch2-build-and-test'></a>
|
||||
```sh
|
||||
# 1. Regenerate the amalgamated distribution
|
||||
# 1. Regenerate the amalgamated distribution (some tests are built against it)
|
||||
./tools/scripts/generateAmalgamatedFiles.py
|
||||
|
||||
# 2. Configure the full test build
|
||||
cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_DEVELOPMENT_BUILD=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON
|
||||
cmake -B debug-build -S . -DCMAKE_BUILD_TYPE=Debug --preset all-tests
|
||||
|
||||
# 3. Run the actual build
|
||||
cmake --build debug-build
|
||||
|
@@ -26,6 +26,15 @@ to accurately probe the environment for this information so the flag
|
||||
where it will export `BAZEL_TEST=1` for purposes like the above. Catch2
|
||||
will now instead inspect the environment instead of relying on build configuration.
|
||||
|
||||
### `IEventLister::skipTest( TestCaseInfo const& testInfo )`
|
||||
|
||||
This event (including implementations in derived classes such as `ReporterBase`)
|
||||
is deprecated and will be removed in the next major release. It is currently
|
||||
invoked for all test cases that are not going to be executed due to the test run
|
||||
being aborted (when using `--abort` or `--abortx`). It is however
|
||||
**NOT** invoked for test cases that are [explicitly skipped using the `SKIP`
|
||||
macro](skipping-passing-failing.md#top).
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
||||
|
@@ -205,13 +205,17 @@ struct IGenerator : GeneratorUntypedBase {
|
||||
// Precondition:
|
||||
// The generator is either freshly constructed or the last call to next() returned true
|
||||
virtual T const& get() const = 0;
|
||||
|
||||
// Returns user-friendly string showing the current generator element
|
||||
// Does not have to be overridden, IGenerator provides default implementation
|
||||
virtual std::string stringifyImpl() const;
|
||||
};
|
||||
```
|
||||
|
||||
However, to be able to use your custom generator inside `GENERATE`, it
|
||||
will need to be wrapped inside a `GeneratorWrapper<T>`.
|
||||
`GeneratorWrapper<T>` is a value wrapper around a
|
||||
`std::unique_ptr<IGenerator<T>>`.
|
||||
`Catch::Detail::unique_ptr<IGenerator<T>>`.
|
||||
|
||||
For full example of implementing your own generator, look into Catch2's
|
||||
examples, specifically
|
||||
|
@@ -88,8 +88,8 @@ because only one thread passes the `REQUIRE` macro and this is not
|
||||
REQUIRE(cnt == 16);
|
||||
```
|
||||
|
||||
Because C++11 provides the necessary tools to do this, we are planning
|
||||
to remove this limitation in the future.
|
||||
We currently do not plan to support thread-safe assertions.
|
||||
|
||||
|
||||
### Process isolation in a test
|
||||
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
||||
@@ -155,7 +155,7 @@ with expansion:
|
||||
|
||||
|
||||
### Clang/G++ -- skipping leaf sections after an exception
|
||||
Some versions of `libc++` and `libstdc++` (or their runtimes) have a bug with `std::uncaught_exception()` getting stuck returning `true` after rethrow, even if there are no active exceptions. One such case is this snippet, which skipped the sections "a" and "b", when compiled against `libcxxrt` from master
|
||||
Some versions of `libc++` and `libstdc++` (or their runtimes) have a bug with `std::uncaught_exception()` getting stuck returning `true` after rethrow, even if there are no active exceptions. One such case is this snippet, which skipped the sections "a" and "b", when compiled against `libcxxrt` from the master branch
|
||||
```cpp
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
|
@@ -141,18 +141,27 @@ are a permutation of the ones in `some_vec`.
|
||||
|
||||
### Floating point matchers
|
||||
|
||||
Catch2 provides 3 matchers that target floating point numbers. These
|
||||
Catch2 provides 4 matchers that target floating point numbers. These
|
||||
are:
|
||||
|
||||
* `WithinAbs(double target, double margin)`,
|
||||
* `WithinULP(FloatingPoint target, uint64_t maxUlpDiff)`, and
|
||||
* `WithinRel(FloatingPoint target, FloatingPoint eps)`.
|
||||
* `IsNaN()`
|
||||
|
||||
> `WithinRel` matcher was introduced in Catch2 2.10.0
|
||||
|
||||
For more details, read [the docs on comparing floating point
|
||||
> `IsNaN` matcher was introduced in Catch2 3.3.2.
|
||||
|
||||
The first three serve to compare two floating pointe numbers. For more
|
||||
details about how they work, read [the docs on comparing floating point
|
||||
numbers](comparing-floating-point-numbers.md#floating-point-matchers).
|
||||
|
||||
`IsNaN` then does exactly what it says on the tin. It matches the input
|
||||
if it is a NaN (Not a Number). The advantage of using it over just plain
|
||||
`REQUIRE(std::isnan(x))`, is that if the check fails, with `REQUIRE` you
|
||||
won't see the value of `x`, but with `REQUIRE_THAT(x, IsNaN())`, you will.
|
||||
|
||||
|
||||
### Miscellaneous matchers
|
||||
|
||||
@@ -190,13 +199,23 @@ properties. The macro is `REQUIRE_THROWS_MATCHES(expr, ExceptionType, Matcher)`.
|
||||
> `REQUIRE_THROWS_MATCHES` macro lives in `catch2/matchers/catch_matchers.hpp`
|
||||
|
||||
|
||||
Catch2 currently provides only one matcher for exceptions,
|
||||
`Message(std::string message)`. `Message` checks that the exception's
|
||||
Catch2 currently provides two matchers for exceptions.
|
||||
These are:
|
||||
* `Message(std::string message)`.
|
||||
* `MessageMatches(Matcher matcher)`.
|
||||
|
||||
> `MessageMatches` was [introduced](https://github.com/catchorg/Catch2/pull/2570) in Catch2 3.3.0
|
||||
|
||||
`Message` checks that the exception's
|
||||
message, as returned from `what` is exactly equal to `message`.
|
||||
|
||||
`MessageMatches` applies the provided matcher on the exception's
|
||||
message, as returned from `what`. This is useful in conjunctions with the `std::string` matchers (e.g. `StartsWith`)
|
||||
|
||||
Example use:
|
||||
```cpp
|
||||
REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, Message("DerivedException::what"));
|
||||
REQUIRE_THROWS_MATCHES(throwsDerivedException(), DerivedException, MessageMatches(StartsWith("DerivedException")));
|
||||
```
|
||||
|
||||
Note that `DerivedException` in the example above has to derive from
|
||||
@@ -218,11 +237,19 @@ definitions to handle generic range-like types. These are:
|
||||
* `Contains(T&& target_element, Comparator = std::equal_to<>{})`
|
||||
* `Contains(Matcher element_matcher)`
|
||||
* `AllMatch(Matcher element_matcher)`
|
||||
* `NoneMatch(Matcher element_matcher)`
|
||||
* `AnyMatch(Matcher element_matcher)`
|
||||
* `AllTrue()`
|
||||
* `NoneTrue()`
|
||||
* `AnyTrue()`
|
||||
* `NoneMatch(Matcher element_matcher)`
|
||||
* `AllTrue()`, `AnyTrue()`, `NoneTrue()`
|
||||
* `RangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})`
|
||||
* `UnorderedRangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})`
|
||||
|
||||
> `IsEmpty`, `SizeIs`, `Contains` were introduced in Catch2 3.0.1
|
||||
|
||||
> `All/Any/NoneMatch` were introduced in Catch2 3.0.1
|
||||
|
||||
> `All/Any/NoneTrue` were introduced in Catch2 3.1.0
|
||||
|
||||
> `RangeEquals` and `UnorderedRangeEquals` matchers were [introduced](https://github.com/catchorg/Catch2/pull/2377) in Catch2 3.3.0
|
||||
|
||||
`IsEmpty` should be self-explanatory. It successfully matches objects
|
||||
that are empty according to either `std::empty`, or ADL-found `empty`
|
||||
@@ -249,6 +276,25 @@ all, none, or any of the contained elements are `true`, respectively.
|
||||
It works for ranges of `bool`s and ranges of elements (explicitly)
|
||||
convertible to `bool`.
|
||||
|
||||
`RangeEquals` compares the range that the matcher is constructed with
|
||||
(the "target range") against the range to be tested, element-wise. The
|
||||
match succeeds if all elements from the two ranges compare equal (using
|
||||
`operator==` by default). The ranges do not need to be the same type,
|
||||
and the element types do not need to be the same, as long as they are
|
||||
comparable. (e.g. you may compare `std::vector<int>` to `std::array<char>`).
|
||||
|
||||
`UnorderedRangeEquals` is similar to `RangeEquals`, but the order
|
||||
does not matter. For example "1, 2, 3" would match "3, 2, 1", but not
|
||||
"1, 1, 2, 3" As with `RangeEquals`, `UnorderedRangeEquals` compares
|
||||
the individual elements using using `operator==` by default.
|
||||
|
||||
Both `RangeEquals` and `UnorderedRangeEquals` optionally accept a
|
||||
predicate which can be used to compare the containers element-wise.
|
||||
|
||||
To check a container elementwise against a given matcher, use
|
||||
`AllMatch`.
|
||||
|
||||
|
||||
## Writing custom matchers (old style)
|
||||
|
||||
The old style of writing matchers has been introduced back in Catch
|
||||
|
@@ -110,6 +110,12 @@ A header-only TOML parser and serializer for modern C++.
|
||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||
A thread-safe header-only mocking framework for C++14.
|
||||
|
||||
### [wxWidgets](https://www.wxwidgets.org/)
|
||||
Cross-Platform C++ GUI Library.
|
||||
|
||||
### [xmlwrapp](https://github.com/vslavik/xmlwrapp)
|
||||
C++ XML parsing library using libxml2.
|
||||
|
||||
## Applications & Tools
|
||||
|
||||
### [App Mesh](https://github.com/laoshanxi/app-mesh)
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
# Release notes
|
||||
**Contents**<br>
|
||||
[3.3.2](#332)<br>
|
||||
[3.3.1](#331)<br>
|
||||
[3.3.0](#330)<br>
|
||||
[3.2.1](#321)<br>
|
||||
[3.2.0](#320)<br>
|
||||
[3.1.1](#311)<br>
|
||||
@@ -54,6 +57,67 @@
|
||||
|
||||
|
||||
|
||||
## 3.3.2
|
||||
|
||||
### Improvements
|
||||
* Further reduced allocations
|
||||
* The compact, console, TAP and XML reporters perform less allocations in various cases
|
||||
* Removed 1 allocation per entered `SECTION`/`TEST_CASE`.
|
||||
* Removed 2 allocations per test case exit, if stdout/stderr is captured
|
||||
* Improved performance
|
||||
* Section tracking is 10%-25% faster than in v3.3.0
|
||||
* Assertion handling is 5%-10% faster than in v3.3.0
|
||||
* Test case registration is 1%-2% faster than in v3.3.0
|
||||
* Tiny speedup for registering listeners
|
||||
* Tiny speedup for `CAPTURE`, `TEST_CASE_METHOD`, `METHOD_AS_TEST_CASE`, and `TEMPLATE_LIST_TEST_*` macros.
|
||||
* `Contains`, `RangeEquals` and `UnorderedRangeEquals` matchers now support ranges with iterator + sentinel pair
|
||||
* Added `IsNaN` matcher
|
||||
* Unlike `REQUIRE(isnan(x))`, `REQUIRE_THAT(x, IsNaN())` shows you the value of `x`.
|
||||
* Suppressed `declared_but_not_referenced` warning for NVHPC (#2637)
|
||||
|
||||
### Fixes
|
||||
* Fixed performance regression in section tracking introduced in v3.3.1
|
||||
* Extreme cases would cause the tracking to run about 4x slower than in 3.3.0
|
||||
|
||||
|
||||
## 3.3.1
|
||||
|
||||
### Improvements
|
||||
* Reduced allocations and improved performance
|
||||
* The exact improvements are dependent on your usage of Catch2.
|
||||
* For example running Catch2's SelfTest binary performs 8k less allocations.
|
||||
* The main improvement comes from smarter handling of `SECTION`s, especially sibling `SECTION`s
|
||||
|
||||
|
||||
## 3.3.0
|
||||
|
||||
### Improvements
|
||||
|
||||
* Added `MessageMatches` exception matcher (#2570)
|
||||
* Added `RangeEquals` and `UnorderedRangeEquals` generic range matchers (#2377)
|
||||
* Added `SKIP` macro for skipping tests from within the test body (#2360)
|
||||
* All built-in reporters have been extended to handle it properly, whether your custom reporter needs changes depends on how it was written
|
||||
* `skipTest` reporter event **is unrelated** to this, and has been deprecated since it has practically no uses
|
||||
* Restored support for PPC Macs in the break-into-debugger functionality (#2619)
|
||||
* Made our warning suppression compatible with CUDA toolkit pre 11.5 (#2626)
|
||||
* Cleaned out some static analysis complaints
|
||||
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fixed macro redefinition warning when NVCC was reporting as MSVC (#2603)
|
||||
* Fixed throws in generator constructor causing the whole binary to abort (#2615)
|
||||
* Now it just fails the test
|
||||
* Fixed missing transitive include with libstdc++13 (#2611)
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* Improved support for dynamic library build with non-MSVC compilers on Windows (#2630)
|
||||
* When used as a subproject, Catch2 keeps its generated header in a separate directory from the main project (#2604)
|
||||
|
||||
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Improvements
|
||||
|
129
docs/skipping-passing-failing.md
Normal file
129
docs/skipping-passing-failing.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<a id="top"></a>
|
||||
# Explicitly skipping, passing, and failing tests at runtime
|
||||
|
||||
## Skipping Test Cases at Runtime
|
||||
|
||||
> [Introduced](https://github.com/catchorg/Catch2/pull/2360) in Catch2 3.3.0.
|
||||
|
||||
In some situations it may not be possible to meaningfully execute a test case,
|
||||
for example when the system under test is missing certain hardware capabilities.
|
||||
If the required conditions can only be determined at runtime, it often
|
||||
doesn't make sense to consider such a test case as either passed or failed,
|
||||
because it simply can not run at all.
|
||||
|
||||
To properly express such scenarios, Catch2 provides a way to explicitly
|
||||
_skip_ test cases, using the `SKIP` macro:
|
||||
|
||||
```
|
||||
SKIP( [streamable expression] )
|
||||
```
|
||||
|
||||
Example usage:
|
||||
|
||||
```c++
|
||||
TEST_CASE("copy files between drives") {
|
||||
if(getNumberOfHardDrives() < 2) {
|
||||
SKIP("at least two hard drives required");
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This test case is then reported as _skipped_ instead of _passed_ or _failed_.
|
||||
|
||||
The `SKIP` macro behaves similarly to an explicit [`FAIL`](#passing-and-failing-test-cases),
|
||||
in that it is the last expression that will be executed:
|
||||
|
||||
```c++
|
||||
TEST_CASE("my test") {
|
||||
printf("foo");
|
||||
SKIP();
|
||||
printf("bar"); // not printed
|
||||
}
|
||||
```
|
||||
|
||||
However a failed assertion _before_ a `SKIP` still causes the entire
|
||||
test case to fail:
|
||||
|
||||
```c++
|
||||
TEST_CASE("failing test") {
|
||||
CHECK(1 == 2);
|
||||
SKIP();
|
||||
}
|
||||
```
|
||||
|
||||
### Interaction with Sections and Generators
|
||||
|
||||
Sections, nested sections as well as specific outputs from [generators](generators.md#top)
|
||||
can all be individually skipped, with the rest executing as usual:
|
||||
|
||||
```c++
|
||||
TEST_CASE("complex test case") {
|
||||
int value = GENERATE(2, 4, 6);
|
||||
SECTION("a") {
|
||||
SECTION("a1") { CHECK(value < 8); }
|
||||
SECTION("a2") {
|
||||
if (value == 4) {
|
||||
SKIP();
|
||||
}
|
||||
CHECK(value % 2 == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This test case will report 5 passing assertions; one for each of the three
|
||||
values in section `a1`, and then two in section `a2`, from values 2 and 4.
|
||||
|
||||
Note that as soon as one section is skipped, the entire test case will
|
||||
be reported as _skipped_ (unless there is a failing assertion, in which
|
||||
case the test is handled as _failed_ instead).
|
||||
|
||||
Note that if all test cases in a run are skipped, Catch2 returns a non-zero
|
||||
exit code, same as it does if no test cases have run. This behaviour can
|
||||
be overridden using the [--allow-running-no-tests](command-line.md#no-tests-override)
|
||||
flag.
|
||||
|
||||
|
||||
## Passing and failing test cases
|
||||
|
||||
Test cases can also be explicitly passed or failed, without the use of
|
||||
assertions, and with a specific message. This can be useful to handle
|
||||
complex preconditions/postconditions and give useful error messages
|
||||
when they fail.
|
||||
|
||||
* `SUCCEED( [streamable expression] )`
|
||||
|
||||
`SUCCEED` is morally equivalent with `INFO( [streamable expression] ); REQUIRE( true );`.
|
||||
Note that it does not stop further test execution, so it cannot be used
|
||||
to guard failing assertions from being executed.
|
||||
|
||||
_In practice, `SUCCEED` is usually used as a test placeholder, to avoid
|
||||
[failing a test case due to missing assertions](command-line.md#warnings)._
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "SUCCEED showcase" ) {
|
||||
int I = 1;
|
||||
SUCCEED( "I is " << I );
|
||||
// ... execution continues here ...
|
||||
}
|
||||
```
|
||||
|
||||
* `FAIL( [streamable expression] )`
|
||||
|
||||
`FAIL` is morally equivalent with `INFO( [streamable expression] ); REQUIRE( false );`.
|
||||
|
||||
_In practice, `FAIL` is usually used to stop executing test that is currently
|
||||
known to be broken, but has to be fixed later._
|
||||
|
||||
```cpp
|
||||
TEST_CASE( "FAIL showcase" ) {
|
||||
FAIL( "This test case causes segfault, which breaks CI." );
|
||||
// ... this will not be executed ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
@@ -25,7 +25,8 @@ _section description_ can be used to provide long form description
|
||||
of a section while keeping the _section name_ short for use with the
|
||||
[`-c` command line parameter](command-line.md#specify-the-section-to-run).
|
||||
|
||||
**Test names must be unique within the Catch executable.**
|
||||
**The combination of test names and tags must be unique within the Catch2
|
||||
executable.**
|
||||
|
||||
For examples see the [Tutorial](tutorial.md#top)
|
||||
|
||||
@@ -68,7 +69,8 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
||||
|
||||
* `[!nonportable]` - Indicates that behaviour may vary between platforms or compilers.
|
||||
|
||||
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped), as a tag to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
|
||||
* `[#<filename>]` - these tags are added to test cases when you run Catch2
|
||||
with [`-#` or `--filenames-as-tags`](command-line.md#filenames-as-tags).
|
||||
|
||||
* `[@<alias>]` - tag aliases all begin with `@` (see below).
|
||||
|
||||
@@ -167,7 +169,11 @@ Other than the additional prefixes and the formatting in the console reporter th
|
||||
|
||||
In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
|
||||
by types, in the form of `TEMPLATE_TEST_CASE`,
|
||||
`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`.
|
||||
`TEMPLATE_PRODUCT_TEST_CASE` and `TEMPLATE_LIST_TEST_CASE`. These macros
|
||||
are defined in the `catch_template_test_macros.hpp` header, so compiling
|
||||
the code examples below also requires
|
||||
`#include <catch2/catch_template_test_macros.hpp>`.
|
||||
|
||||
|
||||
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
|
||||
|
||||
@@ -289,7 +295,9 @@ TEMPLATE_LIST_TEST_CASE("Template test case with test types specified inside std
|
||||
In addition to [type parametrised test cases](#type-parametrised-test-cases) Catch2 also supports
|
||||
signature base parametrised test cases, in form of `TEMPLATE_TEST_CASE_SIG` and `TEMPLATE_PRODUCT_TEST_CASE_SIG`.
|
||||
These test cases have similar syntax like [type parametrised test cases](#type-parametrised-test-cases), with one
|
||||
additional positional argument which specifies the signature.
|
||||
additional positional argument which specifies the signature. These macros are defined in the
|
||||
`catch_template_test_macros.hpp` header, so compiling the code examples below also requires
|
||||
`#include <catch2/catch_template_test_macros.hpp>`.
|
||||
|
||||
### Signature
|
||||
Signature has some strict rules for these tests cases to work properly:
|
||||
|
@@ -46,7 +46,7 @@ function(catch_add_sharded_tests TARGET)
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
|
||||
set(shard_impl_script_file "${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake")
|
||||
set(shard_impl_script_file "${_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT}")
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
@@ -64,3 +64,11 @@ function(catch_add_sharded_tests TARGET)
|
||||
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake
|
||||
CACHE INTERNAL "Catch2 full path to CatchShardTestsImpl.cmake helper file"
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
project(
|
||||
'catch2',
|
||||
'cpp',
|
||||
version: '3.2.1', # CML version placeholder, don't delete
|
||||
version: '3.3.2', # CML version placeholder, don't delete
|
||||
license: 'BSL-1.0',
|
||||
meson_version: '>=0.50.0',
|
||||
)
|
||||
|
@@ -39,7 +39,7 @@ set(BENCHMARK_FILES ${BENCHMARK_HEADERS} ${BENCHMARK_SOURCES})
|
||||
|
||||
|
||||
set(IMPL_HEADERS
|
||||
"${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
${SOURCES_DIR}/catch_user_config.hpp.in
|
||||
${SOURCES_DIR}/catch_all.hpp
|
||||
${SOURCES_DIR}/catch_approx.hpp
|
||||
@@ -55,6 +55,7 @@ set(IMPL_HEADERS
|
||||
${SOURCES_DIR}/catch_template_test_macros.hpp
|
||||
${SOURCES_DIR}/catch_test_case_info.hpp
|
||||
${SOURCES_DIR}/catch_test_macros.hpp
|
||||
${SOURCES_DIR}/catch_test_run_info.hpp
|
||||
${SOURCES_DIR}/catch_test_spec.hpp
|
||||
${SOURCES_DIR}/catch_timer.hpp
|
||||
${SOURCES_DIR}/catch_tostring.hpp
|
||||
@@ -63,6 +64,7 @@ set(IMPL_HEADERS
|
||||
${SOURCES_DIR}/catch_version.hpp
|
||||
${SOURCES_DIR}/catch_version_macros.hpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.hpp
|
||||
${SOURCES_DIR}/internal/catch_benchmark_stats_fwd.hpp
|
||||
${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.hpp
|
||||
${SOURCES_DIR}/internal/catch_case_sensitive.hpp
|
||||
${SOURCES_DIR}/internal/catch_clara.hpp
|
||||
@@ -88,6 +90,7 @@ set(IMPL_HEADERS
|
||||
${SOURCES_DIR}/internal/catch_floating_point_helpers.hpp
|
||||
${SOURCES_DIR}/internal/catch_getenv.hpp
|
||||
${SOURCES_DIR}/internal/catch_istream.hpp
|
||||
${SOURCES_DIR}/internal/catch_is_permutation.hpp
|
||||
${SOURCES_DIR}/internal/catch_lazy_expr.hpp
|
||||
${SOURCES_DIR}/internal/catch_leak_detector.hpp
|
||||
${SOURCES_DIR}/internal/catch_list.hpp
|
||||
@@ -105,6 +108,7 @@ set(IMPL_HEADERS
|
||||
${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.hpp
|
||||
${SOURCES_DIR}/internal/catch_random_seed_generation.hpp
|
||||
${SOURCES_DIR}/internal/catch_registry_hub.hpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.hpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_spec_parser.hpp
|
||||
${SOURCES_DIR}/internal/catch_result_type.hpp
|
||||
@@ -144,7 +148,6 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_config.cpp
|
||||
${SOURCES_DIR}/catch_get_random_seed.cpp
|
||||
${SOURCES_DIR}/catch_message.cpp
|
||||
${SOURCES_DIR}/catch_registry_hub.cpp
|
||||
${SOURCES_DIR}/catch_session.cpp
|
||||
${SOURCES_DIR}/catch_tag_alias_autoregistrar.cpp
|
||||
${SOURCES_DIR}/catch_test_case_info.cpp
|
||||
@@ -152,6 +155,7 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/catch_timer.cpp
|
||||
${SOURCES_DIR}/catch_tostring.cpp
|
||||
${SOURCES_DIR}/catch_totals.cpp
|
||||
${SOURCES_DIR}/catch_translate_exception.cpp
|
||||
${SOURCES_DIR}/catch_version.cpp
|
||||
${SOURCES_DIR}/internal/catch_assertion_handler.cpp
|
||||
${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.cpp
|
||||
@@ -179,6 +183,7 @@ set(IMPL_SOURCES
|
||||
${SOURCES_DIR}/internal/catch_polyfills.cpp
|
||||
${SOURCES_DIR}/internal/catch_random_number_generator.cpp
|
||||
${SOURCES_DIR}/internal/catch_random_seed_generation.cpp
|
||||
${SOURCES_DIR}/internal/catch_registry_hub.cpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_registry.cpp
|
||||
${SOURCES_DIR}/internal/catch_reporter_spec_parser.cpp
|
||||
${SOURCES_DIR}/internal/catch_result_type.cpp
|
||||
@@ -207,27 +212,19 @@ set(INTERNAL_FILES ${IMPL_SOURCES} ${IMPL_HEADERS})
|
||||
|
||||
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
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_tag_alias_registry.hpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp
|
||||
)
|
||||
set(INTERFACE_SOURCES
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_capture.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_config.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_exception.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_generatortracker.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.cpp
|
||||
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.cpp
|
||||
)
|
||||
set(INTERFACE_FILES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES})
|
||||
@@ -252,6 +249,7 @@ set(MATCHER_HEADERS
|
||||
${SOURCES_DIR}/matchers/catch_matchers_all.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_container_properties.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_contains.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_range_equals.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_exception.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_floating_point.hpp
|
||||
${SOURCES_DIR}/matchers/catch_matchers_predicate.hpp
|
||||
@@ -321,7 +319,7 @@ set(ALL_FILES
|
||||
)
|
||||
|
||||
set(FILTERED_FILES ${ALL_FILES})
|
||||
list(REMOVE_ITEM FILTERED_FILES "${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp")
|
||||
list(REMOVE_ITEM FILTERED_FILES "${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp")
|
||||
source_group(
|
||||
TREE ${SOURCES_DIR}
|
||||
PREFIX sources
|
||||
@@ -329,7 +327,7 @@ source_group(
|
||||
)
|
||||
source_group("generated headers"
|
||||
FILES
|
||||
"${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
)
|
||||
|
||||
add_library(Catch2 ${ALL_FILES})
|
||||
@@ -372,13 +370,13 @@ target_compile_features(Catch2
|
||||
|
||||
configure_file(
|
||||
"${SOURCES_DIR}/catch_user_config.hpp.in"
|
||||
"${CMAKE_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2/catch_user_config.hpp"
|
||||
)
|
||||
|
||||
target_include_directories(Catch2
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/generated-includes>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/generated-includes>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
@@ -426,7 +424,7 @@ if (NOT_SUBPROJECT)
|
||||
install(
|
||||
DIRECTORY
|
||||
"${SOURCES_DIR}"
|
||||
"${CMAKE_BINARY_DIR}/generated-includes/catch2" # Also install the generated header
|
||||
"${PROJECT_BINARY_DIR}/generated-includes/catch2" # Also install the generated header
|
||||
DESTINATION
|
||||
"${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
FILES_MATCHING
|
||||
@@ -447,7 +445,7 @@ if (CATCH_BUILD_EXAMPLES OR CATCH_BUILD_EXTRA_TESTS)
|
||||
target_include_directories(Catch2_buildall_interface
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${SOURCES_DIR}/..>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/generated-includes>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/generated-includes>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_definitions(Catch2_buildall_interface
|
||||
@@ -487,12 +485,10 @@ set(CATCH_WARNING_TARGETS ${CATCH_WARNING_TARGETS} PARENT_SCOPE)
|
||||
# so we want to check & warn users if they do this. However, we won't abort
|
||||
# the configuration step so that we don't have to also provide an override.
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if (MSVC)
|
||||
set_target_properties(Catch2 Catch2WithMain
|
||||
PROPERTIES
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS ON
|
||||
)
|
||||
endif()
|
||||
set_target_properties(Catch2 Catch2WithMain
|
||||
PROPERTIES
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS ON
|
||||
)
|
||||
|
||||
get_target_property(_VisPreset Catch2 CXX_VISIBILITY_PRESET)
|
||||
if (NOT MSVC AND _VisPreset STREQUAL "hidden")
|
||||
|
@@ -11,9 +11,11 @@
|
||||
#define CATCH_BENCHMARK_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/benchmark/catch_chronometer.hpp>
|
||||
@@ -26,6 +28,7 @@
|
||||
#include <catch2/benchmark/detail/catch_benchmark_function.hpp>
|
||||
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@@ -64,7 +67,7 @@ namespace Catch {
|
||||
});
|
||||
|
||||
BenchmarkInfo info {
|
||||
name,
|
||||
CATCH_MOVE(name),
|
||||
plan.estimated_duration.count(),
|
||||
plan.iterations_per_sample,
|
||||
cfg->benchmarkSamples(),
|
||||
@@ -80,7 +83,7 @@ namespace Catch {
|
||||
});
|
||||
|
||||
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
||||
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||
getResultCapture().benchmarkEnded(stats);
|
||||
} CATCH_CATCH_ANON (TestFailureException) {
|
||||
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
#define CATCH_OPTIMIZER_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||
# include <atomic> // atomic_thread_fence
|
||||
#endif
|
||||
|
||||
@@ -32,16 +32,23 @@ namespace Catch {
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() { keep_memory(); }
|
||||
} // namespace Detail
|
||||
#elif defined(_MSC_VER)
|
||||
#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
|
||||
|
||||
#if defined(_MSVC_VER)
|
||||
#pragma optimize("", off)
|
||||
#elif defined(__IAR_SYSTEMS_ICC__)
|
||||
// For IAR the pragma only affects the following function
|
||||
#pragma optimize=disable
|
||||
#endif
|
||||
template <typename T>
|
||||
inline void keep_memory(T* p) {
|
||||
// thanks @milleniumbug
|
||||
*reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
|
||||
}
|
||||
// TODO equivalent keep_memory()
|
||||
#if defined(_MSVC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
namespace Detail {
|
||||
inline void optimizer_barrier() {
|
||||
|
@@ -12,8 +12,6 @@
|
||||
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_meta.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <catch2/catch_template_test_macros.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_test_run_info.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
@@ -46,6 +47,7 @@
|
||||
#include <catch2/generators/catch_generators_all.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_all.hpp>
|
||||
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||
#include <catch2/internal/catch_benchmark_stats_fwd.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_case_sensitive.hpp>
|
||||
#include <catch2/internal/catch_clara.hpp>
|
||||
@@ -70,6 +72,7 @@
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_floating_point_helpers.hpp>
|
||||
#include <catch2/internal/catch_getenv.hpp>
|
||||
#include <catch2/internal/catch_is_permutation.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
@@ -88,6 +91,7 @@
|
||||
#include <catch2/internal/catch_preprocessor_remove_parens.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_random_seed_generation.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
|
@@ -7,6 +7,7 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -26,9 +27,9 @@ namespace Catch {
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
|
||||
: m_info( info ),
|
||||
m_resultData( data )
|
||||
m_resultData( CATCH_MOVE(data) )
|
||||
{}
|
||||
|
||||
// Result was a success
|
||||
@@ -67,16 +68,15 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpressionInMacro() const {
|
||||
std::string expr;
|
||||
if( m_info.macroName.empty() )
|
||||
expr = static_cast<std::string>(m_info.capturedExpression);
|
||||
else {
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
if ( m_info.macroName.empty() ) {
|
||||
return static_cast<std::string>( m_info.capturedExpression );
|
||||
}
|
||||
std::string expr;
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ namespace Catch {
|
||||
class AssertionResult {
|
||||
public:
|
||||
AssertionResult() = delete;
|
||||
AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
|
||||
AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
|
||||
|
||||
bool isOk() const;
|
||||
bool succeeded() const;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_test_spec_parser.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_getenv.hpp>
|
||||
|
||||
#include <fstream>
|
||||
@@ -123,7 +123,7 @@ namespace Catch {
|
||||
|
||||
// Bazel support can modify the test specs, so parsing has to happen
|
||||
// after reading Bazel env vars.
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
TestSpecParser parser( TagAliasRegistry::get() );
|
||||
if ( !m_data.testsOrTags.empty() ) {
|
||||
m_hasTestFilters = true;
|
||||
for ( auto const& testOrTags : m_data.testsOrTags ) {
|
||||
|
@@ -6,10 +6,10 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
@@ -19,8 +19,8 @@ namespace Catch {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
|
||||
m_info( builder.m_info ) {
|
||||
ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
|
||||
m_info( CATCH_MOVE(builder.m_info) ) {
|
||||
m_info.message = builder.m_stream.str();
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#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/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
|
||||
#include <string>
|
||||
@@ -39,11 +39,10 @@ namespace Catch {
|
||||
ResultWas::OfType type ):
|
||||
m_info(macroName, lineInfo, type) {}
|
||||
|
||||
|
||||
template<typename T>
|
||||
MessageBuilder& operator << ( T const& value ) {
|
||||
MessageBuilder&& operator << ( T const& value ) && {
|
||||
m_stream << value;
|
||||
return *this;
|
||||
return CATCH_MOVE(*this);
|
||||
}
|
||||
|
||||
MessageInfo m_info;
|
||||
@@ -51,7 +50,7 @@ namespace Catch {
|
||||
|
||||
class ScopedMessage {
|
||||
public:
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
explicit ScopedMessage( MessageBuilder&& builder );
|
||||
ScopedMessage( ScopedMessage& duplicate ) = delete;
|
||||
ScopedMessage( ScopedMessage&& old ) noexcept;
|
||||
~ScopedMessage();
|
||||
@@ -62,7 +61,7 @@ namespace Catch {
|
||||
|
||||
class Capturer {
|
||||
std::vector<MessageInfo> m_messages;
|
||||
IResultCapture& m_resultCapture = getResultCapture();
|
||||
RunContext& m_resultCapture = getResultCapture();
|
||||
size_t m_captured = 0;
|
||||
public:
|
||||
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||
@@ -98,7 +97,10 @@ namespace Catch {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||
Catch::Capturer varName( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
|
||||
Catch::Capturer varName( macroName##_catch_sr, \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
Catch::ResultWas::Info, \
|
||||
#__VA_ARGS__##_catch_sr ); \
|
||||
varName.captureValues( 0, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -1,104 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#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>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
|
||||
class RegistryHub : public IRegistryHub,
|
||||
public IMutableRegistryHub,
|
||||
private Detail::NonCopyable {
|
||||
|
||||
public: // IRegistryHub
|
||||
RegistryHub() = default;
|
||||
IReporterRegistry const& getReporterRegistry() const override {
|
||||
return m_reporterRegistry;
|
||||
}
|
||||
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
||||
return m_testCaseRegistry;
|
||||
}
|
||||
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
|
||||
return m_exceptionTranslatorRegistry;
|
||||
}
|
||||
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
||||
return m_tagAliasRegistry;
|
||||
}
|
||||
StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
|
||||
return m_exceptionRegistry;
|
||||
}
|
||||
|
||||
public: // IMutableRegistryHub
|
||||
void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
|
||||
m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
|
||||
}
|
||||
void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
|
||||
m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
|
||||
}
|
||||
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
|
||||
m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
|
||||
}
|
||||
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
|
||||
m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
|
||||
}
|
||||
void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
|
||||
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||
}
|
||||
void registerStartupException() noexcept override {
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
m_exceptionRegistry.add(std::current_exception());
|
||||
#else
|
||||
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
#endif
|
||||
}
|
||||
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
||||
return m_enumValuesRegistry;
|
||||
}
|
||||
|
||||
private:
|
||||
TestRegistry m_testCaseRegistry;
|
||||
ReporterRegistry m_reporterRegistry;
|
||||
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
||||
TagAliasRegistry m_tagAliasRegistry;
|
||||
StartupExceptionRegistry m_exceptionRegistry;
|
||||
Detail::EnumValuesRegistry m_enumValuesRegistry;
|
||||
};
|
||||
}
|
||||
|
||||
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
|
||||
|
||||
IRegistryHub const& getRegistryHub() {
|
||||
return RegistryHubSingleton::get();
|
||||
}
|
||||
IMutableRegistryHub& getMutableRegistryHub() {
|
||||
return RegistryHubSingleton::getMutable();
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
cleanUpContext();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
@@ -19,11 +19,14 @@
|
||||
#include <catch2/internal/catch_textflow.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/reporters/catch_reporter_multi.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
#include <catch2/internal/catch_istream.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@@ -341,6 +344,12 @@ namespace Catch {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ( totals.testCases.total() > 0 &&
|
||||
totals.testCases.total() == totals.testCases.skipped
|
||||
&& !m_config->zeroTestsCountAsSuccess() ) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||
// the return value to 255 prevents false negative when some multiple
|
||||
// of 256 tests has failed
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <catch2/catch_tag_alias_autoregistrar.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
|
||||
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||
@@ -102,6 +103,7 @@
|
||||
#define CATCH_FAIL( ... ) (void)(0)
|
||||
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||
#define CATCH_SKIP( ... ) (void)(0)
|
||||
|
||||
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
|
||||
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||
@@ -146,6 +148,7 @@
|
||||
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
|
||||
|
||||
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||
@@ -198,6 +201,7 @@
|
||||
#define FAIL( ... ) (void)(0)
|
||||
#define FAIL_CHECK( ... ) (void)(0)
|
||||
#define SUCCEED( ... ) (void)(0)
|
||||
#define SKIP( ... ) (void)(0)
|
||||
|
||||
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||
|
23
src/catch2/catch_test_run_info.hpp
Normal file
23
src/catch2/catch_test_run_info.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// 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_TEST_RUN_INFO_HPP_INCLUDED
|
||||
#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TestRunInfo {
|
||||
constexpr TestRunInfo(StringRef _name) : name(_name) {}
|
||||
StringRef name;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
|
@@ -8,6 +8,7 @@
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
@@ -16,9 +16,9 @@
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_config_wchar.hpp>
|
||||
#include <catch2/internal/catch_stringref.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>
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
|
||||
#include <string_view>
|
||||
@@ -648,7 +648,7 @@ struct ratio_string<std::milli> {
|
||||
};
|
||||
}
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
|
||||
#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
|
||||
namespace Catch { \
|
||||
|
@@ -14,6 +14,7 @@ namespace Catch {
|
||||
diff.passed = passed - other.passed;
|
||||
diff.failed = failed - other.failed;
|
||||
diff.failedButOk = failedButOk - other.failedButOk;
|
||||
diff.skipped = skipped - other.skipped;
|
||||
return diff;
|
||||
}
|
||||
|
||||
@@ -21,14 +22,15 @@ namespace Catch {
|
||||
passed += other.passed;
|
||||
failed += other.failed;
|
||||
failedButOk += other.failedButOk;
|
||||
skipped += other.skipped;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::uint64_t Counts::total() const {
|
||||
return passed + failed + failedButOk;
|
||||
return passed + failed + failedButOk + skipped;
|
||||
}
|
||||
bool Counts::allPassed() const {
|
||||
return failed == 0 && failedButOk == 0;
|
||||
return failed == 0 && failedButOk == 0 && skipped == 0;
|
||||
}
|
||||
bool Counts::allOk() const {
|
||||
return failed == 0;
|
||||
@@ -53,6 +55,8 @@ namespace Catch {
|
||||
++diff.testCases.failed;
|
||||
else if( diff.assertions.failedButOk > 0 )
|
||||
++diff.testCases.failedButOk;
|
||||
else if ( diff.assertions.skipped > 0 )
|
||||
++ diff.testCases.skipped;
|
||||
else
|
||||
++diff.testCases.passed;
|
||||
return diff;
|
||||
|
@@ -23,6 +23,7 @@ namespace Catch {
|
||||
std::uint64_t passed = 0;
|
||||
std::uint64_t failed = 0;
|
||||
std::uint64_t failedButOk = 0;
|
||||
std::uint64_t skipped = 0;
|
||||
};
|
||||
|
||||
struct Totals {
|
||||
|
20
src/catch2/catch_translate_exception.cpp
Normal file
20
src/catch2/catch_translate_exception.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/catch_translate_exception.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void registerTranslatorImpl(
|
||||
Detail::unique_ptr<IExceptionTranslator>&& translator ) {
|
||||
getMutableRegistryHub().registerTranslator(
|
||||
CATCH_MOVE( translator ) );
|
||||
}
|
||||
} // namespace Detail
|
||||
} // namespace Catch
|
@@ -15,6 +15,10 @@
|
||||
#include <exception>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
void registerTranslatorImpl(
|
||||
Detail::unique_ptr<IExceptionTranslator>&& translator );
|
||||
}
|
||||
|
||||
class ExceptionTranslatorRegistrar {
|
||||
template<typename T>
|
||||
@@ -48,9 +52,8 @@ namespace Catch {
|
||||
public:
|
||||
template<typename T>
|
||||
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
|
||||
getMutableRegistryHub().registerTranslator(
|
||||
Detail::make_unique<ExceptionTranslator<T>>(translateFunction)
|
||||
);
|
||||
Detail::registerTranslatorImpl( Detail::make_unique<ExceptionTranslator<T>>(
|
||||
translateFunction ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -36,7 +36,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
Version const& libraryVersion() {
|
||||
static Version version( 3, 2, 1, "", 0 );
|
||||
static Version version( 3, 3, 2, "", 0 );
|
||||
return version;
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 3
|
||||
#define CATCH_VERSION_MINOR 2
|
||||
#define CATCH_VERSION_PATCH 1
|
||||
#define CATCH_VERSION_MINOR 3
|
||||
#define CATCH_VERSION_PATCH 2
|
||||
|
||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/generators/catch_generator_exception.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -27,9 +27,16 @@ namespace Detail {
|
||||
|
||||
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
|
||||
|
||||
auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
|
||||
return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
|
||||
}
|
||||
|
||||
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
GeneratorBasePtr&& generator ) {
|
||||
return getResultCapture().createGeneratorTracker(
|
||||
generatorName, lineInfo, CATCH_MOVE( generator ) );
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_unique_name.hpp>
|
||||
#include <catch2/internal/catch_preprocessor.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
@@ -204,37 +203,47 @@ namespace Detail {
|
||||
return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
|
||||
}
|
||||
|
||||
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo const& lineInfo );
|
||||
IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
GeneratorBasePtr&& generator );
|
||||
|
||||
template<typename L>
|
||||
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||
// the expression used in the typedef inside, when it is in
|
||||
// return type. Yeah.
|
||||
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||
if (!tracker.hasGenerator()) {
|
||||
tracker.setGenerator(Catch::Detail::make_unique<Generators<UnderlyingType>>(generatorExpression()));
|
||||
IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||
// Creation of tracker is delayed after generator creation, so
|
||||
// that constructing generator can fail without breaking everything.
|
||||
if (!tracker) {
|
||||
tracker = createGeneratorTracker(
|
||||
generatorName,
|
||||
lineInfo,
|
||||
Catch::Detail::make_unique<Generators<UnderlyingType>>(
|
||||
generatorExpression() ) );
|
||||
}
|
||||
|
||||
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
|
||||
auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
|
||||
return generator.get();
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
} // namespace Catch
|
||||
|
||||
#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
|
||||
#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
|
||||
|
||||
#define GENERATE( ... ) \
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_COPY( ... ) \
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_REF( ... ) \
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
|
||||
|
@@ -22,16 +22,11 @@
|
||||
#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_ALL_HPP_INCLUDED
|
||||
|
||||
#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>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||
|
||||
#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
|
||||
|
@@ -1,13 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
|
||||
namespace Catch {
|
||||
IResultCapture::~IResultCapture() = default;
|
||||
}
|
@@ -1,96 +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_CAPTURE_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class AssertionResult;
|
||||
struct AssertionInfo;
|
||||
struct SectionInfo;
|
||||
struct SectionEndInfo;
|
||||
struct MessageInfo;
|
||||
struct MessageBuilder;
|
||||
struct Counts;
|
||||
struct AssertionReaction;
|
||||
struct SourceLineInfo;
|
||||
|
||||
class ITransientExpression;
|
||||
class IGeneratorTracker;
|
||||
|
||||
struct BenchmarkInfo;
|
||||
template <typename Duration = std::chrono::duration<double, std::nano>>
|
||||
struct BenchmarkStats;
|
||||
|
||||
class IResultCapture {
|
||||
public:
|
||||
virtual ~IResultCapture();
|
||||
|
||||
virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
||||
Counts& assertions ) = 0;
|
||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
||||
|
||||
virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
||||
|
||||
virtual void benchmarkPreparing( StringRef name ) = 0;
|
||||
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||
virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
|
||||
virtual void benchmarkFailed( StringRef error ) = 0;
|
||||
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
virtual void handleExpr
|
||||
( AssertionInfo const& info,
|
||||
ITransientExpression const& expr,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleMessage
|
||||
( AssertionInfo const& info,
|
||||
ResultWas::OfType resultType,
|
||||
StringRef message,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleUnexpectedExceptionNotThrown
|
||||
( AssertionInfo const& info,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleUnexpectedInflightException
|
||||
( AssertionInfo const& info,
|
||||
std::string const& message,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleIncomplete
|
||||
( AssertionInfo const& info ) = 0;
|
||||
virtual void handleNonExpr
|
||||
( AssertionInfo const &info,
|
||||
ResultWas::OfType resultType,
|
||||
AssertionReaction &reaction ) = 0;
|
||||
|
||||
|
||||
|
||||
virtual bool lastAssertionPassed() = 0;
|
||||
virtual void assertionPassed() = 0;
|
||||
|
||||
// Deprecated, do not use:
|
||||
virtual std::string getCurrentTestName() const = 0;
|
||||
virtual const AssertionResult* getLastResult() const = 0;
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
};
|
||||
|
||||
IResultCapture& getResultCapture();
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
|
@@ -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
|
@@ -10,5 +10,4 @@
|
||||
|
||||
namespace Catch {
|
||||
IExceptionTranslator::~IExceptionTranslator() = default;
|
||||
IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
|
||||
}
|
||||
|
@@ -8,15 +8,12 @@
|
||||
#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
using exceptionTranslateFunction = std::string(*)();
|
||||
|
||||
class IExceptionTranslator;
|
||||
using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
|
||||
|
||||
@@ -26,12 +23,6 @@ namespace Catch {
|
||||
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
|
||||
};
|
||||
|
||||
class IExceptionTranslatorRegistry {
|
||||
public:
|
||||
virtual ~IExceptionTranslatorRegistry(); // = default
|
||||
virtual std::string translateActiveException() const = 0;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
|
||||
|
@@ -1,66 +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_REGISTRY_HUB_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class TestCaseHandle;
|
||||
struct TestCaseInfo;
|
||||
class ITestCaseRegistry;
|
||||
class IExceptionTranslatorRegistry;
|
||||
class IExceptionTranslator;
|
||||
class IReporterRegistry;
|
||||
class IReporterFactory;
|
||||
class ITagAliasRegistry;
|
||||
class ITestInvoker;
|
||||
class IMutableEnumValuesRegistry;
|
||||
struct SourceLineInfo;
|
||||
|
||||
class StartupExceptionRegistry;
|
||||
class EventListenerFactory;
|
||||
|
||||
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||
|
||||
class IRegistryHub {
|
||||
public:
|
||||
virtual ~IRegistryHub(); // = default
|
||||
|
||||
virtual IReporterRegistry const& getReporterRegistry() const = 0;
|
||||
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
||||
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
||||
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
|
||||
|
||||
|
||||
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
||||
};
|
||||
|
||||
class IMutableRegistryHub {
|
||||
public:
|
||||
virtual ~IMutableRegistryHub(); // = default
|
||||
virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
|
||||
virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
|
||||
virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
|
||||
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();
|
||||
IMutableRegistryHub& getMutableRegistryHub();
|
||||
void cleanUp();
|
||||
std::string translateActiveException();
|
||||
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
|
@@ -54,24 +54,21 @@ namespace Catch {
|
||||
infoMessages( _infoMessages ),
|
||||
totals( _totals )
|
||||
{
|
||||
assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
|
||||
|
||||
if( assertionResult.hasMessage() ) {
|
||||
// Copy message into messages list.
|
||||
// !TBD This should have been done earlier, somewhere
|
||||
MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
|
||||
builder << assertionResult.getMessage();
|
||||
builder.m_info.message = builder.m_stream.str();
|
||||
builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
|
||||
|
||||
infoMessages.push_back( builder.m_info );
|
||||
infoMessages.push_back( CATCH_MOVE(builder.m_info) );
|
||||
}
|
||||
}
|
||||
|
||||
SectionStats::SectionStats( SectionInfo const& _sectionInfo,
|
||||
SectionStats::SectionStats( SectionInfo&& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
double _durationInSeconds,
|
||||
bool _missingAssertions )
|
||||
: sectionInfo( _sectionInfo ),
|
||||
: sectionInfo( CATCH_MOVE(_sectionInfo) ),
|
||||
assertions( _assertions ),
|
||||
durationInSeconds( _durationInSeconds ),
|
||||
missingAssertions( _missingAssertions )
|
||||
@@ -80,13 +77,13 @@ namespace Catch {
|
||||
|
||||
TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
|
||||
Totals const& _totals,
|
||||
std::string const& _stdOut,
|
||||
std::string const& _stdErr,
|
||||
std::string&& _stdOut,
|
||||
std::string&& _stdErr,
|
||||
bool _aborting )
|
||||
: testInfo( &_testInfo ),
|
||||
totals( _totals ),
|
||||
stdOut( _stdOut ),
|
||||
stdErr( _stdErr ),
|
||||
stdOut( CATCH_MOVE(_stdOut) ),
|
||||
stdErr( CATCH_MOVE(_stdErr) ),
|
||||
aborting( _aborting )
|
||||
{}
|
||||
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/catch_section_info.hpp>
|
||||
#include <catch2/catch_test_run_info.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/internal/catch_message_info.hpp>
|
||||
@@ -17,15 +18,18 @@
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/benchmark/catch_estimate.hpp>
|
||||
#include <catch2/benchmark/catch_outlier_classification.hpp>
|
||||
|
||||
#include <catch2/internal/catch_benchmark_stats_fwd.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
#include <chrono>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct BenchmarkInfo;
|
||||
|
||||
struct ReporterDescription;
|
||||
struct ListenerDescription;
|
||||
struct TagInfo;
|
||||
@@ -57,11 +61,6 @@ namespace Catch {
|
||||
std::map<std::string, std::string> m_customOptions;
|
||||
};
|
||||
|
||||
struct TestRunInfo {
|
||||
constexpr TestRunInfo(StringRef _name) : name(_name) {}
|
||||
StringRef name;
|
||||
};
|
||||
|
||||
struct AssertionStats {
|
||||
AssertionStats( AssertionResult const& _assertionResult,
|
||||
std::vector<MessageInfo> const& _infoMessages,
|
||||
@@ -78,7 +77,7 @@ namespace Catch {
|
||||
};
|
||||
|
||||
struct SectionStats {
|
||||
SectionStats( SectionInfo const& _sectionInfo,
|
||||
SectionStats( SectionInfo&& _sectionInfo,
|
||||
Counts const& _assertions,
|
||||
double _durationInSeconds,
|
||||
bool _missingAssertions );
|
||||
@@ -92,8 +91,8 @@ namespace Catch {
|
||||
struct TestCaseStats {
|
||||
TestCaseStats( TestCaseInfo const& _testInfo,
|
||||
Totals const& _totals,
|
||||
std::string const& _stdOut,
|
||||
std::string const& _stdErr,
|
||||
std::string&& _stdOut,
|
||||
std::string&& _stdErr,
|
||||
bool _aborting );
|
||||
|
||||
TestCaseInfo const * testInfo;
|
||||
@@ -242,7 +241,12 @@ namespace Catch {
|
||||
*/
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
||||
|
||||
//! Called with test cases that are skipped due to the test run aborting
|
||||
/**
|
||||
* Called with test cases that are skipped due to the test run aborting.
|
||||
* NOT called for test cases that are explicitly skipped using the `SKIP` macro.
|
||||
*
|
||||
* Deprecated - will be removed in the next major release.
|
||||
*/
|
||||
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||
|
||||
//! Called if a fatal error (signal/structured exception) occured
|
||||
|
@@ -1,13 +0,0 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
|
||||
namespace Catch {
|
||||
IReporterRegistry::~IReporterRegistry() = default;
|
||||
}
|
@@ -1,42 +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_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IConfig;
|
||||
|
||||
class IEventListener;
|
||||
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||
class IReporterFactory;
|
||||
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||
struct ReporterConfig;
|
||||
class EventListenerFactory;
|
||||
|
||||
class IReporterRegistry {
|
||||
public:
|
||||
using FactoryMap = std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>;
|
||||
using Listeners = std::vector<Detail::unique_ptr<EventListenerFactory>>;
|
||||
|
||||
virtual ~IReporterRegistry(); // = default
|
||||
virtual IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const = 0;
|
||||
virtual FactoryMap const& getFactories() const = 0;
|
||||
virtual Listeners const& getListeners() const = 0;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_INTERFACES_REPORTER_REGISTRY_HPP_INCLUDED
|
@@ -1,29 +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_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TagAlias;
|
||||
|
||||
class ITagAliasRegistry {
|
||||
public:
|
||||
virtual ~ITagAliasRegistry(); // = default
|
||||
// Nullptr if not present
|
||||
virtual TagAlias const* find( std::string const& alias ) const = 0;
|
||||
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
|
||||
|
||||
static ITagAliasRegistry const& get();
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
@@ -10,5 +10,4 @@
|
||||
|
||||
namespace Catch {
|
||||
ITestInvoker::~ITestInvoker() = default;
|
||||
ITestCaseRegistry::~ITestCaseRegistry() = default;
|
||||
}
|
||||
|
@@ -8,36 +8,14 @@
|
||||
#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
||||
#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class TestSpec;
|
||||
struct TestCaseInfo;
|
||||
|
||||
class ITestInvoker {
|
||||
public:
|
||||
virtual void invoke () const = 0;
|
||||
virtual ~ITestInvoker(); // = default
|
||||
};
|
||||
|
||||
class TestCaseHandle;
|
||||
class IConfig;
|
||||
|
||||
class ITestCaseRegistry {
|
||||
public:
|
||||
virtual ~ITestCaseRegistry(); // = default
|
||||
// TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
|
||||
virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
|
||||
virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
|
||||
virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
|
||||
};
|
||||
|
||||
bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
|
||||
bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config );
|
||||
std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
|
||||
std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
|
||||
|
||||
}
|
||||
|
||||
#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
|
||||
|
@@ -11,7 +11,7 @@
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_debugger.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
void AssertionHandler::complete() {
|
||||
setCompleted();
|
||||
m_completed = true;
|
||||
if( m_reaction.shouldDebugBreak ) {
|
||||
|
||||
// If you find your debugger stopping you here then go one level up on the
|
||||
@@ -50,9 +50,9 @@ namespace Catch {
|
||||
if (m_reaction.shouldThrow) {
|
||||
throw_test_failure_exception();
|
||||
}
|
||||
}
|
||||
void AssertionHandler::setCompleted() {
|
||||
m_completed = true;
|
||||
if ( m_reaction.shouldSkip ) {
|
||||
throw_test_skip_exception();
|
||||
}
|
||||
}
|
||||
|
||||
void AssertionHandler::handleUnexpectedInflightException() {
|
||||
|
@@ -10,25 +10,26 @@
|
||||
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/internal/catch_decomposer.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_lazy_expr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IResultCapture;
|
||||
class RunContext;
|
||||
|
||||
struct AssertionReaction {
|
||||
bool shouldDebugBreak = false;
|
||||
bool shouldThrow = false;
|
||||
bool shouldSkip = false;
|
||||
};
|
||||
|
||||
class AssertionHandler {
|
||||
AssertionInfo m_assertionInfo;
|
||||
AssertionReaction m_reaction;
|
||||
bool m_completed = false;
|
||||
IResultCapture& m_resultCapture;
|
||||
RunContext& m_resultCapture;
|
||||
|
||||
public:
|
||||
AssertionHandler
|
||||
@@ -58,7 +59,6 @@ namespace Catch {
|
||||
void handleUnexpectedInflightException();
|
||||
|
||||
void complete();
|
||||
void setCompleted();
|
||||
|
||||
// query
|
||||
auto allowThrows() const -> bool;
|
||||
|
23
src/catch2/internal/catch_benchmark_stats_fwd.hpp
Normal file
23
src/catch2/internal/catch_benchmark_stats_fwd.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// 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_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// We cannot forward declare the type with default template argument
|
||||
// multiple times, so it is split out into a separate header so that
|
||||
// we can prevent multiple declarations in dependees
|
||||
template <typename Duration = std::chrono::duration<double, std::nano>>
|
||||
struct BenchmarkStats;
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
|
@@ -9,8 +9,8 @@
|
||||
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
#include <catch2/internal/catch_reporter_spec_parser.hpp>
|
||||
@@ -144,7 +144,7 @@ namespace Catch {
|
||||
|
||||
auto const& reporterSpec = *parsed;
|
||||
|
||||
IReporterRegistry::FactoryMap const& factories =
|
||||
auto const& factories =
|
||||
getRegistryHub().getReporterRegistry().getFactories();
|
||||
auto result = factories.find( reporterSpec.name() );
|
||||
|
||||
|
@@ -41,7 +41,7 @@
|
||||
|
||||
// Only GCC compiler should be used in this block, so other compilers trying to
|
||||
// mask themselves as GCC should be ignored.
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
|
||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
|
||||
|
||||
@@ -60,10 +60,21 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__NVCOMPILER)
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
|
||||
#endif
|
||||
|
||||
#if defined(__CUDACC__) && !defined(__clang__)
|
||||
# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
|
||||
// New pragmas introduced in CUDA 11.5+
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" )
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" )
|
||||
# else
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// clang-cl defines _MSC_VER as well as __clang__, which could cause the
|
||||
@@ -181,8 +192,14 @@
|
||||
// Visual C++
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
|
||||
// We want to defer to nvcc-specific warning suppression if we are compiled
|
||||
// with nvcc masquerading for MSVC.
|
||||
# if !defined( __CUDACC__ )
|
||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
__pragma( warning( push ) )
|
||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||
__pragma( warning( pop ) )
|
||||
# endif
|
||||
|
||||
// Universal Windows platform does not support SEH
|
||||
// Or console colours (or console at all...)
|
||||
|
@@ -85,7 +85,7 @@ namespace Catch {
|
||||
namespace {
|
||||
//! A do-nothing implementation of colour, used as fallback for unknown
|
||||
//! platforms, and when the user asks to deactivate all colours.
|
||||
class NoColourImpl : public ColourImpl {
|
||||
class NoColourImpl final : public ColourImpl {
|
||||
public:
|
||||
NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Catch {
|
||||
namespace Catch {
|
||||
namespace {
|
||||
|
||||
class Win32ColourImpl : public ColourImpl {
|
||||
class Win32ColourImpl final : public ColourImpl {
|
||||
public:
|
||||
Win32ColourImpl(IStream* stream):
|
||||
ColourImpl(stream) {
|
||||
@@ -169,7 +169,7 @@ namespace {
|
||||
namespace Catch {
|
||||
namespace {
|
||||
|
||||
class ANSIColourImpl : public ColourImpl {
|
||||
class ANSIColourImpl final : public ColourImpl {
|
||||
public:
|
||||
ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
|
||||
|
||||
|
@@ -47,6 +47,7 @@ namespace Catch {
|
||||
|
||||
Error = BrightRed,
|
||||
Success = Green,
|
||||
Skip = LightGrey,
|
||||
|
||||
OriginalExpression = Cyan,
|
||||
ReconstructedExpression = BrightYellow,
|
||||
|
@@ -11,49 +11,27 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class Context : public IMutableContext, private Detail::NonCopyable {
|
||||
Context* Context::currentContext = nullptr;
|
||||
|
||||
public: // IContext
|
||||
IResultCapture* getResultCapture() override {
|
||||
return m_resultCapture;
|
||||
}
|
||||
|
||||
IConfig const* getConfig() const override {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
~Context() override;
|
||||
|
||||
public: // IMutableContext
|
||||
void setResultCapture( IResultCapture* resultCapture ) override {
|
||||
m_resultCapture = resultCapture;
|
||||
}
|
||||
void setConfig( IConfig const* config ) override {
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
friend IMutableContext& getCurrentMutableContext();
|
||||
|
||||
private:
|
||||
IConfig const* m_config = nullptr;
|
||||
IResultCapture* m_resultCapture = nullptr;
|
||||
};
|
||||
|
||||
IMutableContext *IMutableContext::currentContext = nullptr;
|
||||
|
||||
void IMutableContext::createContext()
|
||||
{
|
||||
void cleanUpContext() {
|
||||
delete Context::currentContext;
|
||||
Context::currentContext = nullptr;
|
||||
}
|
||||
void Context::createContext() {
|
||||
currentContext = new Context();
|
||||
}
|
||||
|
||||
void cleanUpContext() {
|
||||
delete IMutableContext::currentContext;
|
||||
IMutableContext::currentContext = nullptr;
|
||||
Context& getCurrentMutableContext() {
|
||||
if ( !Context::currentContext ) { Context::createContext(); }
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *Context::currentContext;
|
||||
}
|
||||
IContext::~IContext() = default;
|
||||
IMutableContext::~IMutableContext() = default;
|
||||
Context::~Context() = default;
|
||||
|
||||
void Context::setResultCapture( RunContext* resultCapture ) {
|
||||
m_resultCapture = resultCapture;
|
||||
}
|
||||
|
||||
void Context::setConfig( IConfig const* config ) { m_config = config; }
|
||||
|
||||
SimplePcg32& sharedRng() {
|
||||
static SimplePcg32 s_rng;
|
||||
|
@@ -12,41 +12,34 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IResultCapture;
|
||||
class RunContext;
|
||||
class IConfig;
|
||||
|
||||
class IContext {
|
||||
public:
|
||||
virtual ~IContext(); // = default
|
||||
class Context {
|
||||
IConfig const* m_config = nullptr;
|
||||
RunContext* m_resultCapture = nullptr;
|
||||
|
||||
virtual IResultCapture* getResultCapture() = 0;
|
||||
virtual IConfig const* getConfig() const = 0;
|
||||
};
|
||||
|
||||
class IMutableContext : public IContext {
|
||||
public:
|
||||
~IMutableContext() override; // = default
|
||||
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
|
||||
virtual void setConfig( IConfig const* config ) = 0;
|
||||
|
||||
private:
|
||||
CATCH_EXPORT static IMutableContext* currentContext;
|
||||
friend IMutableContext& getCurrentMutableContext();
|
||||
friend void cleanUpContext();
|
||||
CATCH_EXPORT static Context* currentContext;
|
||||
friend Context& getCurrentMutableContext();
|
||||
friend Context const& getCurrentContext();
|
||||
static void createContext();
|
||||
friend void cleanUpContext();
|
||||
|
||||
public:
|
||||
RunContext* getResultCapture() const { return m_resultCapture; }
|
||||
IConfig const* getConfig() const { return m_config; }
|
||||
void setResultCapture( RunContext* resultCapture );
|
||||
void setConfig( IConfig const* config );
|
||||
};
|
||||
|
||||
inline IMutableContext& getCurrentMutableContext()
|
||||
{
|
||||
if( !IMutableContext::currentContext )
|
||||
IMutableContext::createContext();
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *IMutableContext::currentContext;
|
||||
}
|
||||
Context& getCurrentMutableContext();
|
||||
|
||||
inline IContext& getCurrentContext()
|
||||
{
|
||||
return getCurrentMutableContext();
|
||||
inline Context const& getCurrentContext() {
|
||||
// We duplicate the logic from `getCurrentMutableContext` here,
|
||||
// to avoid paying the call overhead in debug mode.
|
||||
if ( !Context::currentContext ) { Context::createContext(); }
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return *Context::currentContext;
|
||||
}
|
||||
|
||||
void cleanUpContext();
|
||||
|
@@ -19,7 +19,10 @@ namespace Catch {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
||||
#elif defined(__aarch64__)
|
||||
#define CATCH_TRAP() __asm__(".inst 0xd43e0000")
|
||||
#define CATCH_TRAP() __asm__(".inst 0xd43e0000")
|
||||
#elif defined(__POWERPC__)
|
||||
#define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
||||
: : : "memory","r0","r3","r4" ) /* NOLINT */
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_PLATFORM_IPHONE)
|
||||
|
@@ -12,44 +12,47 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
|
||||
|
||||
namespace Detail {
|
||||
|
||||
namespace {
|
||||
// Extracts the actual name part of an enum instance
|
||||
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
|
||||
StringRef extractInstanceName(StringRef enumInstance) {
|
||||
// In other words, it returns the Blue part of
|
||||
// Bikeshed::Colour::Blue
|
||||
static StringRef extractInstanceName( StringRef enumInstance ) {
|
||||
// Find last occurrence of ":"
|
||||
size_t name_start = enumInstance.size();
|
||||
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
|
||||
while ( name_start > 0 &&
|
||||
enumInstance[name_start - 1] != ':' ) {
|
||||
--name_start;
|
||||
}
|
||||
return enumInstance.substr(name_start, enumInstance.size() - name_start);
|
||||
return enumInstance.substr( name_start,
|
||||
enumInstance.size() - name_start );
|
||||
}
|
||||
}
|
||||
} // end unnamed namespace
|
||||
|
||||
std::vector<StringRef> parseEnums( StringRef enums ) {
|
||||
auto enumValues = splitStringRef( enums, ',' );
|
||||
std::vector<StringRef> parsed;
|
||||
parsed.reserve( enumValues.size() );
|
||||
for( auto const& enumValue : enumValues ) {
|
||||
parsed.push_back(trim(extractInstanceName(enumValue)));
|
||||
for ( auto const& enumValue : enumValues ) {
|
||||
parsed.push_back( trim( extractInstanceName( enumValue ) ) );
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
EnumInfo::~EnumInfo() {}
|
||||
EnumInfo::~EnumInfo() = default;
|
||||
|
||||
StringRef EnumInfo::lookup( int value ) const {
|
||||
for( auto const& valueToName : m_values ) {
|
||||
if( valueToName.first == value )
|
||||
return valueToName.second;
|
||||
for ( auto const& valueToName : m_values ) {
|
||||
if ( valueToName.first == value ) { return valueToName.second; }
|
||||
}
|
||||
return "{** unexpected enum value **}"_sr;
|
||||
}
|
||||
|
||||
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
|
||||
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() );
|
||||
@@ -57,17 +60,22 @@ namespace Catch {
|
||||
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 ( auto value : values ) {
|
||||
enumInfo->m_values.emplace_back( value, 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();
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
} // Detail
|
||||
} // Catch
|
||||
Detail::EnumInfo const&
|
||||
EnumValuesRegistry::registerEnum( StringRef enumName,
|
||||
StringRef allValueNames,
|
||||
std::vector<int> const& values ) {
|
||||
m_enumInfos.push_back(
|
||||
Detail::makeEnumInfo( enumName, allValueNames, values ) );
|
||||
return *m_enumInfos.back();
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
@@ -8,29 +8,54 @@
|
||||
#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 <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace Detail {
|
||||
struct EnumInfo {
|
||||
StringRef m_name;
|
||||
std::vector<std::pair<int, StringRef>> m_values;
|
||||
|
||||
Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
|
||||
~EnumInfo();
|
||||
|
||||
class EnumValuesRegistry : public IMutableEnumValuesRegistry {
|
||||
|
||||
std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
|
||||
|
||||
EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;
|
||||
StringRef lookup( int value ) const;
|
||||
};
|
||||
|
||||
Detail::unique_ptr<EnumInfo>
|
||||
makeEnumInfo( StringRef enumName,
|
||||
StringRef allValueNames,
|
||||
std::vector<int> const& values );
|
||||
std::vector<StringRef> parseEnums( StringRef enums );
|
||||
|
||||
} // Detail
|
||||
} // namespace Detail
|
||||
|
||||
} // Catch
|
||||
class EnumValuesRegistry {
|
||||
std::vector<Catch::Detail::unique_ptr<Detail::EnumInfo>> m_enumInfos;
|
||||
|
||||
public:
|
||||
Detail::EnumInfo const& registerEnum( StringRef enumName,
|
||||
StringRef allEnums,
|
||||
std::vector<int> const& values );
|
||||
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 );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
|
||||
|
@@ -6,18 +6,41 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
|
||||
namespace {
|
||||
static std::string tryTranslators(
|
||||
std::vector<Detail::unique_ptr<IExceptionTranslator const>> const&
|
||||
translators ) {
|
||||
if ( translators.empty() ) {
|
||||
std::rethrow_exception( std::current_exception() );
|
||||
} else {
|
||||
return translators[0]->translate( translators.begin() + 1,
|
||||
translators.end() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ExceptionTranslatorRegistry::ExceptionTranslatorRegistryImpl {
|
||||
std::vector<Detail::unique_ptr<IExceptionTranslator const>>
|
||||
translators;
|
||||
};
|
||||
|
||||
ExceptionTranslatorRegistry::ExceptionTranslatorRegistry():
|
||||
m_impl( Detail::make_unique<ExceptionTranslatorRegistryImpl>() ) {}
|
||||
ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
|
||||
|
||||
void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
|
||||
m_translators.push_back( CATCH_MOVE( translator ) );
|
||||
m_impl->translators.push_back( CATCH_MOVE( translator ) );
|
||||
}
|
||||
|
||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||
@@ -37,13 +60,16 @@ namespace Catch {
|
||||
// First we try user-registered translators. If none of them can
|
||||
// handle the exception, it will be rethrown handled by our defaults.
|
||||
try {
|
||||
return tryTranslators();
|
||||
return tryTranslators(m_impl->translators);
|
||||
}
|
||||
// To avoid having to handle TFE explicitly everywhere, we just
|
||||
// rethrow it so that it goes back up the caller.
|
||||
catch( TestFailureException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
catch( TestSkipException& ) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
catch( std::exception const& ex ) {
|
||||
return ex.what();
|
||||
}
|
||||
@@ -58,22 +84,10 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
if (m_translators.empty()) {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} else {
|
||||
return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
|
||||
}
|
||||
}
|
||||
|
||||
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
}
|
||||
|
||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||
CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -8,23 +8,22 @@
|
||||
#ifndef CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
#define CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_exception.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
class IExceptionTranslator;
|
||||
|
||||
class ExceptionTranslatorRegistry {
|
||||
struct ExceptionTranslatorRegistryImpl;
|
||||
Detail::unique_ptr<ExceptionTranslatorRegistryImpl> m_impl;
|
||||
|
||||
class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
|
||||
public:
|
||||
~ExceptionTranslatorRegistry() override;
|
||||
ExceptionTranslatorRegistry();
|
||||
~ExceptionTranslatorRegistry();
|
||||
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
|
||||
std::string translateActiveException() const override;
|
||||
std::string tryTranslators() const;
|
||||
|
||||
private:
|
||||
ExceptionTranslators m_translators;
|
||||
std::string translateActiveException() const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/internal/catch_stdstreams.hpp>
|
||||
|
||||
|
138
src/catch2/internal/catch_is_permutation.hpp
Normal file
138
src/catch2/internal/catch_is_permutation.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
|
||||
// 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_IS_PERMUTATION_HPP_INCLUDED
|
||||
#define CATCH_IS_PERMUTATION_HPP_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
template <typename ForwardIter,
|
||||
typename Sentinel,
|
||||
typename T,
|
||||
typename Comparator>
|
||||
ForwardIter find_sentinel( ForwardIter start,
|
||||
Sentinel sentinel,
|
||||
T const& value,
|
||||
Comparator cmp ) {
|
||||
while ( start != sentinel ) {
|
||||
if ( cmp( *start, value ) ) { break; }
|
||||
++start;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
template <typename ForwardIter,
|
||||
typename Sentinel,
|
||||
typename T,
|
||||
typename Comparator>
|
||||
std::ptrdiff_t count_sentinel( ForwardIter start,
|
||||
Sentinel sentinel,
|
||||
T const& value,
|
||||
Comparator cmp ) {
|
||||
std::ptrdiff_t count = 0;
|
||||
while ( start != sentinel ) {
|
||||
if ( cmp( *start, value ) ) { ++count; }
|
||||
++start;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename ForwardIter, typename Sentinel>
|
||||
std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
|
||||
std::ptrdiff_t>
|
||||
sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
|
||||
std::ptrdiff_t dist = 0;
|
||||
while ( iter != sentinel ) {
|
||||
++iter;
|
||||
++dist;
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename ForwardIter>
|
||||
std::ptrdiff_t sentinel_distance( ForwardIter first,
|
||||
ForwardIter last ) {
|
||||
return std::distance( first, last );
|
||||
}
|
||||
|
||||
template <typename ForwardIter1,
|
||||
typename Sentinel1,
|
||||
typename ForwardIter2,
|
||||
typename Sentinel2,
|
||||
typename Comparator>
|
||||
bool check_element_counts( ForwardIter1 first_1,
|
||||
const Sentinel1 end_1,
|
||||
ForwardIter2 first_2,
|
||||
const Sentinel2 end_2,
|
||||
Comparator cmp ) {
|
||||
auto cursor = first_1;
|
||||
while ( cursor != end_1 ) {
|
||||
if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
|
||||
cursor ) {
|
||||
// we haven't checked this element yet
|
||||
const auto count_in_range_2 =
|
||||
count_sentinel( first_2, end_2, *cursor, cmp );
|
||||
// Not a single instance in 2nd range, so it cannot be a
|
||||
// permutation of 1st range
|
||||
if ( count_in_range_2 == 0 ) { return false; }
|
||||
|
||||
const auto count_in_range_1 =
|
||||
count_sentinel( cursor, end_1, *cursor, cmp );
|
||||
if ( count_in_range_1 != count_in_range_2 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
++cursor;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ForwardIter1,
|
||||
typename Sentinel1,
|
||||
typename ForwardIter2,
|
||||
typename Sentinel2,
|
||||
typename Comparator>
|
||||
bool is_permutation( ForwardIter1 first_1,
|
||||
const Sentinel1 end_1,
|
||||
ForwardIter2 first_2,
|
||||
const Sentinel2 end_2,
|
||||
Comparator cmp ) {
|
||||
// TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
|
||||
// TODO: Comparator has to be "both sides", e.g. a == b => b == a
|
||||
// This skips shared prefix of the two ranges
|
||||
while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
|
||||
++first_1;
|
||||
++first_2;
|
||||
}
|
||||
|
||||
// We need to handle case where at least one of the ranges has no more elements
|
||||
if (first_1 == end_1 || first_2 == end_2) {
|
||||
return first_1 == end_1 && first_2 == end_2;
|
||||
}
|
||||
|
||||
// pair counting is n**2, so we pay linear walk to compare the sizes first
|
||||
auto dist_1 = sentinel_distance( first_1, end_1 );
|
||||
auto dist_2 = sentinel_distance( first_2, end_2 );
|
||||
|
||||
if (dist_1 != dist_2) { return false; }
|
||||
|
||||
// Since we do not try to handle stronger iterators pair (e.g.
|
||||
// bidir) optimally, the only thing left to do is to check counts in
|
||||
// the remaining ranges.
|
||||
return check_element_counts( first_1, end_1, first_2, end_2, cmp );
|
||||
}
|
||||
|
||||
} // namespace Detail
|
||||
} // namespace Catch
|
||||
|
||||
#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
|
@@ -24,7 +24,7 @@ namespace Catch {
|
||||
namespace Detail {
|
||||
namespace {
|
||||
template<typename WriterF, std::size_t bufferSize=256>
|
||||
class StreamBufImpl : public std::streambuf {
|
||||
class StreamBufImpl final : public std::streambuf {
|
||||
char data[bufferSize];
|
||||
WriterF m_writer;
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Detail {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileStream : public IStream {
|
||||
class FileStream final : public IStream {
|
||||
std::ofstream m_ofs;
|
||||
public:
|
||||
FileStream( std::string const& filename ) {
|
||||
@@ -89,7 +89,7 @@ namespace Detail {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CoutStream : public IStream {
|
||||
class CoutStream final : public IStream {
|
||||
std::ostream m_os;
|
||||
public:
|
||||
// Store the streambuf from cout up-front because
|
||||
@@ -118,7 +118,7 @@ namespace Detail {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DebugOutStream : public IStream {
|
||||
class DebugOutStream final : public IStream {
|
||||
Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
|
||||
std::ostream m_os;
|
||||
public:
|
||||
|
@@ -7,7 +7,7 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/internal/catch_leak_detector.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
|
||||
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
||||
|
@@ -7,14 +7,14 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_list.hpp>
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/catch_config.hpp>
|
||||
#include <catch2/catch_test_spec.hpp>
|
||||
@@ -54,7 +54,7 @@ namespace Catch {
|
||||
void listReporters(IEventListener& reporter) {
|
||||
std::vector<ReporterDescription> descriptions;
|
||||
|
||||
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
||||
auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
||||
descriptions.reserve(factories.size());
|
||||
for (auto const& fac : factories) {
|
||||
descriptions.push_back({ fac.first, fac.second->getDescription() });
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <catch2/internal/catch_result_type.hpp>
|
||||
#include <catch2/internal/catch_source_line_info.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_capture.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@@ -6,12 +6,12 @@
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
#include <catch2/internal/catch_parse_numbers.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -39,11 +39,14 @@ namespace Catch {
|
||||
return {};
|
||||
}
|
||||
return static_cast<unsigned int>(ret);
|
||||
} CATCH_CATCH_ANON( std::exception const& ) {
|
||||
// There was a larger issue with the input, e.g. the parsed
|
||||
// number would be too large to fit within ull.
|
||||
return {};
|
||||
}
|
||||
CATCH_CATCH_ANON( std::invalid_argument const& ) {
|
||||
// no conversion could be performed
|
||||
}
|
||||
CATCH_CATCH_ANON( std::out_of_range const& ) {
|
||||
// the input does not fit into an unsigned long long
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
114
src/catch2/internal/catch_registry_hub.cpp
Normal file
114
src/catch2/internal/catch_registry_hub.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
// Copyright Catch2 Authors
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_test_case_registry_impl.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_exception_translator_registry.hpp>
|
||||
#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>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct RegistryHub::RegistryHubImpl {
|
||||
TestCaseRegistry testCaseRegistry;
|
||||
ReporterRegistry reporterRegistry;
|
||||
ExceptionTranslatorRegistry exceptionTranslatorRegistry;
|
||||
TagAliasRegistry tagAliasRegistry;
|
||||
StartupExceptionRegistry exceptionRegistry;
|
||||
EnumValuesRegistry enumValuesRegistry;
|
||||
};
|
||||
|
||||
RegistryHub::RegistryHub():
|
||||
m_impl( Detail::make_unique<RegistryHubImpl>() ) {}
|
||||
RegistryHub::~RegistryHub() = default;
|
||||
|
||||
ReporterRegistry const&
|
||||
RegistryHub::getReporterRegistry() const {
|
||||
return m_impl->reporterRegistry;
|
||||
}
|
||||
TestCaseRegistry const&
|
||||
RegistryHub::getTestCaseRegistry() const {
|
||||
return m_impl->testCaseRegistry;
|
||||
}
|
||||
ExceptionTranslatorRegistry const&
|
||||
RegistryHub::getExceptionTranslatorRegistry() const {
|
||||
return m_impl->exceptionTranslatorRegistry;
|
||||
}
|
||||
TagAliasRegistry const&
|
||||
RegistryHub::getTagAliasRegistry() const {
|
||||
return m_impl->tagAliasRegistry;
|
||||
}
|
||||
StartupExceptionRegistry const&
|
||||
RegistryHub::getStartupExceptionRegistry() const {
|
||||
return m_impl->exceptionRegistry;
|
||||
}
|
||||
void
|
||||
RegistryHub::registerReporter( std::string const& name,
|
||||
IReporterFactoryPtr factory ) {
|
||||
m_impl->reporterRegistry.registerReporter( name, CATCH_MOVE( factory ) );
|
||||
}
|
||||
void RegistryHub::registerListener(
|
||||
Detail::unique_ptr<EventListenerFactory> factory ) {
|
||||
m_impl->reporterRegistry.registerListener( CATCH_MOVE( factory ) );
|
||||
}
|
||||
void RegistryHub::registerTest(
|
||||
Detail::unique_ptr<TestCaseInfo>&& testInfo,
|
||||
Detail::unique_ptr<ITestInvoker>&& invoker ) {
|
||||
m_impl->testCaseRegistry.registerTest( CATCH_MOVE( testInfo ),
|
||||
CATCH_MOVE( invoker ) );
|
||||
}
|
||||
void RegistryHub::registerTranslator(
|
||||
Detail::unique_ptr<IExceptionTranslator>&& translator ) {
|
||||
m_impl->exceptionTranslatorRegistry.registerTranslator(
|
||||
CATCH_MOVE( translator ) );
|
||||
}
|
||||
void RegistryHub::registerTagAlias( std::string const& alias,
|
||||
std::string const& tag,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
m_impl->tagAliasRegistry.add( alias, tag, lineInfo );
|
||||
}
|
||||
void RegistryHub::registerStartupException() noexcept {
|
||||
#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
|
||||
m_impl->exceptionRegistry.add( std::current_exception() );
|
||||
#else
|
||||
CATCH_INTERNAL_ERROR( "Attempted to register active exception under "
|
||||
"CATCH_CONFIG_DISABLE_EXCEPTIONS!" );
|
||||
#endif
|
||||
}
|
||||
EnumValuesRegistry& RegistryHub::getMutableEnumValuesRegistry() {
|
||||
return m_impl->enumValuesRegistry;
|
||||
}
|
||||
|
||||
using RegistryHubSingleton = Singleton<RegistryHub>;
|
||||
|
||||
RegistryHub const& getRegistryHub() {
|
||||
return RegistryHubSingleton::get();
|
||||
}
|
||||
RegistryHub& getMutableRegistryHub() {
|
||||
return RegistryHubSingleton::getMutable();
|
||||
}
|
||||
void cleanUp() {
|
||||
cleanupSingletons();
|
||||
cleanUpContext();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
67
src/catch2/internal/catch_registry_hub.hpp
Normal file
67
src/catch2/internal/catch_registry_hub.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
// 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_REGISTRY_HUB_HPP_INCLUDED
|
||||
#define CATCH_REGISTRY_HUB_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class TestCaseHandle;
|
||||
struct TestCaseInfo;
|
||||
class TestCaseRegistry;
|
||||
class ExceptionTranslatorRegistry;
|
||||
class IExceptionTranslator;
|
||||
class ReporterRegistry;
|
||||
class IReporterFactory;
|
||||
class TagAliasRegistry;
|
||||
class ITestInvoker;
|
||||
class EnumValuesRegistry;
|
||||
struct SourceLineInfo;
|
||||
|
||||
class StartupExceptionRegistry;
|
||||
class EventListenerFactory;
|
||||
|
||||
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||
|
||||
class RegistryHub {
|
||||
struct RegistryHubImpl;
|
||||
Detail::unique_ptr<RegistryHubImpl> m_impl;
|
||||
public:
|
||||
RegistryHub();
|
||||
~RegistryHub();
|
||||
|
||||
ReporterRegistry const& getReporterRegistry() const;
|
||||
TestCaseRegistry const& getTestCaseRegistry() const;
|
||||
TagAliasRegistry const& getTagAliasRegistry() const;
|
||||
ExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const;
|
||||
StartupExceptionRegistry const& getStartupExceptionRegistry() const;
|
||||
|
||||
void registerReporter( std::string const& name,
|
||||
IReporterFactoryPtr factory );
|
||||
void registerListener( Detail::unique_ptr<EventListenerFactory> factory );
|
||||
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo,
|
||||
Detail::unique_ptr<ITestInvoker>&& invoker );
|
||||
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
|
||||
void registerTagAlias( std::string const& alias,
|
||||
std::string const& tag,
|
||||
SourceLineInfo const& lineInfo );
|
||||
void registerStartupException() noexcept;
|
||||
EnumValuesRegistry& getMutableEnumValuesRegistry();
|
||||
};
|
||||
|
||||
RegistryHub const& getRegistryHub();
|
||||
RegistryHub& getMutableRegistryHub();
|
||||
void cleanUp();
|
||||
std::string translateActiveException();
|
||||
|
||||
}
|
||||
|
||||
#endif // CATCH_REGISTRY_HUB_HPP_INCLUDED
|
@@ -5,61 +5,86 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/internal/catch_reporter_registry.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/reporters/catch_reporter_automake.hpp>
|
||||
#include <catch2/reporters/catch_reporter_compact.hpp>
|
||||
#include <catch2/reporters/catch_reporter_console.hpp>
|
||||
#include <catch2/reporters/catch_reporter_junit.hpp>
|
||||
#include <catch2/reporters/catch_reporter_registrars.hpp>
|
||||
#include <catch2/reporters/catch_reporter_sonarqube.hpp>
|
||||
#include <catch2/reporters/catch_reporter_tap.hpp>
|
||||
#include <catch2/reporters/catch_reporter_teamcity.hpp>
|
||||
#include <catch2/reporters/catch_reporter_xml.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
|
||||
namespace Catch {
|
||||
struct ReporterRegistry::ReporterRegistryImpl {
|
||||
std::vector<Detail::unique_ptr<EventListenerFactory>> listeners;
|
||||
std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>
|
||||
factories;
|
||||
};
|
||||
|
||||
ReporterRegistry::ReporterRegistry() {
|
||||
ReporterRegistry::ReporterRegistry():
|
||||
m_impl( Detail::make_unique<ReporterRegistryImpl>() ) {
|
||||
// Because it is impossible to move out of initializer list,
|
||||
// we have to add the elements manually
|
||||
m_factories["Automake"] = Detail::make_unique<ReporterFactory<AutomakeReporter>>();
|
||||
m_factories["compact"] = Detail::make_unique<ReporterFactory<CompactReporter>>();
|
||||
m_factories["console"] = Detail::make_unique<ReporterFactory<ConsoleReporter>>();
|
||||
m_factories["JUnit"] = Detail::make_unique<ReporterFactory<JunitReporter>>();
|
||||
m_factories["SonarQube"] = Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
|
||||
m_factories["TAP"] = Detail::make_unique<ReporterFactory<TAPReporter>>();
|
||||
m_factories["TeamCity"] = Detail::make_unique<ReporterFactory<TeamCityReporter>>();
|
||||
m_factories["XML"] = Detail::make_unique<ReporterFactory<XmlReporter>>();
|
||||
m_impl->factories["Automake"] =
|
||||
Detail::make_unique<ReporterFactory<AutomakeReporter>>();
|
||||
m_impl->factories["compact"] =
|
||||
Detail::make_unique<ReporterFactory<CompactReporter>>();
|
||||
m_impl->factories["console"] =
|
||||
Detail::make_unique<ReporterFactory<ConsoleReporter>>();
|
||||
m_impl->factories["JUnit"] =
|
||||
Detail::make_unique<ReporterFactory<JunitReporter>>();
|
||||
m_impl->factories["SonarQube"] =
|
||||
Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
|
||||
m_impl->factories["TAP"] =
|
||||
Detail::make_unique<ReporterFactory<TAPReporter>>();
|
||||
m_impl->factories["TeamCity"] =
|
||||
Detail::make_unique<ReporterFactory<TeamCityReporter>>();
|
||||
m_impl->factories["XML"] =
|
||||
Detail::make_unique<ReporterFactory<XmlReporter>>();
|
||||
}
|
||||
|
||||
ReporterRegistry::~ReporterRegistry() = default;
|
||||
|
||||
IEventListenerPtr
|
||||
ReporterRegistry::create( std::string const& name,
|
||||
ReporterConfig&& config ) const {
|
||||
auto it = m_impl->factories.find( name );
|
||||
if ( it == m_impl->factories.end() ) return nullptr;
|
||||
return it->second->create( CATCH_MOVE( config ) );
|
||||
|
||||
IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const {
|
||||
auto it = m_factories.find( name );
|
||||
if( it == m_factories.end() )
|
||||
return nullptr;
|
||||
return it->second->create( CATCH_MOVE(config) );
|
||||
return IEventListenerPtr();
|
||||
}
|
||||
|
||||
void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) {
|
||||
void ReporterRegistry::registerReporter( std::string const& name,
|
||||
IReporterFactoryPtr factory ) {
|
||||
CATCH_ENFORCE( name.find( "::" ) == name.npos,
|
||||
"'::' is not allowed in reporter name: '" + name + '\'' );
|
||||
auto ret = m_factories.emplace(name, CATCH_MOVE(factory));
|
||||
CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" );
|
||||
"'::' is not allowed in reporter name: '" + name +
|
||||
'\'' );
|
||||
auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) );
|
||||
CATCH_ENFORCE( ret.second,
|
||||
"reporter using '" + name +
|
||||
"' as name was already registered" );
|
||||
}
|
||||
void ReporterRegistry::registerListener(
|
||||
Detail::unique_ptr<EventListenerFactory> factory ) {
|
||||
m_listeners.push_back( CATCH_MOVE(factory) );
|
||||
m_impl->listeners.push_back( CATCH_MOVE( factory ) );
|
||||
}
|
||||
|
||||
IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
|
||||
return m_factories;
|
||||
}
|
||||
IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
|
||||
return m_listeners;
|
||||
std::map<std::string,
|
||||
IReporterFactoryPtr,
|
||||
Detail::CaseInsensitiveLess> const&
|
||||
ReporterRegistry::getFactories() const {
|
||||
return m_impl->factories;
|
||||
}
|
||||
|
||||
}
|
||||
std::vector<Detail::unique_ptr<EventListenerFactory>> const&
|
||||
ReporterRegistry::getListeners() const {
|
||||
return m_impl->listeners;
|
||||
}
|
||||
} // namespace Catch
|
||||
|
@@ -8,31 +8,48 @@
|
||||
#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp>
|
||||
#include <catch2/internal/catch_case_insensitive_comparisons.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ReporterRegistry : public IReporterRegistry {
|
||||
class IEventListener;
|
||||
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||
class IReporterFactory;
|
||||
using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
|
||||
struct ReporterConfig;
|
||||
class EventListenerFactory;
|
||||
|
||||
class ReporterRegistry {
|
||||
struct ReporterRegistryImpl;
|
||||
Detail::unique_ptr<ReporterRegistryImpl> m_impl;
|
||||
|
||||
public:
|
||||
|
||||
ReporterRegistry();
|
||||
~ReporterRegistry() override; // = default, out of line to allow fwd decl
|
||||
~ReporterRegistry(); // = default;
|
||||
|
||||
IEventListenerPtr create( std::string const& name, ReporterConfig&& config ) const override;
|
||||
IEventListenerPtr create( std::string const& name,
|
||||
ReporterConfig&& config ) const;
|
||||
|
||||
void registerReporter( std::string const& name, IReporterFactoryPtr factory );
|
||||
void registerListener( Detail::unique_ptr<EventListenerFactory> factory );
|
||||
void registerReporter( std::string const& name,
|
||||
IReporterFactoryPtr factory );
|
||||
|
||||
FactoryMap const& getFactories() const override;
|
||||
Listeners const& getListeners() const override;
|
||||
void
|
||||
registerListener( Detail::unique_ptr<EventListenerFactory> factory );
|
||||
|
||||
private:
|
||||
FactoryMap m_factories;
|
||||
Listeners m_listeners;
|
||||
std::map<std::string,
|
||||
IReporterFactoryPtr,
|
||||
Detail::CaseInsensitiveLess> const&
|
||||
getFactories() const;
|
||||
|
||||
std::vector<Detail::unique_ptr<EventListenerFactory>> const&
|
||||
getListeners() const;
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED
|
||||
|
@@ -16,6 +16,8 @@ namespace Catch {
|
||||
Ok = 0,
|
||||
Info = 1,
|
||||
Warning = 2,
|
||||
// TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit?
|
||||
ExplicitSkip = 4,
|
||||
|
||||
FailureBit = 0x10,
|
||||
|
||||
|
@@ -7,7 +7,11 @@
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/catch_user_config.hpp>
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_compiler_capabilities.hpp>
|
||||
@@ -15,10 +19,14 @@
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/catch_timer.hpp>
|
||||
#include <catch2/internal/catch_output_redirect.hpp>
|
||||
#include <catch2/internal/catch_assertion_handler.hpp>
|
||||
#include <catch2/internal/catch_test_failure_exception.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
@@ -26,170 +34,182 @@
|
||||
namespace Catch {
|
||||
|
||||
namespace Generators {
|
||||
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
|
||||
GeneratorBasePtr m_generator;
|
||||
namespace {
|
||||
struct GeneratorTracker final : TestCaseTracking::TrackerBase,
|
||||
IGeneratorTracker {
|
||||
GeneratorBasePtr m_generator;
|
||||
|
||||
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( nameAndLocation, ctx, parent )
|
||||
{}
|
||||
~GeneratorTracker() override;
|
||||
GeneratorTracker(
|
||||
TestCaseTracking::NameAndLocation&& nameAndLocation,
|
||||
TrackerContext& ctx,
|
||||
ITracker* parent ):
|
||||
TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
|
||||
~GeneratorTracker() override = default;
|
||||
|
||||
static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
|
||||
GeneratorTracker* tracker;
|
||||
static GeneratorTracker*
|
||||
acquire( TrackerContext& ctx,
|
||||
TestCaseTracking::NameAndLocationRef const&
|
||||
nameAndLocation ) {
|
||||
GeneratorTracker* tracker;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
// Under specific circumstances, the generator we want
|
||||
// to acquire is also the current tracker. If this is
|
||||
// the case, we have to avoid looking through current
|
||||
// tracker's children, and instead return the current
|
||||
// tracker.
|
||||
// A case where this check is important is e.g.
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// int n = GENERATE(1, 2);
|
||||
// }
|
||||
//
|
||||
// without it, the code above creates 5 nested generators.
|
||||
if ( currentTracker.nameAndLocation() == nameAndLocation ) {
|
||||
auto thisTracker =
|
||||
currentTracker.parent()->findChild( nameAndLocation );
|
||||
assert( thisTracker );
|
||||
assert( thisTracker->isGeneratorTracker() );
|
||||
tracker = static_cast<GeneratorTracker*>( thisTracker );
|
||||
} else if ( ITracker* childTracker =
|
||||
currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isGeneratorTracker() );
|
||||
tracker = static_cast<GeneratorTracker*>( childTracker );
|
||||
} else {
|
||||
auto newTracker =
|
||||
Catch::Detail::make_unique<GeneratorTracker>(
|
||||
nameAndLocation, ctx, ¤tTracker );
|
||||
tracker = newTracker.get();
|
||||
currentTracker.addChild( CATCH_MOVE(newTracker) );
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
// Under specific circumstances, the generator we want
|
||||
// to acquire is also the current tracker. If this is
|
||||
// the case, we have to avoid looking through current
|
||||
// tracker's children, and instead return the current
|
||||
// tracker.
|
||||
// A case where this check is important is e.g.
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// int n = GENERATE(1, 2);
|
||||
// }
|
||||
//
|
||||
// without it, the code above creates 5 nested generators.
|
||||
if ( currentTracker.nameAndLocation() == nameAndLocation ) {
|
||||
auto thisTracker = currentTracker.parent()->findChild(
|
||||
nameAndLocation );
|
||||
assert( thisTracker );
|
||||
assert( thisTracker->isGeneratorTracker() );
|
||||
tracker = static_cast<GeneratorTracker*>( thisTracker );
|
||||
} else if ( ITracker* childTracker =
|
||||
currentTracker.findChild(
|
||||
nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isGeneratorTracker() );
|
||||
tracker =
|
||||
static_cast<GeneratorTracker*>( childTracker );
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( !tracker->isComplete() ) { tracker->open(); }
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
if( !tracker->isComplete() ) {
|
||||
tracker->open();
|
||||
// TrackerBase interface
|
||||
bool isGeneratorTracker() const override { return true; }
|
||||
auto hasGenerator() const -> bool override {
|
||||
return !!m_generator;
|
||||
}
|
||||
|
||||
return *tracker;
|
||||
}
|
||||
|
||||
// TrackerBase interface
|
||||
bool isGeneratorTracker() const override { return true; }
|
||||
auto hasGenerator() const -> bool override {
|
||||
return !!m_generator;
|
||||
}
|
||||
void close() override {
|
||||
TrackerBase::close();
|
||||
// If a generator has a child (it is followed by a section)
|
||||
// and none of its children have started, then we must wait
|
||||
// until later to start consuming its values.
|
||||
// This catches cases where `GENERATE` is placed between two
|
||||
// `SECTION`s.
|
||||
// **The check for m_children.empty cannot be removed**.
|
||||
// doing so would break `GENERATE` _not_ followed by `SECTION`s.
|
||||
const bool should_wait_for_child = [&]() {
|
||||
// No children -> nobody to wait for
|
||||
if ( m_children.empty() ) {
|
||||
return false;
|
||||
}
|
||||
// If at least one child started executing, don't wait
|
||||
if ( std::find_if(
|
||||
m_children.begin(),
|
||||
m_children.end(),
|
||||
[]( TestCaseTracking::ITrackerPtr const& tracker ) {
|
||||
return tracker->hasStarted();
|
||||
} ) != m_children.end() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No children have started. We need to check if they _can_
|
||||
// start, and thus we should wait for them, or they cannot
|
||||
// start (due to filters), and we shouldn't wait for them
|
||||
ITracker* parent = m_parent;
|
||||
// This is safe: there is always at least one section
|
||||
// tracker in a test case tracking tree
|
||||
while ( !parent->isSectionTracker() ) {
|
||||
parent = parent->parent();
|
||||
}
|
||||
assert( parent &&
|
||||
"Missing root (test case) level section" );
|
||||
|
||||
auto const& parentSection =
|
||||
static_cast<SectionTracker const&>( *parent );
|
||||
auto const& filters = parentSection.getFilters();
|
||||
// No filters -> no restrictions on running sections
|
||||
if ( filters.empty() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( auto const& child : m_children ) {
|
||||
if ( child->isSectionTracker() &&
|
||||
std::find(
|
||||
filters.begin(),
|
||||
filters.end(),
|
||||
static_cast<SectionTracker const&>( *child )
|
||||
.trimmedName() ) != filters.end() ) {
|
||||
return true;
|
||||
void close() override {
|
||||
TrackerBase::close();
|
||||
// If a generator has a child (it is followed by a section)
|
||||
// and none of its children have started, then we must wait
|
||||
// until later to start consuming its values.
|
||||
// This catches cases where `GENERATE` is placed between two
|
||||
// `SECTION`s.
|
||||
// **The check for m_children.empty cannot be removed**.
|
||||
// doing so would break `GENERATE` _not_ followed by
|
||||
// `SECTION`s.
|
||||
const bool should_wait_for_child = [&]() {
|
||||
// No children -> nobody to wait for
|
||||
if ( m_children.empty() ) { return false; }
|
||||
// If at least one child started executing, don't wait
|
||||
if ( std::find_if(
|
||||
m_children.begin(),
|
||||
m_children.end(),
|
||||
[]( TestCaseTracking::ITrackerPtr const&
|
||||
tracker ) {
|
||||
return tracker->hasStarted();
|
||||
} ) != m_children.end() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No children have started. We need to check if they
|
||||
// _can_ start, and thus we should wait for them, or
|
||||
// they cannot start (due to filters), and we shouldn't
|
||||
// wait for them
|
||||
ITracker* parent = m_parent;
|
||||
// This is safe: there is always at least one section
|
||||
// tracker in a test case tracking tree
|
||||
while ( !parent->isSectionTracker() ) {
|
||||
parent = parent->parent();
|
||||
}
|
||||
assert( parent &&
|
||||
"Missing root (test case) level section" );
|
||||
|
||||
auto const& parentSection =
|
||||
static_cast<SectionTracker const&>( *parent );
|
||||
auto const& filters = parentSection.getFilters();
|
||||
// No filters -> no restrictions on running sections
|
||||
if ( filters.empty() ) { return true; }
|
||||
|
||||
for ( auto const& child : m_children ) {
|
||||
if ( child->isSectionTracker() &&
|
||||
std::find( filters.begin(),
|
||||
filters.end(),
|
||||
static_cast<SectionTracker const&>(
|
||||
*child )
|
||||
.trimmedName() ) !=
|
||||
filters.end() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
// This check is a bit tricky, because m_generator->next()
|
||||
// has a side-effect, where it consumes generator's current
|
||||
// value, but we do not want to invoke the side-effect if
|
||||
// this generator is still waiting for any child to start.
|
||||
assert( m_generator && "Tracker without generator" );
|
||||
if ( should_wait_for_child ||
|
||||
( m_runState == CompletedSuccessfully &&
|
||||
m_generator->countedNext() ) ) {
|
||||
m_children.clear();
|
||||
m_runState = Executing;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
// This check is a bit tricky, because m_generator->next()
|
||||
// has a side-effect, where it consumes generator's current
|
||||
// value, but we do not want to invoke the side-effect if
|
||||
// this generator is still waiting for any child to start.
|
||||
if ( should_wait_for_child ||
|
||||
( m_runState == CompletedSuccessfully &&
|
||||
m_generator->countedNext() ) ) {
|
||||
m_children.clear();
|
||||
m_runState = Executing;
|
||||
}
|
||||
}
|
||||
|
||||
// IGeneratorTracker interface
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
return m_generator;
|
||||
}
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = CATCH_MOVE( generator );
|
||||
}
|
||||
};
|
||||
GeneratorTracker::~GeneratorTracker() = default;
|
||||
// IGeneratorTracker interface
|
||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||
return m_generator;
|
||||
}
|
||||
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||
m_generator = CATCH_MOVE( generator );
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
}
|
||||
|
||||
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
m_context(getCurrentMutableContext()),
|
||||
|
||||
struct RunContext::RunContextImpl {
|
||||
Optional<AssertionResult> lastResult;
|
||||
FatalConditionHandler fatalConditionhandler;
|
||||
TrackerContext trackerContext;
|
||||
std::vector<MessageInfo> messages;
|
||||
// Fake owners for unscoped messages
|
||||
std::vector<ScopedMessage> messageScopes;
|
||||
IEventListenerPtr reporter;
|
||||
std::vector<SectionEndInfo> unfinishedSections;
|
||||
std::vector<ITracker*> activeSections;
|
||||
};
|
||||
|
||||
RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter):
|
||||
m_impl( Detail::make_unique<RunContextImpl>() ),
|
||||
m_runInfo(_config->name()),
|
||||
m_config(_config),
|
||||
m_reporter(CATCH_MOVE(reporter)),
|
||||
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
|
||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || reporter->getPreferences().shouldReportAllAssertions )
|
||||
{
|
||||
m_context.setResultCapture(this);
|
||||
m_reporter->testRunStarting(m_runInfo);
|
||||
getCurrentMutableContext().setResultCapture(this);
|
||||
m_impl->reporter = CATCH_MOVE( reporter );
|
||||
m_impl->reporter->testRunStarting(m_runInfo);
|
||||
}
|
||||
|
||||
RunContext::~RunContext() {
|
||||
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
|
||||
m_impl->reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
|
||||
}
|
||||
|
||||
Totals RunContext::runTest(TestCaseHandle const& testCase) {
|
||||
const Totals prevTotals = m_totals;
|
||||
|
||||
std::string redirectedCout;
|
||||
std::string redirectedCerr;
|
||||
|
||||
auto const& testInfo = testCase.getTestCaseInfo();
|
||||
|
||||
m_reporter->testCaseStarting(testInfo);
|
||||
|
||||
m_impl->reporter->testCaseStarting( testInfo );
|
||||
m_activeTestCase = &testCase;
|
||||
|
||||
|
||||
ITracker& rootTracker = m_trackerContext.startRun();
|
||||
ITracker& rootTracker = m_impl->trackerContext.startRun();
|
||||
assert(rootTracker.isSectionTracker());
|
||||
static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
|
||||
|
||||
@@ -227,11 +247,13 @@ namespace Catch {
|
||||
seedRng( *m_config );
|
||||
|
||||
uint64_t testRuns = 0;
|
||||
std::string redirectedCout;
|
||||
std::string redirectedCerr;
|
||||
do {
|
||||
m_trackerContext.startCycle();
|
||||
m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
|
||||
m_impl->trackerContext.startCycle();
|
||||
m_testCaseTracker = &SectionTracker::acquire(m_impl->trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
|
||||
|
||||
m_reporter->testCasePartialStarting(testInfo, testRuns);
|
||||
m_impl->reporter->testCasePartialStarting( testInfo, testRuns );
|
||||
|
||||
const auto beforeRunTotals = m_totals;
|
||||
std::string oneRunCout, oneRunCerr;
|
||||
@@ -240,9 +262,9 @@ namespace Catch {
|
||||
redirectedCerr += oneRunCerr;
|
||||
|
||||
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
|
||||
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, oneRunCout, oneRunCerr, aborting());
|
||||
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
|
||||
|
||||
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
|
||||
m_impl->reporter->testCasePartialEnded( statsForOneRun, testRuns );
|
||||
++testRuns;
|
||||
} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
|
||||
|
||||
@@ -253,11 +275,12 @@ namespace Catch {
|
||||
deltaTotals.testCases.failed++;
|
||||
}
|
||||
m_totals.testCases += deltaTotals.testCases;
|
||||
m_reporter->testCaseEnded(TestCaseStats(testInfo,
|
||||
deltaTotals,
|
||||
redirectedCout,
|
||||
redirectedCerr,
|
||||
aborting()));
|
||||
m_impl->reporter->testCaseEnded(
|
||||
TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
CATCH_MOVE( redirectedCout ),
|
||||
CATCH_MOVE( redirectedCerr ),
|
||||
aborting() ) );
|
||||
|
||||
m_activeTestCase = nullptr;
|
||||
m_testCaseTracker = nullptr;
|
||||
@@ -270,6 +293,9 @@ namespace Catch {
|
||||
if (result.getResultType() == ResultWas::Ok) {
|
||||
m_totals.assertions.passed++;
|
||||
m_lastAssertionPassed = true;
|
||||
} else if (result.getResultType() == ResultWas::ExplicitSkip) {
|
||||
m_totals.assertions.skipped++;
|
||||
m_lastAssertionPassed = true;
|
||||
} else if (!result.succeeded()) {
|
||||
m_lastAssertionPassed = false;
|
||||
if (result.isOk()) {
|
||||
@@ -283,101 +309,140 @@ namespace Catch {
|
||||
m_lastAssertionPassed = true;
|
||||
}
|
||||
|
||||
m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals));
|
||||
m_impl->reporter->assertionEnded(AssertionStats(result, m_impl->messages, m_totals));
|
||||
|
||||
if (result.getResultType() != ResultWas::Warning)
|
||||
m_messageScopes.clear();
|
||||
if ( result.getResultType() != ResultWas::Warning ) {
|
||||
m_impl->messageScopes.clear();
|
||||
}
|
||||
|
||||
// Reset working state
|
||||
resetAssertionInfo();
|
||||
m_lastResult = result;
|
||||
m_impl->lastResult = result;
|
||||
}
|
||||
void RunContext::resetAssertionInfo() {
|
||||
m_lastAssertionInfo.macroName = StringRef();
|
||||
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
|
||||
}
|
||||
|
||||
bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
|
||||
ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
|
||||
bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) {
|
||||
ITracker& sectionTracker =
|
||||
SectionTracker::acquire( m_impl->trackerContext,
|
||||
TestCaseTracking::NameAndLocationRef(
|
||||
sectionName, sectionLineInfo ) );
|
||||
|
||||
if (!sectionTracker.isOpen())
|
||||
return false;
|
||||
m_activeSections.push_back(§ionTracker);
|
||||
m_impl->activeSections.push_back(§ionTracker);
|
||||
|
||||
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
|
||||
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
||||
|
||||
m_reporter->sectionStarting(sectionInfo);
|
||||
m_impl->reporter->sectionStarting( sectionInfo );
|
||||
|
||||
assertions = m_totals.assertions;
|
||||
|
||||
return true;
|
||||
}
|
||||
auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
IGeneratorTracker*
|
||||
RunContext::acquireGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
using namespace Generators;
|
||||
GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
|
||||
TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
|
||||
GeneratorTracker* tracker = GeneratorTracker::acquire(
|
||||
m_impl->trackerContext,
|
||||
TestCaseTracking::NameAndLocationRef(
|
||||
generatorName, lineInfo ) );
|
||||
m_lastAssertionInfo.lineInfo = lineInfo;
|
||||
return tracker;
|
||||
}
|
||||
|
||||
IGeneratorTracker* RunContext::createGeneratorTracker(
|
||||
StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
Generators::GeneratorBasePtr&& generator ) {
|
||||
|
||||
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
||||
auto& currentTracker = m_impl->trackerContext.currentTracker();
|
||||
assert(
|
||||
currentTracker.nameAndLocation() != nameAndLoc &&
|
||||
"Trying to create tracker for a genreator that already has one" );
|
||||
|
||||
auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
|
||||
CATCH_MOVE(nameAndLoc), m_impl->trackerContext, ¤tTracker );
|
||||
auto ret = newTracker.get();
|
||||
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
||||
|
||||
ret->setGenerator( CATCH_MOVE( generator ) );
|
||||
ret->open();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
||||
if (assertions.total() != 0)
|
||||
return false;
|
||||
if (!m_config->warnAboutMissingAssertions())
|
||||
return false;
|
||||
if (m_trackerContext.currentTracker().hasChildren())
|
||||
if (m_impl->trackerContext.currentTracker().hasChildren())
|
||||
return false;
|
||||
m_totals.assertions.failed++;
|
||||
assertions.failed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
|
||||
void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
|
||||
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
|
||||
bool missingAssertions = testForMissingAssertions(assertions);
|
||||
|
||||
if (!m_activeSections.empty()) {
|
||||
m_activeSections.back()->close();
|
||||
m_activeSections.pop_back();
|
||||
if (!m_impl->activeSections.empty()) {
|
||||
m_impl->activeSections.back()->close();
|
||||
m_impl->activeSections.pop_back();
|
||||
}
|
||||
|
||||
m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
m_impl->reporter->sectionEnded(
|
||||
SectionStats( CATCH_MOVE( endInfo.sectionInfo ),
|
||||
assertions,
|
||||
endInfo.durationInSeconds,
|
||||
missingAssertions ) );
|
||||
m_impl->messages.clear();
|
||||
m_impl->messageScopes.clear();
|
||||
}
|
||||
|
||||
void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
|
||||
if (m_unfinishedSections.empty())
|
||||
m_activeSections.back()->fail();
|
||||
else
|
||||
m_activeSections.back()->close();
|
||||
m_activeSections.pop_back();
|
||||
void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
|
||||
if ( m_impl->unfinishedSections.empty() ) {
|
||||
m_impl->activeSections.back()->fail();
|
||||
} else {
|
||||
m_impl->activeSections.back()->close();
|
||||
}
|
||||
m_impl->activeSections.pop_back();
|
||||
|
||||
m_unfinishedSections.push_back(endInfo);
|
||||
m_impl->unfinishedSections.push_back(CATCH_MOVE(endInfo));
|
||||
}
|
||||
|
||||
void RunContext::benchmarkPreparing( StringRef name ) {
|
||||
m_reporter->benchmarkPreparing(name);
|
||||
m_impl->reporter->benchmarkPreparing( name );
|
||||
}
|
||||
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
|
||||
m_reporter->benchmarkStarting( info );
|
||||
m_impl->reporter->benchmarkStarting( info );
|
||||
}
|
||||
void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
|
||||
m_reporter->benchmarkEnded( stats );
|
||||
m_impl->reporter->benchmarkEnded( stats );
|
||||
}
|
||||
void RunContext::benchmarkFailed( StringRef error ) {
|
||||
m_reporter->benchmarkFailed( error );
|
||||
m_impl->reporter->benchmarkFailed( error );
|
||||
}
|
||||
|
||||
void RunContext::pushScopedMessage(MessageInfo const & message) {
|
||||
m_messages.push_back(message);
|
||||
m_impl->messages.push_back(message);
|
||||
}
|
||||
|
||||
void RunContext::popScopedMessage(MessageInfo const & message) {
|
||||
m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
|
||||
m_impl->messages.erase( std::remove( m_impl->messages.begin(),
|
||||
m_impl->messages.end(),
|
||||
message ),
|
||||
m_impl->messages.end() );
|
||||
}
|
||||
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
|
||||
m_messageScopes.emplace_back( builder );
|
||||
void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
|
||||
m_impl->messageScopes.emplace_back( CATCH_MOVE(builder) );
|
||||
}
|
||||
|
||||
std::string RunContext::getCurrentTestName() const {
|
||||
@@ -387,7 +452,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
const AssertionResult * RunContext::getLastResult() const {
|
||||
return &(*m_lastResult);
|
||||
return &(*m_impl->lastResult);
|
||||
}
|
||||
|
||||
void RunContext::exceptionEarlyReported() {
|
||||
@@ -396,13 +461,13 @@ namespace Catch {
|
||||
|
||||
void RunContext::handleFatalErrorCondition( StringRef message ) {
|
||||
// First notify reporter that bad things happened
|
||||
m_reporter->fatalErrorEncountered(message);
|
||||
m_impl->reporter->fatalErrorEncountered(message);
|
||||
|
||||
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
||||
// Instead, fake a result data.
|
||||
AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
|
||||
tempResult.message = static_cast<std::string>(message);
|
||||
AssertionResult result(m_lastAssertionInfo, tempResult);
|
||||
AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
|
||||
|
||||
assertionEnded(result);
|
||||
|
||||
@@ -414,21 +479,21 @@ namespace Catch {
|
||||
|
||||
Counts assertions;
|
||||
assertions.failed = 1;
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
|
||||
m_impl->reporter->sectionEnded(testCaseSectionStats);
|
||||
|
||||
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
|
||||
|
||||
Totals deltaTotals;
|
||||
deltaTotals.testCases.failed = 1;
|
||||
deltaTotals.assertions.failed = 1;
|
||||
m_reporter->testCaseEnded(TestCaseStats(testInfo,
|
||||
m_impl->reporter->testCaseEnded(TestCaseStats(testInfo,
|
||||
deltaTotals,
|
||||
std::string(),
|
||||
std::string(),
|
||||
false));
|
||||
m_totals.testCases.failed++;
|
||||
m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
|
||||
m_impl->reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
|
||||
}
|
||||
|
||||
bool RunContext::lastAssertionPassed() {
|
||||
@@ -439,7 +504,7 @@ namespace Catch {
|
||||
m_lastAssertionPassed = true;
|
||||
++m_totals.assertions.passed;
|
||||
resetAssertionInfo();
|
||||
m_messageScopes.clear();
|
||||
m_impl->messageScopes.clear();
|
||||
}
|
||||
|
||||
bool RunContext::aborting() const {
|
||||
@@ -449,7 +514,7 @@ namespace Catch {
|
||||
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
|
||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||
m_reporter->sectionStarting(testCaseSection);
|
||||
m_impl->reporter->sectionStarting(testCaseSection);
|
||||
Counts prevAssertions = m_totals.assertions;
|
||||
double duration = 0;
|
||||
m_shouldReportUnexpected = true;
|
||||
@@ -457,7 +522,7 @@ namespace Catch {
|
||||
|
||||
Timer timer;
|
||||
CATCH_TRY {
|
||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
||||
if (m_impl->reporter->getPreferences().shouldRedirectStdOut) {
|
||||
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||
RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
|
||||
|
||||
@@ -475,6 +540,8 @@ namespace Catch {
|
||||
duration = timer.getElapsedSeconds();
|
||||
} CATCH_CATCH_ANON (TestFailureException&) {
|
||||
// This just means the test was aborted due to failure
|
||||
} CATCH_CATCH_ANON (TestSkipException&) {
|
||||
// This just means the test was explicitly skipped
|
||||
} CATCH_CATCH_ALL {
|
||||
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
|
||||
// are reported without translation at the point of origin.
|
||||
@@ -488,18 +555,18 @@ namespace Catch {
|
||||
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messages.clear();
|
||||
m_messageScopes.clear();
|
||||
m_impl->messages.clear();
|
||||
m_impl->messageScopes.clear();
|
||||
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
|
||||
m_impl->reporter->sectionEnded(testCaseSectionStats);
|
||||
}
|
||||
|
||||
void RunContext::invokeActiveTestCase() {
|
||||
// We need to engage a handler for signals/structured exceptions
|
||||
// before running the tests themselves, or the binary can crash
|
||||
// without failed test being reported.
|
||||
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
|
||||
FatalConditionHandlerGuard _(&m_impl->fatalConditionhandler);
|
||||
// We keep having issue where some compilers warn about an unused
|
||||
// variable, even though the type has non-trivial constructor and
|
||||
// destructor. This is annoying and ugly, but it makes them stfu.
|
||||
@@ -511,12 +578,12 @@ namespace Catch {
|
||||
void RunContext::handleUnfinishedSections() {
|
||||
// If sections ended prematurely due to an exception we stored their
|
||||
// infos here so we can tear them down outside the unwind process.
|
||||
for (auto it = m_unfinishedSections.rbegin(),
|
||||
itEnd = m_unfinishedSections.rend();
|
||||
for (auto it = m_impl->unfinishedSections.rbegin(),
|
||||
itEnd = m_impl->unfinishedSections.rend();
|
||||
it != itEnd;
|
||||
++it)
|
||||
sectionEnded(*it);
|
||||
m_unfinishedSections.clear();
|
||||
sectionEnded(CATCH_MOVE(*it));
|
||||
m_impl->unfinishedSections.clear();
|
||||
}
|
||||
|
||||
void RunContext::handleExpr(
|
||||
@@ -524,7 +591,7 @@ namespace Catch {
|
||||
ITransientExpression const& expr,
|
||||
AssertionReaction& reaction
|
||||
) {
|
||||
m_reporter->assertionStarting( info );
|
||||
m_impl->reporter->assertionStarting( info );
|
||||
|
||||
bool negated = isFalseTest( info.resultDisposition );
|
||||
bool result = expr.getResult() != negated;
|
||||
@@ -551,7 +618,7 @@ namespace Catch {
|
||||
m_lastAssertionInfo = info;
|
||||
AssertionResultData data( resultType, LazyExpression( negated ) );
|
||||
|
||||
AssertionResult assertionResult{ info, data };
|
||||
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
|
||||
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
|
||||
|
||||
assertionEnded( assertionResult );
|
||||
@@ -563,16 +630,22 @@ namespace Catch {
|
||||
StringRef message,
|
||||
AssertionReaction& reaction
|
||||
) {
|
||||
m_reporter->assertionStarting( info );
|
||||
m_impl->reporter->assertionStarting( info );
|
||||
|
||||
m_lastAssertionInfo = info;
|
||||
|
||||
AssertionResultData data( resultType, LazyExpression( false ) );
|
||||
data.message = static_cast<std::string>(message);
|
||||
AssertionResult assertionResult{ m_lastAssertionInfo, data };
|
||||
AssertionResult assertionResult{ m_lastAssertionInfo,
|
||||
CATCH_MOVE( data ) };
|
||||
assertionEnded( assertionResult );
|
||||
if( !assertionResult.isOk() )
|
||||
if ( !assertionResult.isOk() ) {
|
||||
populateReaction( reaction );
|
||||
} else if ( resultType == ResultWas::ExplicitSkip ) {
|
||||
// TODO: Need to handle this explicitly, as ExplicitSkip is
|
||||
// considered "OK"
|
||||
reaction.shouldSkip = true;
|
||||
}
|
||||
}
|
||||
void RunContext::handleUnexpectedExceptionNotThrown(
|
||||
AssertionInfo const& info,
|
||||
@@ -583,14 +656,14 @@ namespace Catch {
|
||||
|
||||
void RunContext::handleUnexpectedInflightException(
|
||||
AssertionInfo const& info,
|
||||
std::string const& message,
|
||||
std::string&& message,
|
||||
AssertionReaction& reaction
|
||||
) {
|
||||
m_lastAssertionInfo = info;
|
||||
|
||||
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
|
||||
data.message = message;
|
||||
AssertionResult assertionResult{ info, data };
|
||||
data.message = CATCH_MOVE(message);
|
||||
AssertionResult assertionResult{ info, CATCH_MOVE(data) };
|
||||
assertionEnded( assertionResult );
|
||||
populateReaction( reaction );
|
||||
}
|
||||
@@ -603,11 +676,12 @@ namespace Catch {
|
||||
void RunContext::handleIncomplete(
|
||||
AssertionInfo const& info
|
||||
) {
|
||||
using namespace std::string_literals;
|
||||
m_lastAssertionInfo = info;
|
||||
|
||||
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
|
||||
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
|
||||
AssertionResult assertionResult{ info, data };
|
||||
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
|
||||
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
|
||||
assertionEnded( assertionResult );
|
||||
}
|
||||
void RunContext::handleNonExpr(
|
||||
@@ -618,7 +692,7 @@ namespace Catch {
|
||||
m_lastAssertionInfo = info;
|
||||
|
||||
AssertionResultData data( resultType, LazyExpression( false ) );
|
||||
AssertionResult assertionResult{ info, data };
|
||||
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
|
||||
assertionEnded( assertionResult );
|
||||
|
||||
if( !assertionResult.isOk() )
|
||||
@@ -626,7 +700,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
|
||||
IResultCapture& getResultCapture() {
|
||||
RunContext& getResultCapture() {
|
||||
if (auto* capture = getCurrentContext().getResultCapture())
|
||||
return *capture;
|
||||
else
|
||||
|
@@ -8,37 +8,60 @@
|
||||
#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
|
||||
#define CATCH_RUN_CONTEXT_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
|
||||
#include <catch2/internal/catch_test_registry.hpp>
|
||||
#include <catch2/internal/catch_fatal_condition_handler.hpp>
|
||||
#include <catch2/catch_test_case_info.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_test_run_info.hpp>
|
||||
#include <catch2/catch_totals.hpp>
|
||||
#include <catch2/internal/catch_test_case_tracker.hpp>
|
||||
#include <catch2/catch_assertion_info.hpp>
|
||||
#include <catch2/catch_assertion_result.hpp>
|
||||
#include <catch2/internal/catch_optional.hpp>
|
||||
#include <catch2/internal/catch_move_and_forward.hpp>
|
||||
#include <catch2/internal/catch_benchmark_stats_fwd.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class IMutableContext;
|
||||
class TestCaseHandle;
|
||||
class AssertionResult;
|
||||
struct AssertionInfo;
|
||||
struct SectionInfo;
|
||||
struct SectionEndInfo;
|
||||
struct MessageInfo;
|
||||
struct MessageBuilder;
|
||||
struct Counts;
|
||||
struct AssertionReaction;
|
||||
struct SourceLineInfo;
|
||||
|
||||
class ITransientExpression;
|
||||
class IGeneratorTracker;
|
||||
|
||||
struct BenchmarkInfo;
|
||||
|
||||
namespace Generators {
|
||||
class GeneratorUntypedBase;
|
||||
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
|
||||
}
|
||||
|
||||
|
||||
class IGeneratorTracker;
|
||||
class IConfig;
|
||||
// Fixme: Take out the namespace?
|
||||
namespace TestCaseTracking {
|
||||
class ITracker;
|
||||
}
|
||||
using TestCaseTracking::ITracker;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RunContext : public IResultCapture {
|
||||
class IEventListener;
|
||||
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||
|
||||
class RunContext {
|
||||
struct RunContextImpl;
|
||||
Detail::unique_ptr<RunContextImpl> m_impl;
|
||||
public:
|
||||
RunContext( RunContext const& ) = delete;
|
||||
RunContext& operator =( RunContext const& ) = delete;
|
||||
|
||||
explicit RunContext( IConfig const* _config, IEventListenerPtr&& reporter );
|
||||
|
||||
~RunContext() override;
|
||||
~RunContext();
|
||||
|
||||
Totals runTest(TestCaseHandle const& testCase);
|
||||
|
||||
@@ -48,54 +71,63 @@ namespace Catch {
|
||||
void handleExpr
|
||||
( AssertionInfo const& info,
|
||||
ITransientExpression const& expr,
|
||||
AssertionReaction& reaction ) override;
|
||||
AssertionReaction& reaction );
|
||||
void handleMessage
|
||||
( AssertionInfo const& info,
|
||||
ResultWas::OfType resultType,
|
||||
StringRef message,
|
||||
AssertionReaction& reaction ) override;
|
||||
AssertionReaction& reaction );
|
||||
void handleUnexpectedExceptionNotThrown
|
||||
( AssertionInfo const& info,
|
||||
AssertionReaction& reaction ) override;
|
||||
AssertionReaction& reaction );
|
||||
void handleUnexpectedInflightException
|
||||
( AssertionInfo const& info,
|
||||
std::string const& message,
|
||||
AssertionReaction& reaction ) override;
|
||||
std::string&& message,
|
||||
AssertionReaction& reaction );
|
||||
void handleIncomplete
|
||||
( AssertionInfo const& info ) override;
|
||||
( AssertionInfo const& info );
|
||||
void handleNonExpr
|
||||
( AssertionInfo const &info,
|
||||
ResultWas::OfType resultType,
|
||||
AssertionReaction &reaction ) override;
|
||||
AssertionReaction &reaction );
|
||||
|
||||
bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
|
||||
bool sectionStarted( StringRef sectionName,
|
||||
SourceLineInfo const& sectionLineInfo,
|
||||
Counts& assertions );
|
||||
|
||||
void sectionEnded( SectionEndInfo const& endInfo ) override;
|
||||
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
|
||||
void sectionEnded( SectionEndInfo&& endInfo );
|
||||
void sectionEndedEarly( SectionEndInfo&& endInfo );
|
||||
|
||||
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
|
||||
IGeneratorTracker*
|
||||
acquireGeneratorTracker( StringRef generatorName,
|
||||
SourceLineInfo const& lineInfo );
|
||||
IGeneratorTracker* createGeneratorTracker(
|
||||
StringRef generatorName,
|
||||
SourceLineInfo lineInfo,
|
||||
Generators::GeneratorBasePtr&& generator );
|
||||
|
||||
void benchmarkPreparing( StringRef name ) override;
|
||||
void benchmarkStarting( BenchmarkInfo const& info ) override;
|
||||
void benchmarkEnded( BenchmarkStats<> const& stats ) override;
|
||||
void benchmarkFailed( StringRef error ) override;
|
||||
|
||||
void pushScopedMessage( MessageInfo const& message ) override;
|
||||
void popScopedMessage( MessageInfo const& message ) override;
|
||||
void benchmarkPreparing( StringRef name );
|
||||
void benchmarkStarting( BenchmarkInfo const& info );
|
||||
void benchmarkEnded( BenchmarkStats<> const& stats );
|
||||
void benchmarkFailed( StringRef error );
|
||||
|
||||
void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
|
||||
void pushScopedMessage( MessageInfo const& message );
|
||||
void popScopedMessage( MessageInfo const& message );
|
||||
|
||||
std::string getCurrentTestName() const override;
|
||||
void emplaceUnscopedMessage( MessageBuilder&& builder );
|
||||
|
||||
const AssertionResult* getLastResult() const override;
|
||||
std::string getCurrentTestName() const;
|
||||
|
||||
void exceptionEarlyReported() override;
|
||||
const AssertionResult* getLastResult() const;
|
||||
|
||||
void handleFatalErrorCondition( StringRef message ) override;
|
||||
void exceptionEarlyReported();
|
||||
|
||||
bool lastAssertionPassed() override;
|
||||
void handleFatalErrorCondition( StringRef message );
|
||||
|
||||
void assertionPassed() override;
|
||||
bool lastAssertionPassed();
|
||||
|
||||
void assertionPassed();
|
||||
|
||||
public:
|
||||
// !TBD We need to do this another way!
|
||||
@@ -123,21 +155,12 @@ namespace Catch {
|
||||
void handleUnfinishedSections();
|
||||
|
||||
TestRunInfo m_runInfo;
|
||||
IMutableContext& m_context;
|
||||
TestCaseHandle const* m_activeTestCase = nullptr;
|
||||
ITracker* m_testCaseTracker = nullptr;
|
||||
Optional<AssertionResult> m_lastResult;
|
||||
|
||||
IConfig const* m_config;
|
||||
Totals m_totals;
|
||||
IEventListenerPtr m_reporter;
|
||||
std::vector<MessageInfo> m_messages;
|
||||
std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
|
||||
AssertionInfo m_lastAssertionInfo;
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
TrackerContext m_trackerContext;
|
||||
FatalConditionHandler m_fatalConditionhandler;
|
||||
bool m_lastAssertionPassed = false;
|
||||
bool m_shouldReportUnexpected = true;
|
||||
bool m_includeSuccessfulResults;
|
||||
@@ -145,6 +168,9 @@ namespace Catch {
|
||||
|
||||
void seedRng(IConfig const& config);
|
||||
unsigned int rngSeed();
|
||||
|
||||
RunContext& getResultCapture();
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_RUN_CONTEXT_HPP_INCLUDED
|
||||
|
@@ -15,7 +15,7 @@ namespace Catch {
|
||||
Section::Section( SectionInfo&& info ):
|
||||
m_info( CATCH_MOVE( info ) ),
|
||||
m_sectionIncluded(
|
||||
getResultCapture().sectionStarted( m_info, m_assertions ) ) {
|
||||
getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
|
||||
// Non-"included" sections will not use the timing information
|
||||
// anyway, so don't bother with the potential syscall.
|
||||
if (m_sectionIncluded) {
|
||||
@@ -23,13 +23,31 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
Section::Section( SourceLineInfo const& _lineInfo,
|
||||
StringRef _name,
|
||||
const char* const ):
|
||||
m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
|
||||
m_sectionIncluded(
|
||||
getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
|
||||
// We delay initialization the SectionInfo member until we know
|
||||
// this section needs it, so we avoid allocating std::string for name.
|
||||
// We also delay timer start to avoid the potential syscall unless we
|
||||
// will actually use the result.
|
||||
if ( m_sectionIncluded ) {
|
||||
m_info.name = static_cast<std::string>( _name );
|
||||
m_info.lineInfo = _lineInfo;
|
||||
m_timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
Section::~Section() {
|
||||
if( m_sectionIncluded ) {
|
||||
SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
|
||||
if( uncaught_exceptions() )
|
||||
getResultCapture().sectionEndedEarly( endInfo );
|
||||
else
|
||||
getResultCapture().sectionEnded( endInfo );
|
||||
SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
|
||||
if ( uncaught_exceptions() ) {
|
||||
getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
|
||||
} else {
|
||||
getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,9 @@ namespace Catch {
|
||||
class Section : Detail::NonCopyable {
|
||||
public:
|
||||
Section( SectionInfo&& info );
|
||||
Section( SourceLineInfo const& _lineInfo,
|
||||
StringRef _name,
|
||||
const char* const = nullptr );
|
||||
~Section();
|
||||
|
||||
// This indicates whether the section should be executed or not
|
||||
@@ -38,7 +41,7 @@ namespace Catch {
|
||||
#define INTERNAL_CATCH_SECTION( ... ) \
|
||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
|
||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
|
||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
|
||||
|
||||
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
@@ -17,10 +17,6 @@ namespace Catch {
|
||||
: StringRef( rawChars, std::strlen(rawChars) )
|
||||
{}
|
||||
|
||||
auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
|
||||
return m_size == other.m_size
|
||||
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
|
||||
}
|
||||
|
||||
bool StringRef::operator<(StringRef rhs) const noexcept {
|
||||
if (m_size < rhs.m_size) {
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include <iosfwd>
|
||||
#include <cassert>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
/// A non-owning string class (similar to the forthcoming std::string_view)
|
||||
@@ -49,7 +51,10 @@ namespace Catch {
|
||||
}
|
||||
|
||||
public: // operators
|
||||
auto operator == ( StringRef other ) const noexcept -> bool;
|
||||
auto operator == ( StringRef other ) const noexcept -> bool {
|
||||
return m_size == other.m_size
|
||||
&& (std::memcmp( m_start, other.m_start, m_size ) == 0);
|
||||
}
|
||||
auto operator != (StringRef other) const noexcept -> bool {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
@@ -8,16 +8,24 @@
|
||||
#include <catch2/internal/catch_tag_alias_registry.hpp>
|
||||
#include <catch2/internal/catch_console_colour.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_string_manip.hpp>
|
||||
|
||||
namespace Catch {
|
||||
#include <map>
|
||||
|
||||
TagAliasRegistry::~TagAliasRegistry() {}
|
||||
namespace Catch {
|
||||
struct TagAliasRegistry::TagAliasRegistryImpl {
|
||||
std::map<std::string, TagAlias> registry;
|
||||
};
|
||||
|
||||
|
||||
TagAliasRegistry::TagAliasRegistry():
|
||||
m_impl( Detail::make_unique<TagAliasRegistryImpl>() ){}
|
||||
TagAliasRegistry::~TagAliasRegistry() = default;
|
||||
|
||||
TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
|
||||
auto it = m_registry.find( alias );
|
||||
if( it != m_registry.end() )
|
||||
auto it = m_impl->registry.find( alias );
|
||||
if( it != m_impl->registry.end() )
|
||||
return &(it->second);
|
||||
else
|
||||
return nullptr;
|
||||
@@ -25,7 +33,7 @@ namespace Catch {
|
||||
|
||||
std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
|
||||
std::string expandedTestSpec = unexpandedTestSpec;
|
||||
for( auto const& registryKvp : m_registry ) {
|
||||
for( auto const& registryKvp : m_impl->registry ) {
|
||||
std::size_t pos = expandedTestSpec.find( registryKvp.first );
|
||||
if( pos != std::string::npos ) {
|
||||
expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
|
||||
@@ -40,15 +48,13 @@ namespace Catch {
|
||||
CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
|
||||
"error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
|
||||
|
||||
CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
|
||||
CATCH_ENFORCE( m_impl->registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
|
||||
"error: tag alias, '" << alias << "' already registered.\n"
|
||||
<< "\tFirst seen at: " << find(alias)->lineInfo << "\n"
|
||||
<< "\tRedefined at: " << lineInfo );
|
||||
}
|
||||
|
||||
ITagAliasRegistry::~ITagAliasRegistry() = default;
|
||||
|
||||
ITagAliasRegistry const& ITagAliasRegistry::get() {
|
||||
TagAliasRegistry const& TagAliasRegistry::get() {
|
||||
return getRegistryHub().getTagAliasRegistry();
|
||||
}
|
||||
|
||||
|
@@ -8,24 +8,30 @@
|
||||
#ifndef CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||
#define CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_tag_alias_registry.hpp>
|
||||
#include <catch2/catch_tag_alias.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
struct SourceLineInfo;
|
||||
|
||||
class TagAliasRegistry : public ITagAliasRegistry {
|
||||
class TagAliasRegistry {
|
||||
struct TagAliasRegistryImpl;
|
||||
Detail::unique_ptr<TagAliasRegistryImpl> m_impl;
|
||||
public:
|
||||
~TagAliasRegistry() override;
|
||||
TagAlias const* find( std::string const& alias ) const override;
|
||||
std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
|
||||
TagAliasRegistry();
|
||||
~TagAliasRegistry(); // = default;
|
||||
|
||||
//! Nullptr if not present
|
||||
TagAlias const* find( std::string const& alias ) const;
|
||||
//! Returns the test spec but with expanded aliases
|
||||
std::string expandAliases( std::string const& unexpandedTestSpec ) const;
|
||||
void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
|
||||
|
||||
static TagAliasRegistry const& get();
|
||||
|
||||
private:
|
||||
std::map<std::string, TagAlias> m_registry;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -181,7 +181,7 @@
|
||||
void reg_tests() { \
|
||||
size_t index = 0; \
|
||||
using expander = size_t[]; \
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
|
||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
|
||||
} \
|
||||
};\
|
||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||
@@ -316,7 +316,7 @@
|
||||
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::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||
(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 int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||
|
@@ -9,7 +9,8 @@
|
||||
|
||||
#include <catch2/internal/catch_context.hpp>
|
||||
#include <catch2/internal/catch_enforce.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
|
||||
#include <catch2/interfaces/catch_interfaces_config.hpp>
|
||||
#include <catch2/internal/catch_registry_hub.hpp>
|
||||
#include <catch2/internal/catch_random_number_generator.hpp>
|
||||
#include <catch2/internal/catch_run_context.hpp>
|
||||
#include <catch2/internal/catch_sharding.hpp>
|
||||
@@ -23,6 +24,54 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
static bool matchTest( TestCaseHandle const& testCase,
|
||||
TestSpec const& testSpec,
|
||||
IConfig const& config ) {
|
||||
return testSpec.matches( testCase.getTestCaseInfo() ) &&
|
||||
isThrowSafe( testCase, config );
|
||||
}
|
||||
|
||||
static void enforceNoDuplicateTestCases(
|
||||
std::vector<TestCaseHandle> const& tests ) {
|
||||
auto testInfoCmp = []( TestCaseInfo const* lhs,
|
||||
TestCaseInfo const* rhs ) {
|
||||
return *lhs < *rhs;
|
||||
};
|
||||
std::set<TestCaseInfo const*, decltype( testInfoCmp )&> seenTests(
|
||||
testInfoCmp );
|
||||
for ( auto const& test : tests ) {
|
||||
const auto infoPtr = &test.getTestCaseInfo();
|
||||
const auto prev = seenTests.insert( infoPtr );
|
||||
CATCH_ENFORCE( prev.second,
|
||||
"error: test case \""
|
||||
<< infoPtr->name << "\", with tags \""
|
||||
<< infoPtr->tagsAsString()
|
||||
<< "\" already defined.\n"
|
||||
<< "\tFirst seen at "
|
||||
<< ( *prev.first )->lineInfo << "\n"
|
||||
<< "\tRedefined at " << infoPtr->lineInfo );
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct TestCaseRegistry::TestCaseRegistryImpl {
|
||||
std::vector<Detail::unique_ptr<TestCaseInfo>> owned_test_infos;
|
||||
// Keeps a materialized vector for `getAllInfos`.
|
||||
// We should get rid of that eventually (see interface note)
|
||||
std::vector<TestCaseInfo*> viewed_test_infos;
|
||||
|
||||
std::vector<Detail::unique_ptr<ITestInvoker>> invokers;
|
||||
std::vector<TestCaseHandle> handles;
|
||||
mutable TestRunOrder currentSortOrder = TestRunOrder::Declared;
|
||||
mutable std::vector<TestCaseHandle> sortedFunctions;
|
||||
};
|
||||
|
||||
TestCaseRegistry::TestCaseRegistry():
|
||||
m_impl( Detail::make_unique<TestCaseRegistryImpl>() ) {}
|
||||
TestCaseRegistry ::~TestCaseRegistry() = default;
|
||||
|
||||
|
||||
std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
|
||||
switch (config.runOrder()) {
|
||||
case TestRunOrder::Declared:
|
||||
@@ -79,29 +128,6 @@ namespace Catch {
|
||||
return !testCase.getTestCaseInfo().throws() || config.allowThrows();
|
||||
}
|
||||
|
||||
bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) {
|
||||
return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config );
|
||||
}
|
||||
|
||||
void
|
||||
enforceNoDuplicateTestCases( std::vector<TestCaseHandle> const& tests ) {
|
||||
auto testInfoCmp = []( TestCaseInfo const* lhs,
|
||||
TestCaseInfo const* rhs ) {
|
||||
return *lhs < *rhs;
|
||||
};
|
||||
std::set<TestCaseInfo const*, decltype(testInfoCmp) &> seenTests(testInfoCmp);
|
||||
for ( auto const& test : tests ) {
|
||||
const auto infoPtr = &test.getTestCaseInfo();
|
||||
const auto prev = seenTests.insert( infoPtr );
|
||||
CATCH_ENFORCE(
|
||||
prev.second,
|
||||
"error: test case \"" << infoPtr->name << "\", with tags \""
|
||||
<< infoPtr->tagsAsString() << "\" already defined.\n"
|
||||
<< "\tFirst seen at " << ( *prev.first )->lineInfo << "\n"
|
||||
<< "\tRedefined at " << infoPtr->lineInfo );
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
|
||||
std::vector<TestCaseHandle> filtered;
|
||||
filtered.reserve( testCases.size() );
|
||||
@@ -117,36 +143,29 @@ namespace Catch {
|
||||
return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
|
||||
}
|
||||
|
||||
void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
|
||||
m_handles.emplace_back(testInfo.get(), testInvoker.get());
|
||||
m_viewed_test_infos.push_back(testInfo.get());
|
||||
m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
|
||||
m_invokers.push_back(CATCH_MOVE(testInvoker));
|
||||
void TestCaseRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
|
||||
m_impl->handles.emplace_back(testInfo.get(), testInvoker.get());
|
||||
m_impl->viewed_test_infos.push_back(testInfo.get());
|
||||
m_impl->owned_test_infos.push_back(CATCH_MOVE(testInfo));
|
||||
m_impl->invokers.push_back(CATCH_MOVE(testInvoker));
|
||||
}
|
||||
|
||||
std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
|
||||
return m_viewed_test_infos;
|
||||
std::vector<TestCaseInfo*> const& TestCaseRegistry::getAllInfos() const {
|
||||
return m_impl->viewed_test_infos;
|
||||
}
|
||||
|
||||
std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
|
||||
return m_handles;
|
||||
std::vector<TestCaseHandle> const& TestCaseRegistry::getAllTests() const {
|
||||
return m_impl->handles;
|
||||
}
|
||||
std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
|
||||
if( m_sortedFunctions.empty() )
|
||||
enforceNoDuplicateTestCases( m_handles );
|
||||
std::vector<TestCaseHandle> const& TestCaseRegistry::getAllTestsSorted( IConfig const& config ) const {
|
||||
if( m_impl->sortedFunctions.empty() )
|
||||
enforceNoDuplicateTestCases( m_impl->handles );
|
||||
|
||||
if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
|
||||
m_sortedFunctions = sortTests( config, m_handles );
|
||||
m_currentSortOrder = config.runOrder();
|
||||
if( m_impl->currentSortOrder != config.runOrder() || m_impl->sortedFunctions.empty() ) {
|
||||
m_impl->sortedFunctions = sortTests( config, m_impl->handles );
|
||||
m_impl->currentSortOrder = config.runOrder();
|
||||
}
|
||||
return m_sortedFunctions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void TestInvokerAsFunction::invoke() const {
|
||||
m_testAsFunction();
|
||||
return m_impl->sortedFunctions;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user