Compare commits

...

53 Commits

Author SHA1 Message Date
Martin Hořeňovský
6e79e682b7 v3.4.0 2023-07-13 13:37:30 +02:00
Martin Hořeňovský
683c85772f Clean up explanation in tests 2023-07-12 11:49:43 +02:00
Martin Hořeňovský
1b049bdba4 2 more TEST_CASEs to DiscoverTests/register-tests.cpp 2023-07-04 00:06:24 +02:00
Martin Hořeňovský
e4b16053a6 Escape Catch2 test names in catch_discover_tests tests 2023-06-15 14:19:39 +02:00
Robin Christ
42ee66b5e6 Fix handling of semicolon and backslash characters in CMake test discovery (#2676)
This PR fixes the handling of semicolon and backslash characters in test names in the CMake test discovery

Closes #2674
2023-06-14 23:40:10 +02:00
Martin Hořeňovský
a0c6a28460 Fix possible FP in catch_discover_tests tests 2023-06-14 23:31:41 +02:00
Martin Hořeňovský
c8363143e7 Add test scaffolding for catch_discover_tests 2023-06-14 21:14:33 +02:00
Martin Hořeňovský
7a52dfa77b Fix typo in cross-docs links 2023-06-11 19:37:15 +02:00
Vertexwahn
9131736630 Bazel support: Update skylib 2023-06-08 13:30:50 +02:00
Martin Hořeňovský
0631b607ee Test & document SKIP in generator constructor
Closes #1593
2023-05-31 15:12:43 +02:00
Martin Hořeňovský
dff7513b28 Static analysis cleanup in tests 2023-05-29 21:45:30 +02:00
Martin Hořeňovský
bf5aa7b383 Experimental static analysis support in TEST_CASE and SECTION
Closes #2681
2023-05-29 21:45:28 +02:00
Martin Hořeňovský
dba9197ec7 Add new config option: STATIC_ANALYSIS_SUPPORT 2023-05-29 00:55:20 +02:00
Martin Hořeňovský
f60c15364b Add macro for suppressing Wshadow 2023-05-28 21:07:31 +02:00
Martin Hořeňovský
b3cf1bfb5d Avoid unused variable warning in GeneratorsImpl tests 2023-05-28 21:05:01 +02:00
Martin Hořeňovský
73b93ce6bc Include catch_user_config.hpp in all catch_config_* files 2023-05-28 21:04:16 +02:00
Martin Hořeňovský
8008625d7e Merge pull request #2693 from Ali-Amir/u/ali/optional-meson-unit-tests
Add option to disable building unit tests in Meson build file.
2023-05-27 12:00:52 +02:00
Ali-Amir Aldan
ce7b153021 Add option to disable building unit tests in Meson build file. 2023-05-26 10:05:06 -07:00
Cristian Morales Vega
535205e2ac Suppress -Wunused-result warning in gcc
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425.
2023-05-23 23:31:55 +02:00
Martin Hořeňovský
689fdcd7dc Fix some tests never being run 2023-05-20 22:03:48 +02:00
Martin Hořeňovský
a153fce724 Improve error messages for TEST_CASE tag parsing errors
Also removes a duplicated test case checking for empty tag error.

Related to #2650
2023-05-20 21:13:48 +02:00
Martin Hořeňovský
06c0e1cfab Merge pull request #2689 from ThePhD/fix/includes/header-exception
🛠💚 Add <exception> header where strictly necessary
2023-05-16 18:41:19 +02:00
ThePhD
05d7eb5a00 🛠 Add <exception> header where strictly necessary 2023-05-16 12:18:57 -04:00
Valeri
f53bb3ae7b meson: require version >=0.54.1
See discussion in https://github.com/mesonbuild/wrapdb/pull/1016.
2023-05-15 17:41:56 +02:00
Martin Hořeňovský
ce8a7b3390 Merge pull request #2687 from ChrisThrasher/sfml
Add SFML to the list of open source users
2023-05-15 13:44:59 +02:00
Chris Thrasher
6dce539fad Add SFML to the list of open source users 2023-05-13 14:34:34 -06:00
Yaroslav
5a40b2275c Update CatchConfigOptions.cmake
Fix CMake warning

CMake Warning (dev) at catch2-src/CMake/CatchConfigOptions.cmake:71 (set):
  uninitialized variable 'BUILD_SHARED_LIBS'
2023-05-12 13:52:45 +02:00
Martin Hořeňovský
598895d048 Fix Wredundant-decls
Closes #2682
2023-05-12 09:51:13 +02:00
Martin Hořeňovský
0dc82e08df Move CATCH_INTERNAL_STRINGIFY macro into its own header 2023-05-07 20:58:54 +02:00
Martin Hořeňovský
8ca504cbc9 Move AssertionResult when passing it inside RunContext 2023-05-06 23:58:48 +02:00
Martin Hořeňovský
c57b5cdf43 Move-enable Catch::optional
This avoids copies in couple places through Catch2, e.g. reporter
spec handling, and moving around `AssertionResult` in `RunContext`.
2023-05-06 15:22:02 +02:00
Martin Hořeňovský
d84777c9cb Fix assertionStarting events being sent after the expr is evaluated
Closes #2678
2023-05-06 11:48:41 +02:00
Martin Hořeňovský
51fdbedd13 Internal linkage for outlier_variance 2023-05-01 13:21:47 +02:00
Martin Hořeňovský
10f0a58643 Some template instantiation reductions 2023-05-01 13:21:45 +02:00
Martin Hořeňovský
fe64c28925 Reduce compilation costs of benchmarks
We replaced some simple std::algorithm usage by loops, and reduced
header inclusion.
2023-05-01 13:21:41 +02:00
Martin Hořeňovský
7d07efc92b Clean up iterator usage in benchmarks
Specifically we turned `mean`, `classify_outliers`, `jackknife`,
into concrete functions that take only `const_iterator` from vecs,
instead of generic iterators over anything.

I also changed `resample` to take `const_iterator` instead of
plain `iterator`, and similar for `standard_deviation`, and
`analyse_samples`.
2023-05-01 13:21:36 +02:00
Martin Hořeňovský
f3c678c0ab Constexprify constants in estimate_clock.hpp 2023-05-01 13:21:33 +02:00
Vertexwahn
46539b6d9b Fix spelling 2023-04-29 12:55:51 +02:00
Holger Kaelberer
10596b2278 Fix unreachable-code-return warnings 2023-04-20 14:53:03 +02:00
Holger Kaelberer
897fe2a01b cmake: Improve unreachable-code warnings
Enable CI to report -Wunreachable-code-aggressive warnings in clang
builds which covers all,  -Wunreachable-code, -code-break,
-code-return.
2023-04-20 14:53:03 +02:00
Holger Kaelberer
aad926baf8 Catch.cmake: Add new DISCOVERY_MODE option to catch_discover_tests
Introducing a new DISCOVERY_MODE mode option, which provides greater
control over when catch_discover_tests perforsm test discovery.

It has two supported modes:
* POST_BUILD: The default behavior, which adds a POST_BUILD command
  to perform test discovery after the test has been built as was
  always done so far.

* PRE_TEST: New mode, which delays test discovery until test execution.
  The generated include file generates the appropriate CTest files at
  runtime and regenerates the CTest files when the executable is
  updated.
  This mode can be used in build-environments that don't allow for
  executing the linked binaries at build-time (like in a
  cross-compilation environment).

DISCOVERY_MODE can be controlled in two ways:
1. Setting the DISCOVERY_MODE when calling catch_discover_tests.

2. Setting the global CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE prior
   to calling gtest_discover_tests.

Closes #2493
2023-04-19 23:51:42 +02:00
Holger Kaelberer
4e8399d835 CatchAddTests.cmake: Refactor into callable method
Move test discovery logic into new catch_discover_tests_impl method
and make CatchAddTests aware of whether it is being launched in
CMake's script mode.

When launched in script mode, catch_discover_tests_impl is called
passing arguments obtained from the definitions passed into the call
to cmake. This preserves the existing behavior assumed by Catch.cmake.

Looking ahead, it also allows CatchAddTests to be included in
generated files and call catch_discover_tests_impl to perform test
discovery at test runtime with the new PRE_TEST discovery mode
introduced later.
2023-04-19 23:51:42 +02:00
Martin Hořeňovský
9a2a4eadc0 Bump xml-format-version in XML reporter 2023-04-10 21:59:50 +02:00
Martin Hořeňovský
fb806da76f Add lineinfo to XML reporter output for INFO/WARN
Closes #1251
2023-04-10 16:32:07 +02:00
Arne Mertz
50bf00e266 Fix reporter detection in catch_discover_tests
Closes #2668
Instead of grepping for the reporter, use it in the process and check for the error code
2023-04-05 10:12:50 +02:00
Martin Hořeňovský
9f08097f55 Cleanup internal includes by splitting out some event structs
* Split out BenchmarkInfo and BenchmarkStats to their own header
* Outline BenchmarkStats<> declaration to separate header
* Split out TestRunInfo into its own header

These changes let us remove the large `interfaces_reporter.hpp`
include from `benchmark.hpp`, and replace it with
`interfaces_capture.hpp` in `run_context.hpp`.

I also cleaned out `interfaces_repoter.hpp` from reporter headers
that depend on `reporter_common_base.hpp`. This will not change
anything in the actual inclusion set, but makes it logically
more consistent.
2023-03-31 19:31:51 +02:00
Martin Hořeňovský
1f881ab464 Split ITestInvoker into its own header 2023-03-23 16:50:11 +01:00
Martin Hořeňovský
c487b27d9d Reduce misc includes all around 2023-03-23 16:50:07 +01:00
Martin Hořeňovský
3230760db2 Cleanup in translating exceptions to messages 2023-03-23 12:26:44 +01:00
Martin Hořeňovský
b3ebce715e Cleanup benchmarking includes 2023-03-23 11:59:40 +01:00
Martin Hořeňovský
d0f70fdfd6 Unify IReporterRegistry and ReporterRegistry
To keep the compilation firewall effect, the implementations
are hidden behind a PIMPL. In this case it is probably not
worth it, but we can inline it later if needed.
2023-03-22 23:58:44 +01:00
Martin Hořeňovský
4f4ad8ada9 Sprinkle some constexpr around 2023-03-22 19:12:32 +01:00
Martin Hořeňovský
5b665be643 Cut out catch_interfaces_capture.hpp include from the main include 2023-03-22 19:12:03 +01:00
138 changed files with 4285 additions and 3025 deletions

View File

@@ -29,13 +29,13 @@ jobs:
build_type: Debug build_type: Debug
std: 14 std: 14
other_pkgs: g++-7 other_pkgs: g++-7
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
- cxx: g++-7 - cxx: g++-7
build_description: Extras + Examples build_description: Extras + Examples
build_type: Release build_type: Release
std: 14 std: 14
other_pkgs: g++-7 other_pkgs: g++-7
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
# Extras and examples with Clang-10 # Extras and examples with Clang-10
- cxx: clang++-10 - cxx: clang++-10
@@ -43,13 +43,13 @@ jobs:
build_type: Debug build_type: Debug
std: 17 std: 17
other_pkgs: clang-10 other_pkgs: clang-10
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
- cxx: clang++-10 - cxx: clang++-10
build_description: Extras + Examples build_description: Extras + Examples
build_type: Release build_type: Release
std: 17 std: 17
other_pkgs: clang-10 other_pkgs: clang-10
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
# Configure tests with Clang-10 # Configure tests with Clang-10
- cxx: clang++-10 - cxx: clang++-10

View File

@@ -43,12 +43,14 @@ expand_template(
"#cmakedefine CATCH_CONFIG_NO_GLOBAL_NEXTAFTER": "", "#cmakedefine CATCH_CONFIG_NO_GLOBAL_NEXTAFTER": "",
"#cmakedefine CATCH_CONFIG_NO_POSIX_SIGNALS": "", "#cmakedefine CATCH_CONFIG_NO_POSIX_SIGNALS": "",
"#cmakedefine CATCH_CONFIG_NO_USE_ASYNC": "", "#cmakedefine CATCH_CONFIG_NO_USE_ASYNC": "",
"#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT": "",
"#cmakedefine CATCH_CONFIG_NO_WCHAR": "", "#cmakedefine CATCH_CONFIG_NO_WCHAR": "",
"#cmakedefine CATCH_CONFIG_NO_WINDOWS_SEH": "", "#cmakedefine CATCH_CONFIG_NO_WINDOWS_SEH": "",
"#cmakedefine CATCH_CONFIG_NOSTDOUT": "", "#cmakedefine CATCH_CONFIG_NOSTDOUT": "",
"#cmakedefine CATCH_CONFIG_POSIX_SIGNALS": "", "#cmakedefine CATCH_CONFIG_POSIX_SIGNALS": "",
"#cmakedefine CATCH_CONFIG_PREFIX_ALL": "", "#cmakedefine CATCH_CONFIG_PREFIX_ALL": "",
"#cmakedefine CATCH_CONFIG_SHARED_LIBRARY": "", "#cmakedefine CATCH_CONFIG_SHARED_LIBRARY": "",
"#cmakedefine CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT": "",
"#cmakedefine CATCH_CONFIG_USE_ASYNC": "", "#cmakedefine CATCH_CONFIG_USE_ASYNC": "",
"#cmakedefine CATCH_CONFIG_WCHAR": "", "#cmakedefine CATCH_CONFIG_WCHAR": "",
"#cmakedefine CATCH_CONFIG_WINDOWS_CRTDBG": "", "#cmakedefine CATCH_CONFIG_WINDOWS_CRTDBG": "",

View File

@@ -41,6 +41,7 @@ set(_OverridableOptions
"WCHAR" "WCHAR"
"WINDOWS_SEH" "WINDOWS_SEH"
"GETENV" "GETENV"
"EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT"
) )
foreach(OptionName ${_OverridableOptions}) foreach(OptionName ${_OverridableOptions})
@@ -68,7 +69,11 @@ set(_OtherConfigOptions
foreach(OptionName ${_OtherConfigOptions}) foreach(OptionName ${_OtherConfigOptions})
AddConfigOption(${OptionName}) AddConfigOption(${OptionName})
endforeach() endforeach()
set(CATCH_CONFIG_SHARED_LIBRARY ${BUILD_SHARED_LIBS}) if(DEFINED BUILD_SHARED_LIBS)
set(CATCH_CONFIG_SHARED_LIBRARY ${BUILD_SHARED_LIBS})
else()
set(CATCH_CONFIG_SHARED_LIBRARY "")
endif()
set(CATCH_CONFIG_DEFAULT_REPORTER "console" CACHE STRING "Read docs/configuration.md for details. The name of the reporter should be without quotes.") set(CATCH_CONFIG_DEFAULT_REPORTER "console" CACHE STRING "Read docs/configuration.md for details. The name of the reporter should be without quotes.")
set(CATCH_CONFIG_CONSOLE_WIDTH "80" CACHE STRING "Read docs/configuration.md for details. Must form a valid integer literal.") set(CATCH_CONFIG_CONSOLE_WIDTH "80" CACHE STRING "Read docs/configuration.md for details. Must form a valid integer literal.")

View File

@@ -74,6 +74,7 @@ function(add_warnings_to_targets targets)
"-Woverloaded-virtual" "-Woverloaded-virtual"
"-Wparentheses" "-Wparentheses"
"-Wpedantic" "-Wpedantic"
"-Wredundant-decls"
"-Wreorder" "-Wreorder"
"-Wreturn-std-move" "-Wreturn-std-move"
"-Wshadow" "-Wshadow"
@@ -83,7 +84,7 @@ function(add_warnings_to_targets targets)
"-Wundef" "-Wundef"
"-Wuninitialized" "-Wuninitialized"
"-Wunneeded-internal-declaration" "-Wunneeded-internal-declaration"
"-Wunreachable-code" "-Wunreachable-code-aggressive"
"-Wunused" "-Wunused"
"-Wunused-function" "-Wunused-function"
"-Wunused-parameter" "-Wunused-parameter"

View File

@@ -21,6 +21,7 @@ cmake_dependent_option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io"
cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_ENABLE_WERROR "Enables Werror during build" ON "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_BUILD_SURROGATES "Enable generating and building surrogate TUs for the main headers" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_ENABLE_CONFIGURE_TESTS "Enable CMake configuration tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF) cmake_dependent_option(CATCH_ENABLE_CONFIGURE_TESTS "Enable CMake configuration tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
cmake_dependent_option(CATCH_ENABLE_CMAKE_HELPER_TESTS "Enable CMake helper tests. WARNING: VERY EXPENSIVE" OFF "CATCH_DEVELOPMENT_BUILD" OFF)
# Catch2's build breaks if done in-tree. You probably should not build # Catch2's build breaks if done in-tree. You probably should not build
@@ -31,7 +32,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif() endif()
project(Catch2 project(Catch2
VERSION 3.3.2 # CML version placeholder, don't delete VERSION 3.4.0 # CML version placeholder, don't delete
LANGUAGES CXX LANGUAGES CXX
# HOMEPAGE_URL is not supported until CMake version 3.12, which # HOMEPAGE_URL is not supported until CMake version 3.12, which
# we do not target yet. # we do not target yet.

View File

@@ -18,7 +18,8 @@
"CATCH_BUILD_EXAMPLES": "ON", "CATCH_BUILD_EXAMPLES": "ON",
"CATCH_BUILD_EXTRA_TESTS": "ON", "CATCH_BUILD_EXTRA_TESTS": "ON",
"CATCH_BUILD_SURROGATES": "ON", "CATCH_BUILD_SURROGATES": "ON",
"CATCH_ENABLE_CONFIGURE_TESTS": "ON" "CATCH_ENABLE_CONFIGURE_TESTS": "ON",
"CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
} }
} }
] ]

View File

@@ -4,10 +4,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive( http_archive(
name = "bazel_skylib", name = "bazel_skylib",
sha256 = "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7", sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa",
urls = [ urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz",
"https://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.2/bazel-skylib-1.4.2.tar.gz",
], ],
) )

View File

@@ -126,6 +126,7 @@ catch_discover_tests(target
[OUTPUT_DIR dir] [OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix] [OUTPUT_PREFIX prefix]
[OUTPUT_SUFFIX suffix] [OUTPUT_SUFFIX suffix]
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
) )
``` ```
@@ -198,6 +199,16 @@ If specified, `suffix` is added to each output file name, like so
`--out dir/<test_name>suffix`. This can be used to add a file extension to `--out dir/<test_name>suffix`. This can be used to add a file extension to
the output file name e.g. ".xml". the output file name e.g. ".xml".
* `DISCOVERY_MODE mode`
If specified allows control over when test discovery is performed.
For a value of `POST_BUILD` (default) test discovery is performed at build time.
For a a value of `PRE_TEST` test discovery is delayed until just prior to test
execution (useful e.g. in cross-compilation environments).
``DISCOVERY_MODE`` defaults to the value of the
``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when
calling ``catch_discover_tests``. This provides a mechanism for globally
selecting a preferred test discovery behavior.
### `ParseAndAddCatchTests.cmake` ### `ParseAndAddCatchTests.cmake`

View File

@@ -15,6 +15,7 @@
[Enabling stringification](#enabling-stringification)<br> [Enabling stringification](#enabling-stringification)<br>
[Disabling exceptions](#disabling-exceptions)<br> [Disabling exceptions](#disabling-exceptions)<br>
[Overriding Catch's debug break (`-b`)](#overriding-catchs-debug-break--b)<br> [Overriding Catch's debug break (`-b`)](#overriding-catchs-debug-break--b)<br>
[Static analysis support](#static-analysis-support)<br>
Catch2 is designed to "just work" as much as possible, and most of the Catch2 is designed to "just work" as much as possible, and most of the
configuration options below are changed automatically during compilation, configuration options below are changed automatically during compilation,
@@ -264,6 +265,31 @@ The macro will be used as is, that is, `CATCH_BREAK_INTO_DEBUGGER();`
must compile and must break into debugger. must compile and must break into debugger.
## Static analysis support
> Introduced in Catch2 3.4.0.
Some parts of Catch2, e.g. `SECTION`s, can be hard for static analysis
tools to reason about. Catch2 can change its internals to help static
analysis tools reason about the tests.
Catch2 automatically detects some static analysis tools (initial
implementation checks for clang-tidy and Coverity), but you can override
its detection (in either direction) via
```
CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT // force enables static analysis help
CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT // force disables static analysis help
```
_As the name suggests, this is currently experimental, and thus we provide
no backwards compatibility guarantees._
**DO NOT ENABLE THIS FOR BUILDS YOU INTEND TO RUN.** The changed internals
are not meant to be runnable, only "scannable".
--- ---
[Home](Readme.md#top) [Home](Readme.md#top)

View File

@@ -28,7 +28,7 @@ depending on how often the cleanup needs to happen.
## Why cannot I derive from the built-in reporters? ## Why cannot I derive from the built-in reporters?
They are not made to be overridden, in that we do not attempt to maintain They are not made to be overridden, in that we do not attempt to maintain
a consistent internal state if a member function is overriden, and by a consistent internal state if a member function is overridden, and by
forbidding users from using them as a base class, we can refactor them forbidding users from using them as a base class, we can refactor them
as needed later. as needed later.

View File

@@ -134,7 +134,7 @@ type, making their usage much nicer. These are
* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`) * `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>` * `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator` * `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
* `range(Arithemtic start, Arithmetic end)` for `RangeGenerator<Arithmetic>` with a step size of `1` * `range(Arithmetic start, Arithmetic end)` for `RangeGenerator<Arithmetic>` with a step size of `1`
* `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator<Arithmetic>` with a custom step size * `range(Arithmetic start, Arithmetic end, Arithmetic step)` for `RangeGenerator<Arithmetic>` with a custom step size
* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>` * `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>`
* `from_range(Container const&)` for `IteratorGenerator<T>` * `from_range(Container const&)` for `IteratorGenerator<T>`
@@ -221,3 +221,21 @@ For full example of implementing your own generator, look into Catch2's
examples, specifically examples, specifically
[Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp). [Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp).
### Handling empty generators
The generator interface assumes that a generator always has at least one
element. This is not always true, e.g. if the generator depends on an external
datafile, the file might be missing.
There are two ways to handle this, depending on whether you want this
to be an error or not.
* If empty generator **is** an error, throw an exception in constructor.
* If empty generator **is not** an error, use the [`SKIP`](skipping-passing-failing.md#skipping-test-cases-at-runtime) in constructor.
---
[Home](Readme.md#top)

View File

@@ -95,6 +95,9 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp) ### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
A library of algorithms for values-distributed-in-time. A library of algorithms for values-distributed-in-time.
### [SFML](https://github.com/SFML/SFML)
Simple and Fast Multimedia Library.
### [SOCI](https://github.com/SOCI/soci) ### [SOCI](https://github.com/SOCI/soci)
The C++ Database Access Library. The C++ Database Access Library.
@@ -143,7 +146,7 @@ Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
A 2D, Zombie, RPG game which is being made on our own engine. A 2D, Zombie, RPG game which is being made on our own engine.
### [raspigcd](https://github.com/pantadeusz/raspigcd) ### [raspigcd](https://github.com/pantadeusz/raspigcd)
Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks). Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrollers (just RPi + Stepsticks).
### [SpECTRE](https://github.com/sxs-collaboration/spectre) ### [SpECTRE](https://github.com/sxs-collaboration/spectre)
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics. SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.

View File

@@ -57,6 +57,34 @@
## 3.4.0
### Improvements
* `VectorEquals` supports elements that provide only `==` and not `!=` (#2648)
* Catch2 supports compiling with IAR compiler (#2651)
* Various small internal performance improvements
* Various small internal compilation time improvements
* XMLReporter now reports location info for INFO and WARN (#1251)
* This bumps up the xml format version to 3
* Documented that `SKIP` in generator constructor can be used to handle empty generator (#1593)
* Added experimental static analysis support to `TEST_CASE` and `SECTION` macros (#2681)
* The two macros are redefined in a way that helps the SA tools reason about the possible paths through a test case with sections.
* The support is controlled by the `CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT` option and autodetects clang-tidy and Coverity.
* `*_THROWS`, `*_THROWS_AS`, etc now suppress warning coming from `__attribute__((warn_unused_result))` on GCC (#2691)
* Unlike plain `[[nodiscard]]`, this warning is not silenced by void cast. WTF GCC?
### Fixes
* Fixed `assertionStarting` events being sent after the expr is evaluated (#2678)
* Errors in `TEST_CASE` tags are now reported nicely (#2650)
### Miscellaneous
* Bunch of improvements to `catch_discover_tests`
* Added DISCOVERY_MODE option, so the discovery can happen either post build or pre-run.
* Fixed handling of semicolons and backslashes in test names (#2674, #2676)
* meson build can disable building tests (#2693)
* meson build properly sets meson version 0.54.1 as the minimal supported version (#2688)
## 3.3.2 ## 3.3.2
### Improvements ### Improvements
@@ -149,7 +177,7 @@
### Fixes ### Fixes
* Cleaned out some warnings and static analysis issues * Cleaned out some warnings and static analysis issues
* Suppressed `-Wcomma` warning rarely occuring in templated test cases (#2543) * Suppressed `-Wcomma` warning rarely occurring in templated test cases (#2543)
* Constified implementation details in `INFO` (#2564) * Constified implementation details in `INFO` (#2564)
* Made `MatcherGenericBase` copy constructor const (#2566) * Made `MatcherGenericBase` copy constructor const (#2566)
* Fixed serialization of test filters so the output roundtrips * Fixed serialization of test filters so the output roundtrips
@@ -517,7 +545,7 @@ v3 releases.
* The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will. * The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will.
* Added `-D`/`--min-duration` command line flag (#1910) * Added `-D`/`--min-duration` command line flag (#1910)
* If a test takes longer to finish than the provided value, its name and duration will be printed. * If a test takes longer to finish than the provided value, its name and duration will be printed.
* This flag is overriden by setting `-d`/`--duration`. * This flag is overridden by setting `-d`/`--duration`.
### Fixes ### Fixes
* `TAPReporter` no longer skips successful assertions (#1983) * `TAPReporter` no longer skips successful assertions (#1983)
@@ -585,7 +613,7 @@ v3 releases.
### Fixes ### Fixes
* Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886) * Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886)
* Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901) * Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901)
* It was a false positive trigered by the new warning support workaround * It was a false positive triggered by the new warning support workaround
* Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905) * Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905)
### Miscellaneous ### Miscellaneous
@@ -922,7 +950,7 @@ v3 releases.
### Contrib ### Contrib
* `ParseAndAddCatchTests` has learned how to use `DISABLED` CTest property (#1452) * `ParseAndAddCatchTests` has learned how to use `DISABLED` CTest property (#1452)
* `ParseAndAddCatchTests` now works when there is a whitspace before the test name (#1493) * `ParseAndAddCatchTests` now works when there is a whitespace before the test name (#1493)
### Miscellaneous ### Miscellaneous

View File

@@ -96,12 +96,12 @@ void assertionStarting( AssertionInfo const& assertionInfo );
void assertionEnded( AssertionStats const& assertionStats ); void assertionEnded( AssertionStats const& assertionStats );
``` ```
`assertionStarting` is called after the expression is captured, but before The `assertionStarting` event is emitted before the expression in the
the assertion expression is evaluated. This might seem like a minor assertion is captured or evaluated and `assertionEnded` is emitted
distinction, but what it means is that if you have assertion like afterwards. This means that given assertion like `REQUIRE(a + b == c + d)`,
`REQUIRE( a + b == c + d )`, then what happens is that `a + b` and `c + d` Catch2 first emits `assertionStarting` event, then `a + b` and `c + d`
are evaluated before `assertionStarting` is emitted, while the `==` is are evaluated, then their results are captured, the comparison is evaluated,
evaluated after the event. and then `assertionEnded` event is emitted.
## Benchmarking events ## Benchmarking events

View File

@@ -52,7 +52,7 @@ its machine-readable XML output to file `result-junit.xml`, and the
uses ANSI colour codes for colouring the output. uses ANSI colour codes for colouring the output.
Using multiple reporters (or one reporter and one-or-more [event Using multiple reporters (or one reporter and one-or-more [event
listeners](event-listener.md#top)) can have surprisingly complex semantics listeners](event-listeners.md#top)) can have surprisingly complex semantics
when using customization points provided to reporters by Catch2, namely when using customization points provided to reporters by Catch2, namely
capturing stdout/stderr from test cases. capturing stdout/stderr from test cases.

View File

@@ -84,6 +84,12 @@ 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) be overridden using the [--allow-running-no-tests](command-line.md#no-tests-override)
flag. flag.
### `SKIP` inside generators
You can also use the `SKIP` macro inside generator's constructor to handle
cases where the generator is empty, but you do not want to fail the test
case.
## Passing and failing test cases ## Passing and failing test cases

View File

@@ -44,11 +44,11 @@ TEST_CASE("Table allows pre-computed test inputs and outputs", "[example][genera
/* Possible simplifications where less legacy toolchain support is needed: /* Possible simplifications where less legacy toolchain support is needed:
* *
* - With libstdc++6 or newer, the make_tuple() calls can be ommitted * - With libstdc++6 or newer, the make_tuple() calls can be omitted
* (technically C++17 but does not require -std in GCC/Clang). See * (technically C++17 but does not require -std in GCC/Clang). See
* https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list * https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
* *
* - In C++17 mode std::tie() and the preceding variable delcarations can be * - In C++17 mode std::tie() and the preceding variable declarations can be
* replaced by structured bindings: auto [test_input, expected] = GENERATE( * replaced by structured bindings: auto [test_input, expected] = GENERATE(
* table<std::string, size_t>({ ... * table<std::string, size_t>({ ...
*/ */

View File

@@ -35,8 +35,9 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
[TEST_LIST var] [TEST_LIST var]
[REPORTER reporter] [REPORTER reporter]
[OUTPUT_DIR dir] [OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix} [OUTPUT_PREFIX prefix]
[OUTPUT_SUFFIX suffix] [OUTPUT_SUFFIX suffix]
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
) )
``catch_discover_tests`` sets up a post-build command on the test executable ``catch_discover_tests`` sets up a post-build command on the test executable
@@ -123,14 +124,28 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
test executable and when the tests are executed themselves. This requires test executable and when the tests are executed themselves. This requires
cmake/ctest >= 3.22. cmake/ctest >= 3.22.
`DISCOVERY_MODE mode``
Provides control over when ``catch_discover_tests`` performs test discovery.
By default, ``POST_BUILD`` sets up a post-build command to perform test discovery
at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD``
behavior is not desirable. By contrast, ``PRE_TEST`` delays test discovery until
just prior to test execution. This way test discovery occurs in the target environment
where the test has a better chance at finding appropriate runtime dependencies.
``DISCOVERY_MODE`` defaults to the value of the
``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when
calling ``catch_discover_tests``. This provides a mechanism for globally selecting
a preferred test discovery behavior without having to modify each call site.
#]=======================================================================] #]=======================================================================]
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
function(catch_discover_tests TARGET) function(catch_discover_tests TARGET)
cmake_parse_arguments( cmake_parse_arguments(
"" ""
"" ""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX" "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS" "TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS"
${ARGN} ${ARGN}
) )
@@ -141,12 +156,20 @@ function(catch_discover_tests TARGET)
if(NOT _TEST_LIST) if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS) set(_TEST_LIST ${TARGET}_TESTS)
endif() endif()
if (_DL_PATHS) if (_DL_PATHS)
if(${CMAKE_VERSION} VERSION_LESS "3.22.0") if(${CMAKE_VERSION} VERSION_LESS "3.22.0")
message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22") message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22")
endif() endif()
endif() endif()
if(NOT _DISCOVERY_MODE)
if(NOT CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE)
set(CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD")
endif()
set(_DISCOVERY_MODE ${CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE})
endif()
if (NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$")
message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}")
endif()
## Generate a unique name based on the extra arguments ## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}") string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
@@ -159,6 +182,8 @@ function(catch_discover_tests TARGET)
TARGET ${TARGET} TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR PROPERTY CROSSCOMPILING_EMULATOR
) )
if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
add_custom_command( add_custom_command(
TARGET ${TARGET} POST_BUILD TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}" BYPRODUCTS "${ctest_tests_file}"
@@ -191,6 +216,42 @@ function(catch_discover_tests TARGET)
"endif()\n" "endif()\n"
) )
elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST")
string(CONCAT ctest_include_content
"if(EXISTS \"$<TARGET_FILE:${TARGET}>\")" "\n"
" if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n"
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\" OR\n"
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n"
" include(\"${_CATCH_DISCOVER_TESTS_SCRIPT}\")" "\n"
" catch_discover_tests_impl(" "\n"
" TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
" TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
" TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
" TEST_SPEC" " [==[" "${_TEST_SPEC}" "]==]" "\n"
" TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
" TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"
" TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n"
" TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n"
" TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n"
" TEST_REPORTER" " [==[" "${_REPORTER}" "]==]" "\n"
" TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR}" "]==]" "\n"
" TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX}" "]==]" "\n"
" TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX}" "]==]" "\n"
" CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n"
" TEST_DL_PATHS" " [==[" "${_DL_PATHS}" "]==]" "\n"
" CTEST_FILE" " [==[" "${CTEST_FILE}" "]==]" "\n"
" )" "\n"
" endif()" "\n"
" include(\"${ctest_tests_file}\")" "\n"
"else()" "\n"
" add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n"
"endif()" "\n"
)
file(GENERATE OUTPUT "${ctest_include_file}" CONTENT "${ctest_include_content}")
endif()
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0") if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES # Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY set_property(DIRECTORY
@@ -204,9 +265,7 @@ function(catch_discover_tests TARGET)
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}" PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
) )
else() else()
message(FATAL_ERROR message(FATAL_ERROR "Cannot set more than one TEST_INCLUDE_FILE")
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif() endif()
endif() endif()

View File

@@ -1,28 +1,6 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details. # file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(reporter ${TEST_REPORTER})
set(output_dir ${TEST_OUTPUT_DIR})
set(output_prefix ${TEST_OUTPUT_PREFIX})
set(output_suffix ${TEST_OUTPUT_SUFFIX})
set(dl_paths ${TEST_DL_PATHS})
set(script)
set(suite)
set(tests)
if(WIN32)
set(dl_paths_variable_name PATH)
elseif(APPLE)
set(dl_paths_variable_name DYLD_LIBRARY_PATH)
else()
set(dl_paths_variable_name LD_LIBRARY_PATH)
endif()
function(add_command NAME) function(add_command NAME)
set(_args "") set(_args "")
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments # use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
@@ -38,94 +16,131 @@ function(add_command NAME)
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE) set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction() endfunction()
# Run test executable to get list of available tests function(catch_discover_tests_impl)
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
if(dl_paths) cmake_parse_arguments(
""
""
"TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_DL_PATHS;TEST_OUTPUT_DIR;TEST_OUTPUT_PREFIX;TEST_OUTPUT_SUFFIX;TEST_PREFIX;TEST_REPORTER;TEST_SPEC;TEST_SUFFIX;TEST_LIST;CTEST_FILE"
"TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR"
${ARGN}
)
set(prefix "${_TEST_PREFIX}")
set(suffix "${_TEST_SUFFIX}")
set(spec ${_TEST_SPEC})
set(extra_args ${_TEST_EXTRA_ARGS})
set(properties ${_TEST_PROPERTIES})
set(reporter ${_TEST_REPORTER})
set(output_dir ${_TEST_OUTPUT_DIR})
set(output_prefix ${_TEST_OUTPUT_PREFIX})
set(output_suffix ${_TEST_OUTPUT_SUFFIX})
set(dl_paths ${_TEST_DL_PATHS})
set(script)
set(suite)
set(tests)
if(WIN32)
set(dl_paths_variable_name PATH)
elseif(APPLE)
set(dl_paths_variable_name DYLD_LIBRARY_PATH)
else()
set(dl_paths_variable_name LD_LIBRARY_PATH)
endif()
# Run test executable to get list of available tests
if(NOT EXISTS "${_TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${_TEST_EXECUTABLE}' does not exist"
)
endif()
if(dl_paths)
cmake_path(CONVERT "${dl_paths}" TO_NATIVE_PATH_LIST paths) cmake_path(CONVERT "${dl_paths}" TO_NATIVE_PATH_LIST paths)
set(ENV{${dl_paths_variable_name}} "${paths}") set(ENV{${dl_paths_variable_name}} "${paths}")
endif() endif()
execute_process( execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests --verbosity quiet COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --verbosity quiet
OUTPUT_VARIABLE output OUTPUT_VARIABLE output
RESULT_VARIABLE result RESULT_VARIABLE result
WORKING_DIRECTORY "${TEST_WORKING_DIR}" WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
) )
if(NOT ${result} EQUAL 0) if(NOT ${result} EQUAL 0)
message(FATAL_ERROR message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n" "Error running test executable '${_TEST_EXECUTABLE}':\n"
" Result: ${result}\n" " Result: ${result}\n"
" Output: ${output}\n" " Output: ${output}\n"
) )
endif() endif()
string(REPLACE "\n" ";" output "${output}") # Make sure to escape ; (semicolons) in test names first, because
# that'd break the foreach loop for "Parse output" later and create
# wrongly splitted and thus failing test cases (false positives)
string(REPLACE ";" "\;" output "${output}")
string(REPLACE "\n" ";" output "${output}")
# Run test executable to get list of available reporters # Prepare reporter
execute_process( if(reporter)
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters set(reporter_arg "--reporter ${reporter}")
OUTPUT_VARIABLE reporters_output
RESULT_VARIABLE reporters_result # Run test executable to check whether reporter is available
# note that the use of --list-reporters is not the important part,
# we only want to check whether the execution succeeds with ${reporter_arg}
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} ${reporter_arg} --list-reporters
OUTPUT_VARIABLE reporter_check_output
RESULT_VARIABLE reporter_check_result
WORKING_DIRECTORY "${TEST_WORKING_DIR}" WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
if(NOT ${reporters_result} EQUAL 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${reporters_result}\n"
" Output: ${reporters_output}\n"
) )
endif() if(${reporter_check_result} EQUAL 255)
string(FIND "${reporters_output}" "${reporter}" reporter_is_valid)
if(reporter AND ${reporter_is_valid} EQUAL -1)
message(FATAL_ERROR message(FATAL_ERROR
"\"${reporter}\" is not a valid reporter!\n" "\"${reporter}\" is not a valid reporter!\n"
) )
endif() elseif(NOT ${reporter_check_result} EQUAL 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${reporter_check_result}\n"
" Output: ${reporter_check_output}\n"
)
endif()
endif()
# Prepare reporter # Prepare output dir
if(reporter) if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
set(reporter_arg "--reporter ${reporter}") set(output_dir "${_TEST_WORKING_DIR}/${output_dir}")
endif()
# Prepare output dir
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
set(output_dir "${TEST_WORKING_DIR}/${output_dir}")
if(NOT EXISTS ${output_dir}) if(NOT EXISTS ${output_dir})
file(MAKE_DIRECTORY ${output_dir}) file(MAKE_DIRECTORY ${output_dir})
endif() endif()
endif() endif()
if(dl_paths) if(dl_paths)
foreach(path ${dl_paths}) foreach(path ${dl_paths})
cmake_path(NATIVE_PATH path native_path) cmake_path(NATIVE_PATH path native_path)
list(APPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}") list(APPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}")
endforeach() endforeach()
endif() endif()
# Parse output # Parse output
foreach(line ${output}) foreach(line ${output})
set(test ${line}) set(test "${line}")
# Escape characters in test case names that would be parsed by Catch2 # Escape characters in test case names that would be parsed by Catch2
set(test_name ${test}) # Note that the \ escaping must happen FIRST! Do not change the order.
foreach(char , [ ]) set(test_name "${test}")
string(REPLACE ${char} "\\${char}" test_name ${test_name}) foreach(char \\ , [ ])
string(REPLACE ${char} "\\${char}" test_name "${test_name}")
endforeach(char) endforeach(char)
# ...add output dir # ...add output dir
if(output_dir) if(output_dir)
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean ${test_name}) string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean "${test_name}")
set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}") set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}")
endif() endif()
# ...and add to script # ...and add to script
add_command(add_test add_command(add_test
"${prefix}${test}${suffix}" "${prefix}${test}${suffix}"
${TEST_EXECUTOR} ${_TEST_EXECUTOR}
"${TEST_EXECUTABLE}" "${_TEST_EXECUTABLE}"
"${test_name}" "${test_name}"
${extra_args} ${extra_args}
"${reporter_arg}" "${reporter_arg}"
@@ -134,7 +149,7 @@ foreach(line ${output})
add_command(set_tests_properties add_command(set_tests_properties
"${prefix}${test}${suffix}" "${prefix}${test}${suffix}"
PROPERTIES PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}" WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
${properties} ${properties}
) )
@@ -146,11 +161,32 @@ foreach(line ${output})
endif() endif()
list(APPEND tests "${prefix}${test}${suffix}") list(APPEND tests "${prefix}${test}${suffix}")
endforeach() endforeach()
# Create a list of all discovered tests, which users may use to e.g. set # Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests # properties on the tests
add_command(set ${TEST_LIST} ${tests}) add_command(set ${_TEST_LIST} ${tests})
# Write CTest script # Write CTest script
file(WRITE "${CTEST_FILE}" "${script}") file(WRITE "${_CTEST_FILE}" "${script}")
endfunction()
if(CMAKE_SCRIPT_MODE_FILE)
catch_discover_tests_impl(
TEST_EXECUTABLE ${TEST_EXECUTABLE}
TEST_EXECUTOR ${TEST_EXECUTOR}
TEST_WORKING_DIR ${TEST_WORKING_DIR}
TEST_SPEC ${TEST_SPEC}
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
TEST_PROPERTIES ${TEST_PROPERTIES}
TEST_PREFIX ${TEST_PREFIX}
TEST_SUFFIX ${TEST_SUFFIX}
TEST_LIST ${TEST_LIST}
TEST_REPORTER ${TEST_REPORTER}
TEST_OUTPUT_DIR ${TEST_OUTPUT_DIR}
TEST_OUTPUT_PREFIX ${TEST_OUTPUT_PREFIX}
TEST_OUTPUT_SUFFIX ${TEST_OUTPUT_SUFFIX}
TEST_DL_PATHS ${TEST_DL_PATHS}
CTEST_FILE ${CTEST_FILE}
)
endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,10 +8,12 @@
project( project(
'catch2', 'catch2',
'cpp', 'cpp',
version: '3.3.2', # CML version placeholder, don't delete version: '3.4.0', # CML version placeholder, don't delete
license: 'BSL-1.0', license: 'BSL-1.0',
meson_version: '>=0.50.0', meson_version: '>=0.54.1',
) )
subdir('src/catch2') subdir('src/catch2')
subdir('tests') if get_option('tests')
subdir('tests')
endif

1
meson_options.txt Normal file
View File

@@ -0,0 +1 @@
option('tests', type: 'boolean', value: true, description: 'Build the unit tests')

View File

@@ -21,6 +21,8 @@ set(BENCHMARK_HEADERS
${SOURCES_DIR}/benchmark/catch_sample_analysis.hpp ${SOURCES_DIR}/benchmark/catch_sample_analysis.hpp
${SOURCES_DIR}/benchmark/detail/catch_analyse.hpp ${SOURCES_DIR}/benchmark/detail/catch_analyse.hpp
${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.hpp ${SOURCES_DIR}/benchmark/detail/catch_benchmark_function.hpp
${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats.hpp
${SOURCES_DIR}/benchmark/detail/catch_benchmark_stats_fwd.hpp
${SOURCES_DIR}/benchmark/detail/catch_complete_invoke.hpp ${SOURCES_DIR}/benchmark/detail/catch_complete_invoke.hpp
${SOURCES_DIR}/benchmark/detail/catch_estimate_clock.hpp ${SOURCES_DIR}/benchmark/detail/catch_estimate_clock.hpp
${SOURCES_DIR}/benchmark/detail/catch_measure.hpp ${SOURCES_DIR}/benchmark/detail/catch_measure.hpp
@@ -71,6 +73,7 @@ set(IMPL_HEADERS
${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp ${SOURCES_DIR}/internal/catch_compiler_capabilities.hpp
${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp ${SOURCES_DIR}/internal/catch_config_android_logwrite.hpp
${SOURCES_DIR}/internal/catch_config_counter.hpp ${SOURCES_DIR}/internal/catch_config_counter.hpp
${SOURCES_DIR}/internal/catch_config_static_analysis_support.hpp
${SOURCES_DIR}/internal/catch_config_uncaught_exceptions.hpp ${SOURCES_DIR}/internal/catch_config_uncaught_exceptions.hpp
${SOURCES_DIR}/internal/catch_config_wchar.hpp ${SOURCES_DIR}/internal/catch_config_wchar.hpp
${SOURCES_DIR}/internal/catch_console_colour.hpp ${SOURCES_DIR}/internal/catch_console_colour.hpp
@@ -128,6 +131,7 @@ set(IMPL_HEADERS
${SOURCES_DIR}/internal/catch_test_failure_exception.hpp ${SOURCES_DIR}/internal/catch_test_failure_exception.hpp
${SOURCES_DIR}/internal/catch_test_macro_impl.hpp ${SOURCES_DIR}/internal/catch_test_macro_impl.hpp
${SOURCES_DIR}/internal/catch_test_registry.hpp ${SOURCES_DIR}/internal/catch_test_registry.hpp
${SOURCES_DIR}/internal/catch_test_run_info.hpp
${SOURCES_DIR}/internal/catch_test_spec_parser.hpp ${SOURCES_DIR}/internal/catch_test_spec_parser.hpp
${SOURCES_DIR}/internal/catch_textflow.hpp ${SOURCES_DIR}/internal/catch_textflow.hpp
${SOURCES_DIR}/internal/catch_to_string.hpp ${SOURCES_DIR}/internal/catch_to_string.hpp
@@ -153,6 +157,7 @@ set(IMPL_SOURCES
${SOURCES_DIR}/catch_timer.cpp ${SOURCES_DIR}/catch_timer.cpp
${SOURCES_DIR}/catch_tostring.cpp ${SOURCES_DIR}/catch_tostring.cpp
${SOURCES_DIR}/catch_totals.cpp ${SOURCES_DIR}/catch_totals.cpp
${SOURCES_DIR}/catch_translate_exception.cpp
${SOURCES_DIR}/catch_version.cpp ${SOURCES_DIR}/catch_version.cpp
${SOURCES_DIR}/internal/catch_assertion_handler.cpp ${SOURCES_DIR}/internal/catch_assertion_handler.cpp
${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.cpp ${SOURCES_DIR}/internal/catch_case_insensitive_comparisons.cpp
@@ -216,8 +221,8 @@ set(INTERFACE_HEADERS
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.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_tag_alias_registry.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_test_invoker.hpp
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp ${SOURCES_DIR}/interfaces/catch_interfaces_testcase.hpp
) )
set(INTERFACE_SOURCES set(INTERFACE_SOURCES
@@ -228,7 +233,6 @@ set(INTERFACE_SOURCES
${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_registry_hub.cpp
${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter.cpp
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_reporter_factory.cpp
${SOURCES_DIR}/interfaces/catch_interfaces_reporter_registry.cpp
${SOURCES_DIR}/interfaces/catch_interfaces_testcase.cpp ${SOURCES_DIR}/interfaces/catch_interfaces_testcase.cpp
) )
set(INTERFACE_FILES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES}) set(INTERFACE_FILES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES})

View File

@@ -10,23 +10,27 @@
#ifndef CATCH_BENCHMARK_HPP_INCLUDED #ifndef CATCH_BENCHMARK_HPP_INCLUDED
#define CATCH_BENCHMARK_HPP_INCLUDED #define CATCH_BENCHMARK_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/catch_user_config.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_context.hpp> #include <catch2/internal/catch_context.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_unique_name.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/benchmark/catch_chronometer.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/internal/catch_unique_name.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
#include <catch2/benchmark/catch_clock.hpp> #include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/catch_environment.hpp> #include <catch2/benchmark/catch_environment.hpp>
#include <catch2/benchmark/catch_execution_plan.hpp> #include <catch2/benchmark/catch_execution_plan.hpp>
#include <catch2/benchmark/detail/catch_estimate_clock.hpp> #include <catch2/benchmark/detail/catch_estimate_clock.hpp>
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
#include <catch2/benchmark/detail/catch_analyse.hpp> #include <catch2/benchmark/detail/catch_analyse.hpp>
#include <catch2/benchmark/detail/catch_benchmark_function.hpp> #include <catch2/benchmark/detail/catch_benchmark_function.hpp>
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp> #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
#include <algorithm> #include <algorithm>
#include <chrono>
#include <exception>
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -82,7 +86,7 @@ namespace Catch {
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(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); getResultCapture().benchmarkEnded(stats);
} CATCH_CATCH_ANON (TestFailureException) { } CATCH_CATCH_ANON (TestFailureException const&) {
getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
} CATCH_CATCH_ALL{ } CATCH_CATCH_ALL{
getResultCapture().benchmarkFailed(translateActiveException()); getResultCapture().benchmarkFailed(translateActiveException());

View File

@@ -33,6 +33,8 @@
#include <catch2/benchmark/catch_sample_analysis.hpp> #include <catch2/benchmark/catch_sample_analysis.hpp>
#include <catch2/benchmark/detail/catch_analyse.hpp> #include <catch2/benchmark/detail/catch_analyse.hpp>
#include <catch2/benchmark/detail/catch_benchmark_function.hpp> #include <catch2/benchmark/detail/catch_benchmark_function.hpp>
#include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
#include <catch2/benchmark/detail/catch_complete_invoke.hpp> #include <catch2/benchmark/detail/catch_complete_invoke.hpp>
#include <catch2/benchmark/detail/catch_estimate_clock.hpp> #include <catch2/benchmark/detail/catch_estimate_clock.hpp>
#include <catch2/benchmark/detail/catch_measure.hpp> #include <catch2/benchmark/detail/catch_measure.hpp>

View File

@@ -12,7 +12,6 @@
#include <catch2/benchmark/catch_clock.hpp> #include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/catch_optimizer.hpp> #include <catch2/benchmark/catch_optimizer.hpp>
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
#include <catch2/internal/catch_meta.hpp> #include <catch2/internal/catch_meta.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>

View File

@@ -17,8 +17,7 @@
#include <catch2/benchmark/detail/catch_repeat.hpp> #include <catch2/benchmark/detail/catch_repeat.hpp>
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp> #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
#include <algorithm> #include <vector>
#include <iterator>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
@@ -41,14 +40,17 @@ namespace Catch {
Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
std::vector<FloatDuration<Clock>> times; std::vector<FloatDuration<Clock>> times;
times.reserve(cfg.benchmarkSamples()); const auto num_samples = cfg.benchmarkSamples();
std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { times.reserve( num_samples );
for ( size_t i = 0; i < num_samples; ++i ) {
Detail::ChronometerModel<Clock> model; Detail::ChronometerModel<Clock> model;
this->benchmark(Chronometer(model, iterations_per_sample)); this->benchmark( Chronometer( model, iterations_per_sample ) );
auto sample_time = model.elapsed() - env.clock_cost.mean; auto sample_time = model.elapsed() - env.clock_cost.mean;
if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); if ( sample_time < FloatDuration<Clock>::zero() ) {
return sample_time / iterations_per_sample; sample_time = FloatDuration<Clock>::zero();
}); }
times.push_back(sample_time / iterations_per_sample);
}
return times; return times;
} }
}; };

View File

@@ -10,14 +10,11 @@
#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
#include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/catch_estimate.hpp> #include <catch2/benchmark/catch_estimate.hpp>
#include <catch2/benchmark/catch_outlier_classification.hpp> #include <catch2/benchmark/catch_outlier_classification.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <algorithm>
#include <vector> #include <vector>
#include <iterator>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
@@ -33,7 +30,9 @@ namespace Catch {
operator SampleAnalysis<Duration2>() const { operator SampleAnalysis<Duration2>() const {
std::vector<Duration2> samples2; std::vector<Duration2> samples2;
samples2.reserve(samples.size()); samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); for (auto const& d : samples) {
samples2.push_back(Duration2(d));
}
return { return {
CATCH_MOVE(samples2), CATCH_MOVE(samples2),
mean, mean,

View File

@@ -10,15 +10,12 @@
#ifndef CATCH_ANALYSE_HPP_INCLUDED #ifndef CATCH_ANALYSE_HPP_INCLUDED
#define CATCH_ANALYSE_HPP_INCLUDED #define CATCH_ANALYSE_HPP_INCLUDED
#include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/catch_environment.hpp> #include <catch2/benchmark/catch_environment.hpp>
#include <catch2/benchmark/catch_sample_analysis.hpp> #include <catch2/benchmark/catch_sample_analysis.hpp>
#include <catch2/benchmark/detail/catch_stats.hpp> #include <catch2/benchmark/detail/catch_stats.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <algorithm>
#include <iterator>
#include <vector> #include <vector>
namespace Catch { namespace Catch {
@@ -29,7 +26,9 @@ namespace Catch {
if (!cfg.benchmarkNoAnalysis()) { if (!cfg.benchmarkNoAnalysis()) {
std::vector<double> samples; std::vector<double> samples;
samples.reserve(static_cast<size_t>(last - first)); samples.reserve(static_cast<size_t>(last - first));
std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); for (auto current = first; current != last; ++current) {
samples.push_back( current->count() );
}
auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
@@ -44,7 +43,10 @@ namespace Catch {
}; };
std::vector<Duration> samples2; std::vector<Duration> samples2;
samples2.reserve(samples.size()); samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); for (auto s : samples) {
samples2.push_back( Duration( s ) );
}
return { return {
CATCH_MOVE(samples2), CATCH_MOVE(samples2),
wrap_estimate(analysis.mean), wrap_estimate(analysis.mean),

View File

@@ -11,7 +11,6 @@
#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED #define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
#include <catch2/benchmark/catch_chronometer.hpp> #include <catch2/benchmark/catch_chronometer.hpp>
#include <catch2/benchmark/detail/catch_complete_invoke.hpp>
#include <catch2/internal/catch_meta.hpp> #include <catch2/internal/catch_meta.hpp>
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>

View File

@@ -0,0 +1,64 @@
// 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_HPP_INCLUDED
#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/benchmark/catch_estimate.hpp>
#include <catch2/benchmark/catch_outlier_classification.hpp>
// The fwd decl & default specialization needs to be seen by VS2017 before
// BenchmarkStats itself, or VS2017 will report compilation error.
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
#include <string>
#include <vector>
namespace Catch {
struct BenchmarkInfo {
std::string name;
double estimatedDuration;
int iterations;
unsigned int samples;
unsigned int resamples;
double clockResolution;
double clockCost;
};
template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
std::vector<Duration> samples;
Benchmark::Estimate<Duration> mean;
Benchmark::Estimate<Duration> standardDeviation;
Benchmark::OutlierClassification outliers;
double outlierVariance;
template <typename Duration2>
operator BenchmarkStats<Duration2>() const {
std::vector<Duration2> samples2;
samples2.reserve(samples.size());
for (auto const& sample : samples) {
samples2.push_back(Duration2(sample));
}
return {
info,
CATCH_MOVE(samples2),
mean,
standardDeviation,
outliers,
outlierVariance,
};
}
};
} // end namespace Catch
#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED

View 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

View File

@@ -10,14 +10,9 @@
#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED #ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED #define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
#include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/internal/catch_meta.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 <catch2/internal/catch_move_and_forward.hpp>
#include <type_traits>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
namespace Detail { namespace Detail {

View File

@@ -19,7 +19,6 @@
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <algorithm> #include <algorithm>
#include <iterator>
#include <vector> #include <vector>
#include <cmath> #include <cmath>
@@ -30,26 +29,29 @@ namespace Catch {
std::vector<double> resolution(int k) { std::vector<double> resolution(int k) {
std::vector<TimePoint<Clock>> times; std::vector<TimePoint<Clock>> times;
times.reserve(static_cast<size_t>(k + 1)); times.reserve(static_cast<size_t>(k + 1));
std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); for ( int i = 0; i < k + 1; ++i ) {
times.push_back( Clock::now() );
}
std::vector<double> deltas; std::vector<double> deltas;
deltas.reserve(static_cast<size_t>(k)); deltas.reserve(static_cast<size_t>(k));
std::transform(std::next(times.begin()), times.end(), times.begin(), for ( size_t idx = 1; idx < times.size(); ++idx ) {
std::back_inserter(deltas), deltas.push_back( static_cast<double>(
[](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); ( times[idx] - times[idx - 1] ).count() ) );
}
return deltas; return deltas;
} }
const auto warmup_iterations = 10000; constexpr auto warmup_iterations = 10000;
const auto warmup_time = std::chrono::milliseconds(100); constexpr auto warmup_time = std::chrono::milliseconds(100);
const auto minimum_ticks = 1000; constexpr auto minimum_ticks = 1000;
const auto warmup_seed = 10000; constexpr auto warmup_seed = 10000;
const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
const auto clock_cost_estimation_tick_limit = 100000; constexpr auto clock_cost_estimation_tick_limit = 100000;
const auto clock_cost_estimation_time = std::chrono::milliseconds(10); constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
const auto clock_cost_estimation_iterations = 10000; constexpr auto clock_cost_estimation_iterations = 10000;
template <typename Clock> template <typename Clock>
int warmup() { int warmup() {
@@ -84,9 +86,11 @@ namespace Catch {
std::vector<double> times; std::vector<double> times;
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
times.reserve(static_cast<size_t>(nsamples)); times.reserve(static_cast<size_t>(nsamples));
std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { for ( int s = 0; s < nsamples; ++s ) {
return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); times.push_back( static_cast<double>(
}); ( time_clock( r.iterations ) / r.iterations )
.count() ) );
}
return { return {
FloatDuration<Clock>(mean(times.begin(), times.end())), FloatDuration<Clock>(mean(times.begin(), times.end())),
classify_outliers(times.begin(), times.end()), classify_outliers(times.begin(), times.end()),

View File

@@ -10,7 +10,6 @@
#ifndef CATCH_MEASURE_HPP_INCLUDED #ifndef CATCH_MEASURE_HPP_INCLUDED
#define CATCH_MEASURE_HPP_INCLUDED #define CATCH_MEASURE_HPP_INCLUDED
#include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/detail/catch_complete_invoke.hpp> #include <catch2/benchmark/detail/catch_complete_invoke.hpp>
#include <catch2/benchmark/detail/catch_timing.hpp> #include <catch2/benchmark/detail/catch_timing.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>

View File

@@ -7,9 +7,10 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp> #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
#include <exception>
#include <catch2/internal/catch_enforce.hpp> #include <catch2/internal/catch_enforce.hpp>
#include <exception>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
namespace Detail { namespace Detail {

View File

@@ -13,7 +13,7 @@
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iterator> #include <numeric>
#include <random> #include <random>
@@ -21,35 +21,84 @@
#include <future> #include <future>
#endif #endif
namespace { namespace Catch {
namespace Benchmark {
using Catch::Benchmark::Detail::sample; namespace Detail {
namespace {
template <typename URng, typename Estimator> template <typename URng, typename Estimator>
sample resample(URng& rng, unsigned int resamples, std::vector<double>::iterator first, std::vector<double>::iterator last, Estimator& estimator) { static sample
auto n = static_cast<size_t>(last - first); resample( URng& rng,
std::uniform_int_distribution<decltype(n)> dist(0, n - 1); unsigned int resamples,
std::vector<double>::const_iterator first,
std::vector<double>::const_iterator last,
Estimator& estimator ) {
auto n = static_cast<size_t>( last - first );
std::uniform_int_distribution<decltype( n )> dist( 0,
n - 1 );
sample out; sample out;
out.reserve(resamples); out.reserve( resamples );
std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { // We allocate the vector outside the loop to avoid realloc
// per resample
std::vector<double> resampled; std::vector<double> resampled;
resampled.reserve(n); resampled.reserve( n );
std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast<std::ptrdiff_t>(dist(rng))]; }); for ( size_t i = 0; i < resamples; ++i ) {
return estimator(resampled.begin(), resampled.end()); resampled.clear();
}); for ( size_t s = 0; s < n; ++s ) {
std::sort(out.begin(), out.end()); resampled.push_back(
first[static_cast<std::ptrdiff_t>(
dist( rng ) )] );
}
const auto estimate =
estimator( resampled.begin(), resampled.end() );
out.push_back( estimate );
}
std::sort( out.begin(), out.end() );
return out; return out;
} }
static double outlier_variance( Estimate<double> mean,
Estimate<double> stddev,
int n ) {
double sb = stddev.point;
double mn = mean.point / n;
double mg_min = mn / 2.;
double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
double sg2 = sg * sg;
double sb2 = sb * sb;
double erf_inv(double x) { auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
// Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 double k = mn - x;
double d = k * k;
double nd = n * d;
double k0 = -n * nd;
double k1 = sb2 - n * sg2 + nd;
double det = k1 * k1 - 4 * sg2 * k0;
return static_cast<int>( -2. * k0 /
( k1 + std::sqrt( det ) ) );
};
auto var_out = [n, sb2, sg2]( double c ) {
double nc = n - c;
return ( nc / n ) * ( sb2 - nc * sg2 );
};
return (std::min)( var_out( 1 ),
var_out(
(std::min)( c_max( 0. ),
c_max( mg_min ) ) ) ) /
sb2;
}
static double erf_inv( double x ) {
// Code accompanying the article "Approximating the erfinv
// function" in GPU Computing Gems, Volume 2
double w, p; double w, p;
w = -log((1.0 - x) * (1.0 + x)); w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
if (w < 6.250000) { if ( w < 6.250000 ) {
w = w - 3.125000; w = w - 3.125000;
p = -3.6444120640178196996e-21; p = -3.6444120640178196996e-21;
p = -1.685059138182016589e-19 + p * w; p = -1.685059138182016589e-19 + p * w;
@@ -74,8 +123,8 @@ using Catch::Benchmark::Detail::sample;
p = -0.0060336708714301490533 + p * w; p = -0.0060336708714301490533 + p * w;
p = 0.24015818242558961693 + p * w; p = 0.24015818242558961693 + p * w;
p = 1.6536545626831027356 + p * w; p = 1.6536545626831027356 + p * w;
} else if (w < 16.000000) { } else if ( w < 16.000000 ) {
w = sqrt(w) - 3.250000; w = sqrt( w ) - 3.250000;
p = 2.2137376921775787049e-09; p = 2.2137376921775787049e-09;
p = 9.0756561938885390979e-08 + p * w; p = 9.0756561938885390979e-08 + p * w;
p = -2.7517406297064545428e-07 + p * w; p = -2.7517406297064545428e-07 + p * w;
@@ -96,7 +145,7 @@ using Catch::Benchmark::Detail::sample;
p = 1.0052589676941592334 + p * w; p = 1.0052589676941592334 + p * w;
p = 3.0838856104922207635 + p * w; p = 3.0838856104922207635 + p * w;
} else { } else {
w = sqrt(w) - 5.000000; w = sqrt( w ) - 5.000000;
p = -2.7109920616438573243e-11; p = -2.7109920616438573243e-11;
p = -2.5556418169965252055e-10 + p * w; p = -2.5556418169965252055e-10 + p * w;
p = 1.5076572693500548083e-09 + p * w; p = 1.5076572693500548083e-09 + p * w;
@@ -118,9 +167,12 @@ using Catch::Benchmark::Detail::sample;
return p * x; return p * x;
} }
double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) { static double
auto m = Catch::Benchmark::Detail::mean(first, last); standard_deviation( std::vector<double>::const_iterator first,
double variance = std::accumulate( first, std::vector<double>::const_iterator last ) {
auto m = Catch::Benchmark::Detail::mean( first, last );
double variance =
std::accumulate( first,
last, last,
0., 0.,
[m]( double a, double b ) { [m]( double a, double b ) {
@@ -131,7 +183,10 @@ using Catch::Benchmark::Detail::sample;
return std::sqrt( variance ); return std::sqrt( variance );
} }
} } // namespace
} // namespace Detail
} // namespace Benchmark
} // namespace Catch
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
@@ -161,6 +216,47 @@ namespace Catch {
return xj + g * (xj1 - xj); return xj + g * (xj1 - xj);
} }
OutlierClassification
classify_outliers( std::vector<double>::const_iterator first,
std::vector<double>::const_iterator last ) {
std::vector<double> copy( first, last );
auto q1 = weighted_average_quantile( 1, 4, copy.begin(), copy.end() );
auto q3 = weighted_average_quantile( 3, 4, copy.begin(), copy.end() );
auto iqr = q3 - q1;
auto los = q1 - ( iqr * 3. );
auto lom = q1 - ( iqr * 1.5 );
auto him = q3 + ( iqr * 1.5 );
auto his = q3 + ( iqr * 3. );
OutlierClassification o;
for ( ; first != last; ++first ) {
const double t = *first;
if ( t < los ) {
++o.low_severe;
} else if ( t < lom ) {
++o.low_mild;
} else if ( t > his ) {
++o.high_severe;
} else if ( t > him ) {
++o.high_mild;
}
++o.samples_seen;
}
return o;
}
double mean( std::vector<double>::const_iterator first,
std::vector<double>::const_iterator last ) {
auto count = last - first;
double sum = 0.;
while (first != last) {
sum += *first;
++first;
}
return sum / static_cast<double>(count);
}
double erfc_inv(double x) { double erfc_inv(double x) {
return erf_inv(1.0 - x); return erf_inv(1.0 - x);
@@ -182,35 +278,10 @@ namespace Catch {
return result; return result;
} }
bootstrap_analysis analyse_samples(double confidence_level,
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) { unsigned int n_resamples,
double sb = stddev.point; std::vector<double>::iterator first,
double mn = mean.point / n; std::vector<double>::iterator last) {
double mg_min = mn / 2.;
double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
auto c_max = [n, mn, sb2, sg2](double x) -> double {
double k = mn - x;
double d = k * k;
double nd = n * d;
double k0 = -n * nd;
double k1 = sb2 - n * sg2 + nd;
double det = k1 * k1 - 4 * sg2 * k0;
return static_cast<int>(-2. * k0 / (k1 + std::sqrt(det)));
};
auto var_out = [n, sb2, sg2](double c) {
double nc = n - c;
return (nc / n) * (sb2 - nc * sg2);
};
return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
}
bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
static std::random_device entropy; static std::random_device entropy;
@@ -218,11 +289,12 @@ namespace Catch {
auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
auto mean = &Detail::mean<std::vector<double>::iterator>; auto mean = &Detail::mean;
auto stddev = &standard_deviation; auto stddev = &standard_deviation;
#if defined(CATCH_CONFIG_USE_ASYNC) #if defined(CATCH_CONFIG_USE_ASYNC)
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { auto Estimate = [=](double(*f)(std::vector<double>::const_iterator,
std::vector<double>::const_iterator)) {
auto seed = entropy(); auto seed = entropy();
return std::async(std::launch::async, [=] { return std::async(std::launch::async, [=] {
std::mt19937 rng(seed); std::mt19937 rng(seed);
@@ -237,7 +309,8 @@ namespace Catch {
auto mean_estimate = mean_future.get(); auto mean_estimate = mean_future.get();
auto stddev_estimate = stddev_future.get(); auto stddev_estimate = stddev_future.get();
#else #else
auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { auto Estimate = [=](double(*f)(std::vector<double>::const_iterator,
std::vector<double>::const_iterator)) {
auto seed = entropy(); auto seed = entropy();
std::mt19937 rng(seed); std::mt19937 rng(seed);
auto resampled = resample(rng, n_resamples, first, last, f); auto resampled = resample(rng, n_resamples, first, last, f);

View File

@@ -15,8 +15,6 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <numeric>
#include <tuple>
#include <cmath> #include <cmath>
namespace Catch { namespace Catch {
@@ -30,39 +28,17 @@ namespace Catch {
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last); double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
template <typename Iterator> OutlierClassification
OutlierClassification classify_outliers(Iterator first, Iterator last) { classify_outliers( std::vector<double>::const_iterator first,
std::vector<double> copy(first, last); std::vector<double>::const_iterator last );
auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); double mean( std::vector<double>::const_iterator first,
auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); std::vector<double>::const_iterator last );
auto iqr = q3 - q1;
auto los = q1 - (iqr * 3.);
auto lom = q1 - (iqr * 1.5);
auto him = q3 + (iqr * 1.5);
auto his = q3 + (iqr * 3.);
OutlierClassification o; template <typename Estimator>
for (; first != last; ++first) { sample jackknife(Estimator&& estimator,
auto&& t = *first; std::vector<double>::iterator first,
if (t < los) ++o.low_severe; std::vector<double>::iterator last) {
else if (t < lom) ++o.low_mild;
else if (t > his) ++o.high_severe;
else if (t > him) ++o.high_mild;
++o.samples_seen;
}
return o;
}
template <typename Iterator>
double mean(Iterator first, Iterator last) {
auto count = last - first;
double sum = std::accumulate(first, last, 0.);
return sum / static_cast<double>(count);
}
template <typename Estimator, typename Iterator>
sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {
auto n = static_cast<size_t>(last - first); auto n = static_cast<size_t>(last - first);
auto second = first; auto second = first;
++second; ++second;
@@ -85,8 +61,12 @@ namespace Catch {
double normal_quantile(double p); double normal_quantile(double p);
template <typename Iterator, typename Estimator> template <typename Estimator>
Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { Estimate<double> bootstrap( double confidence_level,
std::vector<double>::iterator first,
std::vector<double>::iterator last,
sample const& resample,
Estimator&& estimator ) {
auto n_samples = last - first; auto n_samples = last - first;
double point = estimator(first, last); double point = estimator(first, last);
@@ -95,13 +75,13 @@ namespace Catch {
sample jack = jackknife(estimator, first, last); sample jack = jackknife(estimator, first, last);
double jack_mean = mean(jack.begin(), jack.end()); double jack_mean = mean(jack.begin(), jack.end());
double sum_squares, sum_cubes; double sum_squares = 0, sum_cubes = 0;
std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> { for (double x : jack) {
auto d = jack_mean - x; auto difference = jack_mean - x;
auto d2 = d * d; auto square = difference * difference;
auto d3 = d2 * d; auto cube = square * difference;
return { sqcb.first + d2, sqcb.second + d3 }; sum_squares += square; sum_cubes += cube;
}); }
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
long n = static_cast<long>(resample.size()); long n = static_cast<long>(resample.size());
@@ -128,15 +108,16 @@ namespace Catch {
return { point, resample[lo], resample[hi], confidence_level }; return { point, resample[lo], resample[hi], confidence_level };
} }
double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);
struct bootstrap_analysis { struct bootstrap_analysis {
Estimate<double> mean; Estimate<double> mean;
Estimate<double> standard_deviation; Estimate<double> standard_deviation;
double outlier_variance; double outlier_variance;
}; };
bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last); bootstrap_analysis analyse_samples(double confidence_level,
unsigned int n_resamples,
std::vector<double>::iterator first,
std::vector<double>::iterator last);
} // namespace Detail } // namespace Detail
} // namespace Benchmark } // namespace Benchmark
} // namespace Catch } // namespace Catch

View File

@@ -54,6 +54,7 @@
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_config_android_logwrite.hpp> #include <catch2/internal/catch_config_android_logwrite.hpp>
#include <catch2/internal/catch_config_counter.hpp> #include <catch2/internal/catch_config_counter.hpp>
#include <catch2/internal/catch_config_static_analysis_support.hpp>
#include <catch2/internal/catch_config_uncaught_exceptions.hpp> #include <catch2/internal/catch_config_uncaught_exceptions.hpp>
#include <catch2/internal/catch_config_wchar.hpp> #include <catch2/internal/catch_config_wchar.hpp>
#include <catch2/internal/catch_console_colour.hpp> #include <catch2/internal/catch_console_colour.hpp>
@@ -86,6 +87,7 @@
#include <catch2/internal/catch_platform.hpp> #include <catch2/internal/catch_platform.hpp>
#include <catch2/internal/catch_polyfills.hpp> #include <catch2/internal/catch_polyfills.hpp>
#include <catch2/internal/catch_preprocessor.hpp> #include <catch2/internal/catch_preprocessor.hpp>
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
#include <catch2/internal/catch_preprocessor_remove_parens.hpp> #include <catch2/internal/catch_preprocessor_remove_parens.hpp>
#include <catch2/internal/catch_random_number_generator.hpp> #include <catch2/internal/catch_random_number_generator.hpp>
#include <catch2/internal/catch_random_seed_generation.hpp> #include <catch2/internal/catch_random_seed_generation.hpp>
@@ -111,6 +113,7 @@
#include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/internal/catch_test_macro_impl.hpp> #include <catch2/internal/catch_test_macro_impl.hpp>
#include <catch2/internal/catch_test_registry.hpp> #include <catch2/internal/catch_test_registry.hpp>
#include <catch2/internal/catch_test_run_info.hpp>
#include <catch2/internal/catch_test_spec_parser.hpp> #include <catch2/internal/catch_test_spec_parser.hpp>
#include <catch2/internal/catch_textflow.hpp> #include <catch2/internal/catch_textflow.hpp>
#include <catch2/internal/catch_to_string.hpp> #include <catch2/internal/catch_to_string.hpp>

View File

@@ -105,7 +105,7 @@ namespace Catch {
elem = trim(elem); elem = trim(elem);
} }
// Insert the default reporter if user hasn't asked for a specfic one // Insert the default reporter if user hasn't asked for a specific one
if ( m_data.reporterSpecifications.empty() ) { if ( m_data.reporterSpecifications.empty() ) {
m_data.reporterSpecifications.push_back( { m_data.reporterSpecifications.push_back( {
#if defined( CATCH_CONFIG_DEFAULT_REPORTER ) #if defined( CATCH_CONFIG_DEFAULT_REPORTER )

View File

@@ -37,7 +37,11 @@ namespace Catch {
} }
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { Capturer::Capturer( StringRef macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType resultType,
StringRef names ):
m_resultCapture( getResultCapture() ) {
auto trimmed = [&] (size_t start, size_t end) { auto trimmed = [&] (size_t start, size_t end) {
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
++start; ++start;

View File

@@ -12,7 +12,6 @@
#include <catch2/internal/catch_reusable_string_stream.hpp> #include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_stream_end_stop.hpp> #include <catch2/internal/catch_stream_end_stop.hpp>
#include <catch2/internal/catch_message_info.hpp> #include <catch2/internal/catch_message_info.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/catch_tostring.hpp> #include <catch2/catch_tostring.hpp>
#include <string> #include <string>
@@ -21,6 +20,7 @@
namespace Catch { namespace Catch {
struct SourceLineInfo; struct SourceLineInfo;
class IResultCapture;
struct MessageStream { struct MessageStream {
@@ -61,7 +61,7 @@ namespace Catch {
class Capturer { class Capturer {
std::vector<MessageInfo> m_messages; std::vector<MessageInfo> m_messages;
IResultCapture& m_resultCapture = getResultCapture(); IResultCapture& m_resultCapture;
size_t m_captured = 0; size_t m_captured = 0;
public: public:
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );

View File

@@ -20,6 +20,9 @@
#include <catch2/internal/catch_noncopyable.hpp> #include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.hpp> #include <catch2/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_reporter_registry.hpp>
#include <exception>
namespace Catch { namespace Catch {
@@ -31,7 +34,7 @@ namespace Catch {
public: // IRegistryHub public: // IRegistryHub
RegistryHub() = default; RegistryHub() = default;
IReporterRegistry const& getReporterRegistry() const override { ReporterRegistry const& getReporterRegistry() const override {
return m_reporterRegistry; return m_reporterRegistry;
} }
ITestCaseRegistry const& getTestCaseRegistry() const override { ITestCaseRegistry const& getTestCaseRegistry() const override {

View File

@@ -13,13 +13,13 @@
#include <catch2/internal/catch_run_context.hpp> #include <catch2/internal/catch_run_context.hpp>
#include <catch2/catch_test_spec.hpp> #include <catch2/catch_test_spec.hpp>
#include <catch2/catch_version.hpp> #include <catch2/catch_version.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_startup_exception_registry.hpp> #include <catch2/internal/catch_startup_exception_registry.hpp>
#include <catch2/internal/catch_sharding.hpp> #include <catch2/internal/catch_sharding.hpp>
#include <catch2/internal/catch_test_case_registry_impl.hpp>
#include <catch2/internal/catch_textflow.hpp> #include <catch2/internal/catch_textflow.hpp>
#include <catch2/internal/catch_windows_h_proxy.hpp> #include <catch2/internal/catch_windows_h_proxy.hpp>
#include <catch2/reporters/catch_reporter_multi.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/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_stdstreams.hpp> #include <catch2/internal/catch_stdstreams.hpp>
@@ -27,6 +27,7 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <exception>
#include <iomanip> #include <iomanip>
#include <set> #include <set>

View File

@@ -139,12 +139,20 @@ namespace Catch {
for (size_t idx = 0; idx < originalTags.size(); ++idx) { for (size_t idx = 0; idx < originalTags.size(); ++idx) {
auto c = originalTags[idx]; auto c = originalTags[idx];
if (c == '[') { if (c == '[') {
assert(!inTag); CATCH_ENFORCE(
!inTag,
"Found '[' inside a tag while registering test case '"
<< _nameAndTags.name << "' at " << _lineInfo );
inTag = true; inTag = true;
tagStart = idx; tagStart = idx;
} }
if (c == ']') { if (c == ']') {
assert(inTag); CATCH_ENFORCE(
inTag,
"Found unmatched ']' while registering test case '"
<< _nameAndTags.name << "' at " << _lineInfo );
inTag = false; inTag = false;
tagEnd = idx; tagEnd = idx;
assert(tagStart < tagEnd); assert(tagStart < tagEnd);
@@ -153,7 +161,11 @@ namespace Catch {
// it over to backing storage and actually reference the // it over to backing storage and actually reference the
// backing storage in the saved tags // backing storage in the saved tags
StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1); StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
CATCH_ENFORCE(!tagStr.empty(), "Empty tags are not allowed"); CATCH_ENFORCE( !tagStr.empty(),
"Found an empty tag while registering test case '"
<< _nameAndTags.name << "' at "
<< _lineInfo );
enforceNotReservedTag(tagStr, lineInfo); enforceNotReservedTag(tagStr, lineInfo);
properties |= parseSpecialTag(tagStr); properties |= parseSpecialTag(tagStr);
// When copying a tag to the backing storage, we need to // When copying a tag to the backing storage, we need to
@@ -167,8 +179,12 @@ namespace Catch {
// the tags. // the tags.
internalAppendTag(tagStr); internalAppendTag(tagStr);
} }
(void)inTag; // Silence "set-but-unused" warning in release mode.
} }
CATCH_ENFORCE( !inTag,
"Found an unclosed tag while registering test case '"
<< _nameAndTags.name << "' at " << _lineInfo );
// Add [.] if relevant // Add [.] if relevant
if (isHidden()) { if (isHidden()) {
internalAppendTag("."_sr); internalAppendTag("."_sr);

View File

@@ -6,6 +6,8 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
#include <catch2/catch_test_spec.hpp> #include <catch2/catch_test_spec.hpp>
#include <catch2/interfaces/catch_interfaces_testcase.hpp>
#include <catch2/internal/catch_test_case_registry_impl.hpp>
#include <catch2/internal/catch_reusable_string_stream.hpp> #include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_string_manip.hpp> #include <catch2/internal/catch_string_manip.hpp>
#include <catch2/catch_test_case_info.hpp> #include <catch2/catch_test_case_info.hpp>
@@ -106,16 +108,18 @@ namespace Catch {
return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
} }
TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
{ Matches matches;
Matches matches( m_filters.size() ); matches.reserve( m_filters.size() );
std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ for ( auto const& filter : m_filters ) {
std::vector<TestCaseHandle const*> currentMatches; std::vector<TestCaseHandle const*> currentMatches;
for( auto const& test : testCases ) for ( auto const& test : testCases )
if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) ) if ( isThrowSafe( test, config ) &&
filter.matches( test.getTestCaseInfo() ) )
currentMatches.emplace_back( &test ); currentMatches.emplace_back( &test );
return FilterMatch{ extractFilterName(filter), currentMatches }; matches.push_back(
} ); FilterMatch{ extractFilterName( filter ), currentMatches } );
}
return matches; return matches;
} }

View File

@@ -116,7 +116,6 @@ namespace Catch {
} // namespace Detail } // namespace Detail
// If we decide for C++14, change these to enable_if_ts
template <typename T, typename = void> template <typename T, typename = void>
struct StringMaker { struct StringMaker {
template <typename Fake = T> template <typename Fake = T>

View 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/interfaces/catch_interfaces_registry_hub.hpp>
namespace Catch {
namespace Detail {
void registerTranslatorImpl(
Detail::unique_ptr<IExceptionTranslator>&& translator ) {
getMutableRegistryHub().registerTranslator(
CATCH_MOVE( translator ) );
}
} // namespace Detail
} // namespace Catch

View File

@@ -15,6 +15,10 @@
#include <exception> #include <exception>
namespace Catch { namespace Catch {
namespace Detail {
void registerTranslatorImpl(
Detail::unique_ptr<IExceptionTranslator>&& translator );
}
class ExceptionTranslatorRegistrar { class ExceptionTranslatorRegistrar {
template<typename T> template<typename T>
@@ -48,9 +52,9 @@ namespace Catch {
public: public:
template<typename T> template<typename T>
ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) { ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
getMutableRegistryHub().registerTranslator( Detail::registerTranslatorImpl(
Detail::make_unique<ExceptionTranslator<T>>(translateFunction) Detail::make_unique<ExceptionTranslator<T>>(
); translateFunction ) );
} }
}; };

View File

@@ -169,9 +169,18 @@
#endif #endif
#cmakedefine CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
#cmakedefine CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
#if defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
# error Cannot force STATIC_ANALYSIS_SUPPORT to both ON and OFF
#endif
// ------ // ------
// Simple toggle defines // Simple toggle defines
// their value is never used and they cannot be overriden // their value is never used and they cannot be overridden
// ------ // ------

View File

@@ -36,7 +36,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 3, 3, 2, "", 0 ); static Version version( 3, 4, 0, "", 0 );
return version; return version;
} }

View File

@@ -9,7 +9,7 @@
#define CATCH_VERSION_MACROS_HPP_INCLUDED #define CATCH_VERSION_MACROS_HPP_INCLUDED
#define CATCH_VERSION_MAJOR 3 #define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 3 #define CATCH_VERSION_MINOR 4
#define CATCH_VERSION_PATCH 2 #define CATCH_VERSION_PATCH 0
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED #endif // CATCH_VERSION_MACROS_HPP_INCLUDED

View File

@@ -30,8 +30,8 @@
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp> #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp> #include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_factory.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_tag_alias_registry.hpp>
#include <catch2/interfaces/catch_interfaces_test_invoker.hpp>
#include <catch2/interfaces/catch_interfaces_testcase.hpp> #include <catch2/interfaces/catch_interfaces_testcase.hpp>
#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED #endif // CATCH_INTERFACES_ALL_HPP_INCLUDED

View File

@@ -14,6 +14,7 @@
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_result_type.hpp> #include <catch2/internal/catch_result_type.hpp>
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/benchmark/detail/catch_benchmark_stats_fwd.hpp>
namespace Catch { namespace Catch {
@@ -31,8 +32,6 @@ namespace Catch {
class IGeneratorTracker; class IGeneratorTracker;
struct BenchmarkInfo; struct BenchmarkInfo;
template <typename Duration = std::chrono::duration<double, std::nano>>
struct BenchmarkStats;
namespace Generators { namespace Generators {
class GeneratorUntypedBase; class GeneratorUntypedBase;
@@ -44,6 +43,7 @@ namespace Catch {
public: public:
virtual ~IResultCapture(); virtual ~IResultCapture();
virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0;
virtual bool sectionStarted( StringRef sectionName, virtual bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo, SourceLineInfo const& sectionLineInfo,
Counts& assertions ) = 0; Counts& assertions ) = 0;

View File

@@ -8,7 +8,6 @@
#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED #ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
#define 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 <catch2/internal/catch_unique_ptr.hpp>
#include <string> #include <string>

View File

@@ -19,7 +19,7 @@ namespace Catch {
class ITestCaseRegistry; class ITestCaseRegistry;
class IExceptionTranslatorRegistry; class IExceptionTranslatorRegistry;
class IExceptionTranslator; class IExceptionTranslator;
class IReporterRegistry; class ReporterRegistry;
class IReporterFactory; class IReporterFactory;
class ITagAliasRegistry; class ITagAliasRegistry;
class ITestInvoker; class ITestInvoker;
@@ -35,7 +35,7 @@ namespace Catch {
public: public:
virtual ~IRegistryHub(); // = default virtual ~IRegistryHub(); // = default
virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;

View File

@@ -13,11 +13,10 @@
#include <catch2/catch_assertion_result.hpp> #include <catch2/catch_assertion_result.hpp>
#include <catch2/internal/catch_message_info.hpp> #include <catch2/internal/catch_message_info.hpp>
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_test_run_info.hpp>
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/benchmark/catch_estimate.hpp> #include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
#include <catch2/benchmark/catch_outlier_classification.hpp>
#include <map> #include <map>
#include <string> #include <string>
@@ -57,11 +56,6 @@ namespace Catch {
std::map<std::string, std::string> m_customOptions; std::map<std::string, std::string> m_customOptions;
}; };
struct TestRunInfo {
constexpr TestRunInfo(StringRef _name) : name(_name) {}
StringRef name;
};
struct AssertionStats { struct AssertionStats {
AssertionStats( AssertionResult const& _assertionResult, AssertionStats( AssertionResult const& _assertionResult,
std::vector<MessageInfo> const& _infoMessages, std::vector<MessageInfo> const& _infoMessages,
@@ -113,45 +107,6 @@ namespace Catch {
bool aborting; bool aborting;
}; };
struct BenchmarkInfo {
std::string name;
double estimatedDuration;
int iterations;
unsigned int samples;
unsigned int resamples;
double clockResolution;
double clockCost;
};
template <class Duration>
struct BenchmarkStats {
BenchmarkInfo info;
std::vector<Duration> samples;
Benchmark::Estimate<Duration> mean;
Benchmark::Estimate<Duration> standardDeviation;
Benchmark::OutlierClassification outliers;
double outlierVariance;
template <typename Duration2>
operator BenchmarkStats<Duration2>() const {
std::vector<Duration2> samples2;
samples2.reserve(samples.size());
for (auto const& sample : samples) {
samples2.push_back(Duration2(sample));
}
return {
info,
CATCH_MOVE(samples2),
mean,
standardDeviation,
outliers,
outlierVariance,
};
}
};
//! By setting up its preferences, a reporter can modify Catch2's behaviour //! By setting up its preferences, a reporter can modify Catch2's behaviour
//! in some regards, e.g. it can request Catch2 to capture writes to //! in some regards, e.g. it can request Catch2 to capture writes to
//! stdout/stderr during test execution, and pass them to the reporter. //! stdout/stderr during test execution, and pass them to the reporter.
@@ -250,7 +205,7 @@ namespace Catch {
*/ */
virtual void skipTest( TestCaseInfo const& testInfo ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
//! Called if a fatal error (signal/structured exception) occured //! Called if a fatal error (signal/structured exception) occurred
virtual void fatalErrorEncountered( StringRef error ) = 0; virtual void fatalErrorEncountered( StringRef error ) = 0;
//! Writes out information about provided reporters using reporter-specific format //! Writes out information about provided reporters using reporter-specific format

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,21 @@
// 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_TEST_INVOKER_HPP_INCLUDED
#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
namespace Catch {
class ITestInvoker {
public:
virtual void invoke() const = 0;
virtual ~ITestInvoker(); // = default
};
} // namespace Catch
#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED

View File

@@ -9,6 +9,5 @@
#include <catch2/interfaces/catch_interfaces_testcase.hpp> #include <catch2/interfaces/catch_interfaces_testcase.hpp>
namespace Catch { namespace Catch {
ITestInvoker::~ITestInvoker() = default;
ITestCaseRegistry::~ITestCaseRegistry() = default; ITestCaseRegistry::~ITestCaseRegistry() = default;
} }

View File

@@ -12,15 +12,7 @@
namespace Catch { namespace Catch {
class TestSpec;
struct TestCaseInfo; struct TestCaseInfo;
class ITestInvoker {
public:
virtual void invoke () const = 0;
virtual ~ITestInvoker(); // = default
};
class TestCaseHandle; class TestCaseHandle;
class IConfig; class IConfig;
@@ -33,11 +25,6 @@ namespace Catch {
virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) 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 #endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED

View File

@@ -12,7 +12,6 @@
#include <catch2/internal/catch_debugger.hpp> #include <catch2/internal/catch_debugger.hpp>
#include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp> #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_run_context.hpp>
#include <catch2/matchers/catch_matchers_string.hpp> #include <catch2/matchers/catch_matchers_string.hpp>
namespace Catch { namespace Catch {
@@ -24,7 +23,9 @@ namespace Catch {
ResultDisposition::Flags resultDisposition ) ResultDisposition::Flags resultDisposition )
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
m_resultCapture( getResultCapture() ) m_resultCapture( getResultCapture() )
{} {
m_resultCapture.notifyAssertionStarted( m_assertionInfo );
}
void AssertionHandler::handleExpr( ITransientExpression const& expr ) { void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );

View File

@@ -11,14 +11,11 @@
#include <catch2/catch_assertion_info.hpp> #include <catch2/catch_assertion_info.hpp>
#include <catch2/internal/catch_decomposer.hpp> #include <catch2/internal/catch_decomposer.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp> #include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_lazy_expr.hpp>
#include <string> #include <string>
namespace Catch { namespace Catch {
class IResultCapture;
struct AssertionReaction { struct AssertionReaction {
bool shouldDebugBreak = false; bool shouldDebugBreak = false;
bool shouldThrow = false; bool shouldThrow = false;

View File

@@ -10,7 +10,7 @@
#include <catch2/catch_config.hpp> #include <catch2/catch_config.hpp>
#include <catch2/internal/catch_string_manip.hpp> #include <catch2/internal/catch_string_manip.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp> #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp> #include <catch2/internal/catch_reporter_registry.hpp>
#include <catch2/internal/catch_console_colour.hpp> #include <catch2/internal/catch_console_colour.hpp>
#include <catch2/internal/catch_parse_numbers.hpp> #include <catch2/internal/catch_parse_numbers.hpp>
#include <catch2/internal/catch_reporter_spec_parser.hpp> #include <catch2/internal/catch_reporter_spec_parser.hpp>
@@ -144,7 +144,7 @@ namespace Catch {
auto const& reporterSpec = *parsed; auto const& reporterSpec = *parsed;
IReporterRegistry::FactoryMap const& factories = auto const& factories =
getRegistryHub().getReporterRegistry().getFactories(); getRegistryHub().getReporterRegistry().getFactories();
auto result = factories.find( reporterSpec.name() ); auto result = factories.find( reporterSpec.name() );

View File

@@ -50,12 +50,18 @@
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
_Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
_Pragma( "GCC diagnostic ignored \"-Wunused-result\"" )
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
_Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" )
# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ # define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
_Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" )
# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
_Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
#endif #endif
@@ -128,6 +134,9 @@
# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ # define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
_Pragma( "clang diagnostic ignored \"-Wcomma\"" ) _Pragma( "clang diagnostic ignored \"-Wcomma\"" )
# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
_Pragma( "clang diagnostic ignored \"-Wshadow\"" )
#endif // __clang__ #endif // __clang__
@@ -365,6 +374,9 @@
#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
#endif #endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS # define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS
#endif #endif
@@ -374,6 +386,16 @@
#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
#endif #endif
#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS )
# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif
#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS )
# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS
#endif
#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS )
# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS
#endif
// The goal of this macro is to avoid evaluation of the arguments, but // The goal of this macro is to avoid evaluation of the arguments, but
// still have the compiler warn on problems inside... // still have the compiler warn on problems inside...
@@ -387,13 +409,6 @@
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif #endif
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
#endif
#if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS)
# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS
#endif
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
#define CATCH_TRY if ((true)) #define CATCH_TRY if ((true))

View File

@@ -18,6 +18,8 @@
#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED #ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED
#define CATCH_CONFIG_COUNTER_HPP_INCLUDED #define CATCH_CONFIG_COUNTER_HPP_INCLUDED
#include <catch2/catch_user_config.hpp>
#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
#define CATCH_INTERNAL_CONFIG_COUNTER #define CATCH_INTERNAL_CONFIG_COUNTER
#endif #endif

View File

@@ -0,0 +1,34 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
/** \file
* Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option
*
* Some of Catch2's macros can be defined differently to work better with
* static analysis tools, like clang-tidy or coverity.
* Currently the main use case is to show that `SECTION`s are executed
* exclusively, and not all in one run of a `TEST_CASE`.
*/
#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
#include <catch2/catch_user_config.hpp>
#if defined(__clang_analyzer__) || defined(__COVERITY__)
#define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT
#endif
#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \
!defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
!defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
#endif
#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED

View File

@@ -17,6 +17,8 @@
#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
#include <catch2/catch_user_config.hpp>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer # if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS

View File

@@ -17,6 +17,8 @@
#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED #ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED
#define CATCH_CONFIG_WCHAR_HPP_INCLUDED #define CATCH_CONFIG_WCHAR_HPP_INCLUDED
#include <catch2/catch_user_config.hpp>
// We assume that WCHAR should be enabled by default, and only disabled // We assume that WCHAR should be enabled by default, and only disabled
// for a shortlist (so far only DJGPP) of compilers. // for a shortlist (so far only DJGPP) of compilers.

View File

@@ -11,8 +11,24 @@
#include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_test_failure_exception.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <exception>
namespace Catch { namespace Catch {
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() );
}
}
}
ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
} }
@@ -37,7 +53,7 @@ namespace Catch {
// First we try user-registered translators. If none of them can // First we try user-registered translators. If none of them can
// handle the exception, it will be rethrown handled by our defaults. // handle the exception, it will be rethrown handled by our defaults.
try { try {
return tryTranslators(); return tryTranslators(m_translators);
} }
// To avoid having to handle TFE explicitly everywhere, we just // To avoid having to handle TFE explicitly everywhere, we just
// rethrow it so that it goes back up the caller. // rethrow it so that it goes back up the caller.
@@ -61,23 +77,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 #else // ^^ Exceptions are enabled // Exceptions are disabled vv
std::string ExceptionTranslatorRegistry::translateActiveException() const { std::string ExceptionTranslatorRegistry::translateActiveException() const {
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); 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 #endif
} }

View File

@@ -21,7 +21,6 @@ namespace Catch {
~ExceptionTranslatorRegistry() override; ~ExceptionTranslatorRegistry() override;
void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ); void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
std::string translateActiveException() const override; std::string translateActiveException() const override;
std::string tryTranslators() const;
private: private:
ExceptionTranslators m_translators; ExceptionTranslators m_translators;

View File

@@ -9,9 +9,9 @@
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp> #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.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/interfaces/catch_interfaces_reporter_factory.hpp>
#include <catch2/internal/catch_test_case_registry_impl.hpp>
#include <catch2/internal/catch_reporter_registry.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_case_insensitive_comparisons.hpp> #include <catch2/internal/catch_case_insensitive_comparisons.hpp>
@@ -54,7 +54,7 @@ namespace Catch {
void listReporters(IEventListener& reporter) { void listReporters(IEventListener& reporter) {
std::vector<ReporterDescription> descriptions; std::vector<ReporterDescription> descriptions;
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
descriptions.reserve(factories.size()); descriptions.reserve(factories.size());
for (auto const& fac : factories) { for (auto const& fac : factories) {
descriptions.push_back({ fac.first, fac.second->getDescription() }); descriptions.push_back({ fac.first, fac.second->getDescription() });

View File

@@ -10,7 +10,7 @@
#include <catch2/internal/catch_result_type.hpp> #include <catch2/internal/catch_result_type.hpp>
#include <catch2/internal/catch_source_line_info.hpp> #include <catch2/internal/catch_source_line_info.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <string> #include <string>

View File

@@ -8,6 +8,8 @@
#ifndef CATCH_OPTIONAL_HPP_INCLUDED #ifndef CATCH_OPTIONAL_HPP_INCLUDED
#define CATCH_OPTIONAL_HPP_INCLUDED #define CATCH_OPTIONAL_HPP_INCLUDED
#include <catch2/internal/catch_move_and_forward.hpp>
#include <cassert> #include <cassert>
namespace Catch { namespace Catch {
@@ -16,35 +18,50 @@ namespace Catch {
template<typename T> template<typename T>
class Optional { class Optional {
public: public:
Optional() : nullableValue( nullptr ) {} Optional(): nullableValue( nullptr ) {}
Optional( T const& _value ) ~Optional() { reset(); }
: nullableValue( new( storage ) T( _value ) )
{}
Optional( Optional const& _other )
: nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
{}
~Optional() { Optional( T const& _value ):
nullableValue( new ( storage ) T( _value ) ) {}
Optional( T&& _value ):
nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {}
Optional& operator=( T const& _value ) {
reset(); reset();
nullableValue = new ( storage ) T( _value );
return *this;
}
Optional& operator=( T&& _value ) {
reset();
nullableValue = new ( storage ) T( CATCH_MOVE( _value ) );
return *this;
} }
Optional& operator= ( Optional const& _other ) { Optional( Optional const& _other ):
if( &_other != this ) { nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {}
Optional( Optional&& _other ):
nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) )
: nullptr ) {}
Optional& operator=( Optional const& _other ) {
if ( &_other != this ) {
reset(); reset();
if( _other ) if ( _other ) { nullableValue = new ( storage ) T( *_other ); }
nullableValue = new( storage ) T( *_other );
} }
return *this; return *this;
} }
Optional& operator = ( T const& _value ) { Optional& operator=( Optional&& _other ) {
if ( &_other != this ) {
reset(); reset();
nullableValue = new( storage ) T( _value ); if ( _other ) {
nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) );
}
}
return *this; return *this;
} }
void reset() { void reset() {
if( nullableValue ) if ( nullableValue ) { nullableValue->~T(); }
nullableValue->~T();
nullableValue = nullptr; nullableValue = nullptr;
} }
@@ -91,7 +108,7 @@ namespace Catch {
} }
private: private:
T *nullableValue; T* nullableValue;
alignas(alignof(T)) char storage[sizeof(T)]; alignas(alignof(T)) char storage[sizeof(T)];
}; };

View File

@@ -0,0 +1,19 @@
// 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_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
#include <catch2/catch_user_config.hpp>
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif
#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED

View File

@@ -5,61 +5,84 @@
// https://www.boost.org/LICENSE_1_0.txt) // https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0 // 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_automake.hpp>
#include <catch2/reporters/catch_reporter_compact.hpp> #include <catch2/reporters/catch_reporter_compact.hpp>
#include <catch2/reporters/catch_reporter_console.hpp> #include <catch2/reporters/catch_reporter_console.hpp>
#include <catch2/reporters/catch_reporter_junit.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_sonarqube.hpp>
#include <catch2/reporters/catch_reporter_tap.hpp> #include <catch2/reporters/catch_reporter_tap.hpp>
#include <catch2/reporters/catch_reporter_teamcity.hpp> #include <catch2/reporters/catch_reporter_teamcity.hpp>
#include <catch2/reporters/catch_reporter_xml.hpp> #include <catch2/reporters/catch_reporter_xml.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_enforce.hpp>
namespace Catch { 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, // Because it is impossible to move out of initializer list,
// we have to add the elements manually // we have to add the elements manually
m_factories["Automake"] = Detail::make_unique<ReporterFactory<AutomakeReporter>>(); m_impl->factories["Automake"] =
m_factories["compact"] = Detail::make_unique<ReporterFactory<CompactReporter>>(); Detail::make_unique<ReporterFactory<AutomakeReporter>>();
m_factories["console"] = Detail::make_unique<ReporterFactory<ConsoleReporter>>(); m_impl->factories["compact"] =
m_factories["JUnit"] = Detail::make_unique<ReporterFactory<JunitReporter>>(); Detail::make_unique<ReporterFactory<CompactReporter>>();
m_factories["SonarQube"] = Detail::make_unique<ReporterFactory<SonarQubeReporter>>(); m_impl->factories["console"] =
m_factories["TAP"] = Detail::make_unique<ReporterFactory<TAPReporter>>(); Detail::make_unique<ReporterFactory<ConsoleReporter>>();
m_factories["TeamCity"] = Detail::make_unique<ReporterFactory<TeamCityReporter>>(); m_impl->factories["JUnit"] =
m_factories["XML"] = Detail::make_unique<ReporterFactory<XmlReporter>>(); 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; ReporterRegistry::~ReporterRegistry() = default;
IEventListenerPtr
IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const { ReporterRegistry::create( std::string const& name,
auto it = m_factories.find( name ); ReporterConfig&& config ) const {
if( it == m_factories.end() ) auto it = m_impl->factories.find( name );
return nullptr; if ( it == m_impl->factories.end() ) return nullptr;
return it->second->create( CATCH_MOVE(config) ); return it->second->create( CATCH_MOVE( config ) );
} }
void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) { void ReporterRegistry::registerReporter( std::string const& name,
IReporterFactoryPtr factory ) {
CATCH_ENFORCE( name.find( "::" ) == name.npos, CATCH_ENFORCE( name.find( "::" ) == name.npos,
"'::' is not allowed in reporter name: '" + name + '\'' ); "'::' 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" ); 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( void ReporterRegistry::registerListener(
Detail::unique_ptr<EventListenerFactory> factory ) { 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 { std::map<std::string,
return m_factories; IReporterFactoryPtr,
} Detail::CaseInsensitiveLess> const&
IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { ReporterRegistry::getFactories() const {
return m_listeners; return m_impl->factories;
} }
} std::vector<Detail::unique_ptr<EventListenerFactory>> const&
ReporterRegistry::getListeners() const {
return m_impl->listeners;
}
} // namespace Catch

View File

@@ -8,31 +8,48 @@
#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED #ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED #define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_reporter.hpp> #include <catch2/internal/catch_case_insensitive_comparisons.hpp>
#include <catch2/interfaces/catch_interfaces_reporter_registry.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <map> #include <map>
#include <string>
#include <vector>
namespace Catch { 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: public:
ReporterRegistry(); 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 registerReporter( std::string const& name,
void registerListener( Detail::unique_ptr<EventListenerFactory> factory ); IReporterFactoryPtr factory );
FactoryMap const& getFactories() const override; void
Listeners const& getListeners() const override; registerListener( Detail::unique_ptr<EventListenerFactory> factory );
private: std::map<std::string,
FactoryMap m_factories; IReporterFactoryPtr,
Listeners m_listeners; Detail::CaseInsensitiveLess> const&
getFactories() const;
std::vector<Detail::unique_ptr<EventListenerFactory>> const&
getListeners() const;
}; };
}
} // end namespace Catch
#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED #endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED

View File

@@ -21,9 +21,9 @@ namespace Catch {
}; };
kvPair splitKVPair(StringRef kvString) { kvPair splitKVPair(StringRef kvString) {
auto splitPos = static_cast<size_t>( std::distance( auto splitPos = static_cast<size_t>(
kvString.begin(), std::find( kvString.begin(), kvString.end(), '=' ) -
std::find( kvString.begin(), kvString.end(), '=' ) ) ); kvString.begin() );
return { kvString.substr( 0, splitPos ), return { kvString.substr( 0, splitPos ),
kvString.substr( splitPos + 1, kvString.size() ) }; kvString.substr( splitPos + 1, kvString.size() ) };

View File

@@ -8,8 +8,9 @@
#include <catch2/internal/catch_run_context.hpp> #include <catch2/internal/catch_run_context.hpp>
#include <catch2/catch_user_config.hpp> #include <catch2/catch_user_config.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_context.hpp> #include <catch2/internal/catch_context.hpp>
#include <catch2/internal/catch_enforce.hpp> #include <catch2/internal/catch_enforce.hpp>
@@ -266,7 +267,7 @@ namespace Catch {
} }
void RunContext::assertionEnded(AssertionResult const & result) { void RunContext::assertionEnded(AssertionResult&& result) {
if (result.getResultType() == ResultWas::Ok) { if (result.getResultType() == ResultWas::Ok) {
m_totals.assertions.passed++; m_totals.assertions.passed++;
m_lastAssertionPassed = true; m_lastAssertionPassed = true;
@@ -288,19 +289,26 @@ namespace Catch {
m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals));
if (result.getResultType() != ResultWas::Warning) if ( result.getResultType() != ResultWas::Warning ) {
m_messageScopes.clear(); m_messageScopes.clear();
}
// Reset working state // Reset working state
resetAssertionInfo(); resetAssertionInfo();
m_lastResult = result; m_lastResult = CATCH_MOVE( result );
} }
void RunContext::resetAssertionInfo() { void RunContext::resetAssertionInfo() {
m_lastAssertionInfo.macroName = StringRef(); m_lastAssertionInfo.macroName = StringRef();
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
} }
bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) { void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
m_reporter->assertionStarting( info );
}
bool RunContext::sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo,
Counts& assertions ) {
ITracker& sectionTracker = ITracker& sectionTracker =
SectionTracker::acquire( m_trackerContext, SectionTracker::acquire( m_trackerContext,
TestCaseTracking::NameAndLocationRef( TestCaseTracking::NameAndLocationRef(
@@ -438,7 +446,7 @@ namespace Catch {
tempResult.message = static_cast<std::string>(message); tempResult.message = static_cast<std::string>(message);
AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
assertionEnded(result); assertionEnded(CATCH_MOVE(result) );
handleUnfinishedSections(); handleUnfinishedSections();
@@ -560,8 +568,6 @@ namespace Catch {
ITransientExpression const& expr, ITransientExpression const& expr,
AssertionReaction& reaction AssertionReaction& reaction
) { ) {
m_reporter->assertionStarting( info );
bool negated = isFalseTest( info.resultDisposition ); bool negated = isFalseTest( info.resultDisposition );
bool result = expr.getResult() != negated; bool result = expr.getResult() != negated;
@@ -590,7 +596,7 @@ namespace Catch {
AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
assertionEnded( assertionResult ); assertionEnded( CATCH_MOVE(assertionResult) );
} }
void RunContext::handleMessage( void RunContext::handleMessage(
@@ -599,16 +605,16 @@ namespace Catch {
StringRef message, StringRef message,
AssertionReaction& reaction AssertionReaction& reaction
) { ) {
m_reporter->assertionStarting( info );
m_lastAssertionInfo = info; m_lastAssertionInfo = info;
AssertionResultData data( resultType, LazyExpression( false ) ); AssertionResultData data( resultType, LazyExpression( false ) );
data.message = static_cast<std::string>(message); data.message = static_cast<std::string>(message);
AssertionResult assertionResult{ m_lastAssertionInfo, AssertionResult assertionResult{ m_lastAssertionInfo,
CATCH_MOVE( data ) }; CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if ( !assertionResult.isOk() ) { const auto isOk = assertionResult.isOk();
assertionEnded( CATCH_MOVE(assertionResult) );
if ( !isOk ) {
populateReaction( reaction ); populateReaction( reaction );
} else if ( resultType == ResultWas::ExplicitSkip ) { } else if ( resultType == ResultWas::ExplicitSkip ) {
// TODO: Need to handle this explicitly, as ExplicitSkip is // TODO: Need to handle this explicitly, as ExplicitSkip is
@@ -633,7 +639,7 @@ namespace Catch {
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = CATCH_MOVE(message); data.message = CATCH_MOVE(message);
AssertionResult assertionResult{ info, CATCH_MOVE(data) }; AssertionResult assertionResult{ info, CATCH_MOVE(data) };
assertionEnded( assertionResult ); assertionEnded( CATCH_MOVE(assertionResult) );
populateReaction( reaction ); populateReaction( reaction );
} }
@@ -651,7 +657,7 @@ namespace Catch {
AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult ); assertionEnded( CATCH_MOVE(assertionResult) );
} }
void RunContext::handleNonExpr( void RunContext::handleNonExpr(
AssertionInfo const &info, AssertionInfo const &info,
@@ -662,10 +668,10 @@ namespace Catch {
AssertionResultData data( resultType, LazyExpression( false ) ); AssertionResultData data( resultType, LazyExpression( false ) );
AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( assertionResult );
if( !assertionResult.isOk() ) const auto isOk = assertionResult.isOk();
populateReaction( reaction ); assertionEnded( CATCH_MOVE(assertionResult) );
if ( !isOk ) { populateReaction( reaction ); }
} }

View File

@@ -8,8 +8,9 @@
#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED #ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
#define CATCH_RUN_CONTEXT_HPP_INCLUDED #define CATCH_RUN_CONTEXT_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_reporter.hpp> #include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_test_registry.hpp> #include <catch2/internal/catch_test_registry.hpp>
#include <catch2/internal/catch_test_run_info.hpp>
#include <catch2/internal/catch_fatal_condition_handler.hpp> #include <catch2/internal/catch_fatal_condition_handler.hpp>
#include <catch2/catch_test_case_info.hpp> #include <catch2/catch_test_case_info.hpp>
#include <catch2/catch_message.hpp> #include <catch2/catch_message.hpp>
@@ -26,6 +27,8 @@ namespace Catch {
class IGeneratorTracker; class IGeneratorTracker;
class IConfig; class IConfig;
class IEventListener;
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@@ -67,6 +70,7 @@ namespace Catch {
ResultWas::OfType resultType, ResultWas::OfType resultType,
AssertionReaction &reaction ) override; AssertionReaction &reaction ) override;
void notifyAssertionStarted( AssertionInfo const& info ) override;
bool sectionStarted( StringRef sectionName, bool sectionStarted( StringRef sectionName,
SourceLineInfo const& sectionLineInfo, SourceLineInfo const& sectionLineInfo,
Counts& assertions ) override; Counts& assertions ) override;
@@ -117,7 +121,7 @@ namespace Catch {
void resetAssertionInfo(); void resetAssertionInfo();
bool testForMissingAssertions( Counts& assertions ); bool testForMissingAssertions( Counts& assertions );
void assertionEnded( AssertionResult const& result ); void assertionEnded( AssertionResult&& result );
void reportExpr void reportExpr
( AssertionInfo const &info, ( AssertionInfo const &info,
ResultWas::OfType resultType, ResultWas::OfType resultType,

View File

@@ -9,6 +9,7 @@
#define CATCH_SECTION_HPP_INCLUDED #define CATCH_SECTION_HPP_INCLUDED
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
#include <catch2/internal/catch_config_static_analysis_support.hpp>
#include <catch2/internal/catch_noncopyable.hpp> #include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/catch_section_info.hpp> #include <catch2/catch_section_info.hpp>
#include <catch2/catch_timer.hpp> #include <catch2/catch_timer.hpp>
@@ -38,16 +39,62 @@ namespace Catch {
} // end namespace Catch } // end namespace Catch
#define INTERNAL_CATCH_SECTION( ... ) \ #if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
# define INTERNAL_CATCH_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( 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 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ # define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
catch_internal_Section ) = \
Catch::SectionInfo( \
CATCH_INTERNAL_LINEINFO, \
( Catch::ReusableStringStream() << __VA_ARGS__ ) \
.str() ) ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#else
// These section definitions imply that at most one section at one level
// will be intered (because only one section's __LINE__ can be equal to
// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
namespace Catch {
namespace Detail {
// Intentionally without linkage, as it should only be used as a dummy
// symbol for static analysis.
int GetNewSectionHint();
} // namespace Detail
} // namespace Catch
# define INTERNAL_CATCH_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \
catchInternalSectionHint, \
catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
catchInternalPreviousSectionHint == __LINE__ ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
if ( [[maybe_unused]] int catchInternalPreviousSectionHint = \
catchInternalSectionHint, \
catchInternalSectionHint = Catch::Detail::GetNewSectionHint(); \
catchInternalPreviousSectionHint == __LINE__ ) \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
#endif
#endif // CATCH_SECTION_HPP_INCLUDED #endif // CATCH_SECTION_HPP_INCLUDED

View File

@@ -17,10 +17,10 @@ namespace Catch {
// as well as // as well as
// << stuff +StreamEndStop // << stuff +StreamEndStop
struct StreamEndStop { struct StreamEndStop {
StringRef operator+() const { return StringRef(); } constexpr StringRef operator+() const { return StringRef(); }
template <typename T> template <typename T>
friend T const& operator+( T const& value, StreamEndStop ) { constexpr friend T const& operator+( T const& value, StreamEndStop ) {
return value; return value;
} }
}; };

View File

@@ -8,7 +8,6 @@
#include <catch2/internal/catch_string_manip.hpp> #include <catch2/internal/catch_string_manip.hpp>
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <algorithm>
#include <ostream> #include <ostream>
#include <cstring> #include <cstring>
#include <cctype> #include <cctype>
@@ -32,9 +31,9 @@ namespace Catch {
return s.find( infix ) != std::string::npos; return s.find( infix ) != std::string::npos;
} }
void toLowerInPlace( std::string& s ) { void toLowerInPlace( std::string& s ) {
std::transform( s.begin(), s.end(), s.begin(), []( char c ) { for ( char& c : s ) {
return toLower( c ); c = toLower( c );
} ); }
} }
std::string toLower( std::string const& s ) { std::string toLower( std::string const& s ) {
std::string lc = s; std::string lc = s;

View File

@@ -24,6 +24,38 @@
namespace Catch { namespace Catch {
namespace {
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 );
}
}
static bool matchTest( TestCaseHandle const& testCase,
TestSpec const& testSpec,
IConfig const& config ) {
return testSpec.matches( testCase.getTestCaseInfo() ) &&
isThrowSafe( testCase, config );
}
} // end unnamed namespace
std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) { std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
switch (config.runOrder()) { switch (config.runOrder()) {
case TestRunOrder::Declared: case TestRunOrder::Declared:
@@ -80,29 +112,6 @@ namespace Catch {
return !testCase.getTestCaseInfo().throws() || config.allowThrows(); 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> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
std::vector<TestCaseHandle> filtered; std::vector<TestCaseHandle> filtered;
filtered.reserve( testCases.size() ); filtered.reserve( testCases.size() );

View File

@@ -16,16 +16,14 @@
namespace Catch { namespace Catch {
class TestCaseHandle;
class IConfig; class IConfig;
class ITestInvoker;
class TestCaseHandle;
class TestSpec; class TestSpec;
std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ); std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases );
bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config );
void enforceNoDuplicateTestCases( std::vector<TestCaseHandle> const& functions );
std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, 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 ); std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );

View File

@@ -113,7 +113,7 @@ namespace TestCaseTracking {
//! Returns true if tracker run to completion (successfully or not) //! Returns true if tracker run to completion (successfully or not)
virtual bool isComplete() const = 0; virtual bool isComplete() const = 0;
//! Returns true if tracker run to completion succesfully //! Returns true if tracker run to completion successfully
bool isSuccessfullyCompleted() const { bool isSuccessfullyCompleted() const {
return m_runState == CompletedSuccessfully; return m_runState == CompletedSuccessfully;
} }

View File

@@ -10,6 +10,7 @@
#include <catch2/catch_user_config.hpp> #include <catch2/catch_user_config.hpp>
#include <catch2/internal/catch_assertion_handler.hpp> #include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
#include <catch2/interfaces/catch_interfaces_capture.hpp> #include <catch2/interfaces/catch_interfaces_capture.hpp>
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_source_line_info.hpp> #include <catch2/internal/catch_source_line_info.hpp>
@@ -22,12 +23,6 @@
#if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE)
#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
#else
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
#endif
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -95,6 +90,7 @@
if( catchAssertionHandler.allowThrows() ) \ if( catchAssertionHandler.allowThrows() ) \
try { \ try { \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
static_cast<void>(__VA_ARGS__); \ static_cast<void>(__VA_ARGS__); \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
@@ -115,6 +111,7 @@
if( catchAssertionHandler.allowThrows() ) \ if( catchAssertionHandler.allowThrows() ) \
try { \ try { \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
static_cast<void>(expr); \ static_cast<void>(expr); \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
@@ -141,6 +138,7 @@
if( catchAssertionHandler.allowThrows() ) \ if( catchAssertionHandler.allowThrows() ) \
try { \ try { \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
static_cast<void>(__VA_ARGS__); \ static_cast<void>(__VA_ARGS__); \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \

View File

@@ -16,6 +16,7 @@
#include <iterator> #include <iterator>
namespace Catch { namespace Catch {
ITestInvoker::~ITestInvoker() = default;
namespace { namespace {
static StringRef extractClassName( StringRef classOrMethodName ) { static StringRef extractClassName( StringRef classOrMethodName ) {

View File

@@ -8,9 +8,10 @@
#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED #ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
#define CATCH_TEST_REGISTRY_HPP_INCLUDED #define CATCH_TEST_REGISTRY_HPP_INCLUDED
#include <catch2/internal/catch_config_static_analysis_support.hpp>
#include <catch2/internal/catch_source_line_info.hpp> #include <catch2/internal/catch_source_line_info.hpp>
#include <catch2/internal/catch_noncopyable.hpp> #include <catch2/internal/catch_noncopyable.hpp>
#include <catch2/interfaces/catch_interfaces_testcase.hpp> #include <catch2/interfaces/catch_interfaces_test_invoker.hpp>
#include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <catch2/internal/catch_unique_name.hpp> #include <catch2/internal/catch_unique_name.hpp>
@@ -72,6 +73,9 @@ struct AutoReg : Detail::NonCopyable {
void TestName::test() void TestName::test()
#endif #endif
#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \ static void TestName(); \
@@ -84,19 +88,40 @@ struct AutoReg : Detail::NonCopyable {
#define INTERNAL_CATCH_TESTCASE( ... ) \ #define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
/////////////////////////////////////////////////////////////////////////////// #else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
// Dummy registrator for the dumy test case macros
namespace Catch {
namespace Detail {
struct DummyUse {
DummyUse( void ( * )( int ) );
};
} // namespace Detail
} // namespace Catch
// Note that both the presence of the argument and its exact name are
// necessary for the section support.
// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE`
// tests can compile. The redefined `TEST_CASE` shadows this with param.
static int catchInternalSectionHint = 0;
# define INTERNAL_CATCH_TESTCASE2( fname ) \
static void fname( int ); \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
namespace { \ static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ dummyUser )( &fname ); \
Catch::makeTestInvoker( &QualifiedMethod ), \ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
CATCH_INTERNAL_LINEINFO, \ static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
"&" #QualifiedMethod##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); \
} /* NOLINT */ \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
# define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ) )
#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
@@ -118,6 +143,22 @@ struct AutoReg : Detail::NonCopyable {
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
namespace { \
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
Catch::makeTestInvoker( &QualifiedMethod ), \
CATCH_INTERNAL_LINEINFO, \
"&" #QualifiedMethod##_catch_sr, \
Catch::NameAndTags{ __VA_ARGS__ } ); \
} /* NOLINT */ \
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
do { \ do { \

View File

@@ -0,0 +1,22 @@
// 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

View File

@@ -59,7 +59,7 @@ namespace Catch {
// Calculates the length of the current line // Calculates the length of the current line
void calcLength(); void calcLength();
// Returns current indention width // Returns current indentation width
size_t indentSize() const; size_t indentSize() const;
// Creates an indented and (optionally) suffixed string from // Creates an indented and (optionally) suffixed string from

View File

@@ -129,7 +129,7 @@ namespace Catch {
/** /**
* Creates a matcher that checks if all elements in a range are equal * Creates a matcher that checks if all elements in a range are equal
* to all elements in another range, in some permuation. * to all elements in another range, in some permutation.
* *
* Uses to provided predicate `predicate` to do the comparisons * Uses to provided predicate `predicate` to do the comparisons
*/ */

View File

@@ -8,9 +8,14 @@
#ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED #ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED
#define CATCH_MATCHERS_IMPL_HPP_INCLUDED #define CATCH_MATCHERS_IMPL_HPP_INCLUDED
#include <catch2/internal/catch_test_macro_impl.hpp> #include <catch2/internal/catch_assertion_handler.hpp>
#include <catch2/internal/catch_source_line_info.hpp>
#include <catch2/internal/catch_decomposer.hpp>
#include <catch2/internal/catch_preprocessor_internal_stringify.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <string>
namespace Catch { namespace Catch {
template<typename ArgT, typename MatcherT> template<typename ArgT, typename MatcherT>

View File

@@ -32,6 +32,8 @@ benchmark_headers = [
'benchmark/catch_sample_analysis.hpp', 'benchmark/catch_sample_analysis.hpp',
'benchmark/detail/catch_analyse.hpp', 'benchmark/detail/catch_analyse.hpp',
'benchmark/detail/catch_benchmark_function.hpp', 'benchmark/detail/catch_benchmark_function.hpp',
'benchmark/detail/catch_benchmark_stats.hpp',
'benchmark/detail/catch_benchmark_stats_fwd.hpp',
'benchmark/detail/catch_complete_invoke.hpp', 'benchmark/detail/catch_complete_invoke.hpp',
'benchmark/detail/catch_estimate_clock.hpp', 'benchmark/detail/catch_estimate_clock.hpp',
'benchmark/detail/catch_measure.hpp', 'benchmark/detail/catch_measure.hpp',
@@ -64,8 +66,8 @@ internal_headers = [
'interfaces/catch_interfaces_registry_hub.hpp', 'interfaces/catch_interfaces_registry_hub.hpp',
'interfaces/catch_interfaces_reporter.hpp', 'interfaces/catch_interfaces_reporter.hpp',
'interfaces/catch_interfaces_reporter_factory.hpp', 'interfaces/catch_interfaces_reporter_factory.hpp',
'interfaces/catch_interfaces_reporter_registry.hpp',
'interfaces/catch_interfaces_tag_alias_registry.hpp', 'interfaces/catch_interfaces_tag_alias_registry.hpp',
'interfaces/catch_interfaces_test_invoker.hpp',
'interfaces/catch_interfaces_testcase.hpp', 'interfaces/catch_interfaces_testcase.hpp',
'internal/catch_assertion_handler.hpp', 'internal/catch_assertion_handler.hpp',
'internal/catch_case_insensitive_comparisons.hpp', 'internal/catch_case_insensitive_comparisons.hpp',
@@ -76,6 +78,7 @@ internal_headers = [
'internal/catch_compiler_capabilities.hpp', 'internal/catch_compiler_capabilities.hpp',
'internal/catch_config_android_logwrite.hpp', 'internal/catch_config_android_logwrite.hpp',
'internal/catch_config_counter.hpp', 'internal/catch_config_counter.hpp',
'internal/catch_config_static_analysis_support.hpp',
'internal/catch_config_uncaught_exceptions.hpp', 'internal/catch_config_uncaught_exceptions.hpp',
'internal/catch_config_wchar.hpp', 'internal/catch_config_wchar.hpp',
'internal/catch_console_colour.hpp', 'internal/catch_console_colour.hpp',
@@ -108,6 +111,7 @@ internal_headers = [
'internal/catch_platform.hpp', 'internal/catch_platform.hpp',
'internal/catch_polyfills.hpp', 'internal/catch_polyfills.hpp',
'internal/catch_preprocessor.hpp', 'internal/catch_preprocessor.hpp',
'internal/catch_preprocessor_internal_stringify.hpp',
'internal/catch_preprocessor_remove_parens.hpp', 'internal/catch_preprocessor_remove_parens.hpp',
'internal/catch_random_number_generator.hpp', 'internal/catch_random_number_generator.hpp',
'internal/catch_random_seed_generation.hpp', 'internal/catch_random_seed_generation.hpp',
@@ -133,6 +137,7 @@ internal_headers = [
'internal/catch_test_failure_exception.hpp', 'internal/catch_test_failure_exception.hpp',
'internal/catch_test_macro_impl.hpp', 'internal/catch_test_macro_impl.hpp',
'internal/catch_test_registry.hpp', 'internal/catch_test_registry.hpp',
'internal/catch_test_run_info.hpp',
'internal/catch_test_spec_parser.hpp', 'internal/catch_test_spec_parser.hpp',
'internal/catch_textflow.hpp', 'internal/catch_textflow.hpp',
'internal/catch_to_string.hpp', 'internal/catch_to_string.hpp',
@@ -189,7 +194,6 @@ internal_sources = files(
'interfaces/catch_interfaces_registry_hub.cpp', 'interfaces/catch_interfaces_registry_hub.cpp',
'interfaces/catch_interfaces_reporter.cpp', 'interfaces/catch_interfaces_reporter.cpp',
'interfaces/catch_interfaces_reporter_factory.cpp', 'interfaces/catch_interfaces_reporter_factory.cpp',
'interfaces/catch_interfaces_reporter_registry.cpp',
'interfaces/catch_interfaces_testcase.cpp', 'interfaces/catch_interfaces_testcase.cpp',
'internal/catch_assertion_handler.cpp', 'internal/catch_assertion_handler.cpp',
'internal/catch_case_insensitive_comparisons.cpp', 'internal/catch_case_insensitive_comparisons.cpp',
@@ -262,6 +266,7 @@ internal_sources = files(
'catch_timer.cpp', 'catch_timer.cpp',
'catch_tostring.cpp', 'catch_tostring.cpp',
'catch_totals.cpp', 'catch_totals.cpp',
'catch_translate_exception.cpp',
'catch_version.cpp', 'catch_version.cpp',
) )

View File

@@ -8,7 +8,6 @@
#ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED #ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
#define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED #define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/reporters/catch_reporter_streaming_base.hpp> #include <catch2/reporters/catch_reporter_streaming_base.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>

View File

@@ -171,7 +171,7 @@ private:
return; return;
const auto itEnd = messages.cend(); const auto itEnd = messages.cend();
const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); const auto N = static_cast<std::size_t>(itEnd - itMessage);
stream << colourImpl->guardColour( colour ) << " with " stream << colourImpl->guardColour( colour ) << " with "
<< pluralise( N, "message"_sr ) << ':'; << pluralise( N, "message"_sr ) << ':';

View File

@@ -8,7 +8,6 @@
#ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED #ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
#define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED #define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
#include <catch2/reporters/catch_reporter_common_base.hpp> #include <catch2/reporters/catch_reporter_common_base.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
@@ -125,7 +124,7 @@ namespace Catch {
void skipTest(TestCaseInfo const&) override {} void skipTest(TestCaseInfo const&) override {}
protected: protected:
//! Should the cumulative base store the assertion expansion for succesful assertions? //! Should the cumulative base store the assertion expansion for successful assertions?
bool m_shouldStoreSuccesfulAssertions = true; bool m_shouldStoreSuccesfulAssertions = true;
//! Should the cumulative base store the assertion expansion for failed assertions? //! Should the cumulative base store the assertion expansion for failed assertions?
bool m_shouldStoreFailedAssertions = true; bool m_shouldStoreFailedAssertions = true;

View File

@@ -8,6 +8,7 @@
#include <catch2/reporters/catch_reporter_registrars.hpp> #include <catch2/reporters/catch_reporter_registrars.hpp>
#include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp> #include <catch2/internal/catch_compiler_capabilities.hpp>
namespace Catch { namespace Catch {

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