Compare commits

..

44 Commits

Author SHA1 Message Date
Martin Hořeňovský
5c88067bd3 v2.13.6 2021-04-16 20:14:58 +02:00
Georg Schwab
86a4d704bc fixed inconsistent semicolon expansion in catch_discover_tests (Bug #2214) 2021-04-16 17:26:08 +02:00
Matteo Beniamino
469a717395 Fixed [dis]engage_platform declarations mismatch 2021-04-13 19:50:32 +02:00
Martin Hořeňovský
42e368dd0a v2.13.5 2021-04-10 23:48:32 +02:00
Clare Macrae
1ff1f2741d Prevent Catch2 v2 tests running if loaded as a sub-project
See #2202
2021-04-09 23:54:13 +02:00
Julien Brianceau
269f96e2bc Fix typos in the code base
Note that only documentation and comments are impacted by this change.
2021-04-08 18:06:36 +02:00
Martin Hořeňovský
cec35630fb Don't build Catch2WithMain target by default for v2
The `Catch2WithMain` target was added experimentally for v2.13.4
to provide potentially better compilation (and link) times to users.
However, having it compiled by default causes worse experience for
people who do not use it, and for the v2 versions the single include
distribution is still the main one.

Closes #2142
2021-04-05 18:04:31 +02:00
Martin Hořeňovský
b8b03da534 Mangle doccoments to avoid breaking single include stitching 2021-04-04 18:09:29 +02:00
Martin Hořeňovský
8f277a54c0 Significantly refactor fatal error handling
Because new glibc has changed `MINSIGSTKSZ` to be a syscall instead
of being constant, the signal posix handling needed changes, as it
used the value in constexpr context, for deciding size of an array.
It would be simple to fix it by having the handler determine the
signal handling stack size and allocate the memory every time the
handler is being installed, but that would add another allocation
and a syscall every time a test case is entered.

Instead, I split apart the idea of preparing fatal error handlers,
and engaging them, so that the memory can be allocated only once
and still be guarded by RAII.

Also turns out that Catch2's use of `MINSIGSTKSZ` was wrong, and
we should've been using `SIGSTKSZ` the whole time, which we use now.

Closes #2178
2021-04-04 18:09:26 +02:00
Pavel Kamenov
4cb3220a8a Add lcc to the list of unwanted compilers that mimic gcc 2021-04-04 14:05:39 +02:00
Scott Hutchinson
b025a007b9 Wrap all std::min and std::max calls in parentheses 2021-02-20 23:28:20 +01:00
Rob Boehne
68975e3ff3 [Issue 2154] Correct error when building with IBM's latest XLC (#2155)
* [Issue 2154] Correct error when building with IBM's latest XLC compiler with xlclang++ front-end.

On AIX, the XLC 16.1.0.1 compiler considers the call to `std::abs` ambigious, so it needs help with a static_cast to the type of the template argument.

Co-authored-by: Martin Hořeňovský <martin.horenovsky@gmail.com>
2021-01-21 22:50:49 +01:00
Martin Hořeňovský
bcb9ea8cb5 Merge pull request #2157 from tdegeus/patch
Making target detection on Mac more robust
2021-01-21 15:35:23 +01:00
Tom de Geus
d4c9494eb5 Making target detection on Mac more robust 2021-01-20 21:12:18 +01:00
Mathieu Mirmont
bed285af07 Make the build reproducible with g++-8 and clang-10
Make the build reproducible by removing references to the source
directory from the Catch2WithMain static library.
2021-01-13 18:09:24 +01:00
Martin Hořeňovský
de6fe184a9 v2.13.4 2020-12-29 15:03:40 +01:00
Martin Hořeňovský
fe3dddcc6d Fix updateVersionPlaceholder when the placeholder starts the line 2020-12-29 15:02:25 +01:00
Reinhold Gschweicher
18ab353e55 Add deprecation warning in ParseAndCatchTests
Parsing C++ with regex in CMake is error prone and regularly leads to silently
dropped (not run) test cases.

Going forward the function `catch_discover_tests` from `contrib/CMake.cmake`
should be used.

For more information see https://github.com/catchorg/Catch2/issues/2092#issuecomment-747342765
2020-12-21 13:15:36 +01:00
Reinhold Gschweicher
2375a7f5b7 Fix Catch.cmake helper by setting variable globally
Set `_CATCH_DISCOVER_TESTS_SCRIPT` helper variable globally. Otherwise in a
scoped call (like `add_subdirectory()`) the variable gets lost. This lost
variable results in a post build error with not much information to lead to the
root of the problem.

This enables the usage of the helper script with the following example structure

- CMakeLists.txt (project root with `add_subdirectory(external/catch2)`
- external/catch2
  - CMakeLists.txt (contents listed below)
  - contrib/Catch.cmake
  - contrib/CatchAddTests.cmake
  - catch2/catch.hpp
- tests
  - CMakeLists.txt (add tests with `catch_discover_tests(${PROJECT_NAME})`)

contents of project specific helper `external/catch2/CMakeLists.txt`
```cmake
cmake_minimum_required (VERSION 3.1...${CMAKE_VERSION})
project(Catch2 LANGUAGES CXX VERSION 2.13.3)
add_library(Catch2 INTERFACE)
target_include_directories(Catch2
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)
 # provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2)
include(contrib/Catch.cmake)
```
2020-12-17 18:50:04 +01:00
Martin Hořeňovský
fac517d571 Fix conan package build 2020-11-26 15:05:58 +01:00
Florian Berchtold
578f8b8006 Add bazel support 2020-11-18 21:37:12 +01:00
Deniz Evrenci
92f8b01dfa Add the static library Catch2WithMain
It should provide a shared impl for all targets that need to link
against Catch2's implementation. However, due to limitations of
C++ linking and Catch2's v2 implementation, this is only experimental
and might not work under some circumstances.
2020-11-18 21:37:10 +01:00
Martin Hořeňovský
dc7e705672 Small cleanups for the reworked test case order hashing 2020-11-17 21:08:33 +01:00
Sergio Losilla
3ba745552b Modified hash to make it more independent of the choice of test names. 2020-11-17 20:58:16 +01:00
Martin Hořeňovský
ff349a50bf v2.13.3 2020-10-31 18:21:23 +01:00
Martin Hořeňovský
aca2472d40 Stop uploading new releases to wandbox 2020-10-31 18:21:00 +01:00
Martin Hořeňovský
765ac08f08 Fix potential infinite loops in generators combined with section filter
The problem was that under specific circumstances, namely that none
of their children progressed, `GeneratorTracker` will not progress.
This was changed recently, to allow for code like this, where a
`SECTION` follows a `GENERATE` at the same level:

```cpp
SECTION("A") {}
auto a = GENERATE(1, 2);
SECTION("B") {}
```

However, this interacted badly with `SECTION` filters (`-c foo`),
as they could deactivate all `SECTION`s below a generator, and thus
stop it from progressing forever. This commit makes GeneratorTracker
check whether there are any filters active, and if they are, it checks
whether its section-children can ever run.

Fixes #2025
2020-10-31 18:04:15 +01:00
Martin Hořeňovský
8dd25b0410 Fix bunch of links to master to point to v2.x branch
Fixes #2063
Related to #2050
2020-10-21 15:30:35 +02:00
Reinhold Gschweicher
69297ceeb6 Consider CMP0110 add_test() policy
CMake 3.19 introduces new add_test() behavior guarded with the policy
CMP0110.

See: https://cmake.org/cmake/help/latest/policy/CMP0110.html

Update the helper script ParseAndAddCatchTests to consider the policy and
handle the test case name accordingly.
2020-10-20 23:25:45 +02:00
Reinhold Gschweicher
2d30df3500 Fix indentation in ParseAndAddCatchTests
Consistently use 4 spaces instead of tabs
2020-10-20 13:48:46 +02:00
Reinhold Gschweicher
77b2a7daea Fix CMake regex to add tests
Fix regex that requires two string arguments in the form of
TEST_CASE("a", "b") resulting in not finding TEST_CASE("a") entries.

See https://regex101.com/r/JygOND/1

Fixes: https://github.com/catchorg/Catch2/issues/2055
2020-10-20 13:48:14 +02:00
laoshanxi
e905edb10f Add AppMesh to Open Source projects using Catch 2020-10-20 13:48:14 +02:00
Martin Hořeňovský
87074da73e v2.13.2 2020-10-07 11:43:02 +02:00
Martin Hořeňovský
e6f5e05ebc Improve detection of std::uncaught_exceptions support
The problem was that Catch2 did not reliably include `<exception>`
before it checked for the feature test macro for
`std::uncaught_exceptions`. To avoid overhead of including
`<exception>` everywhere, the configuration check was split out
into a separate header.

Closes #2021
2020-10-06 11:07:53 +02:00
Rémy Salim
44900d5371 Add WORKING_DIRECTORY to CatchAddTests.cmake commands 2020-10-02 23:29:40 +02:00
Martin Hořeňovský
7c75ecaef4 Workaround AppleClang bug by renaming TestHasher constructor argument
As far as I understand the standard, if there is a function called
`rng` in the global namespace, and a function argument called `rng`,
then the argument should shadow the function. This then means that
uses of `rng` inside the function should refer to the argument.

This is not the case for AppleClang 12.0.0. Luckily the workaround
is simple enough; just rename the argument. Given that the function
is 3 lines and uncomplicated, the change of the name doesn't really
affect readability.

Still, WTF AppleClang?

Closes #2030
2020-10-02 23:22:49 +02:00
Matt Godbolt
fba0feeba1 Add missing syntax highlighting tag 2020-09-24 22:43:07 +02:00
Ansel Sermersheim
3e8800beb1 Support template test cases in ParseAndAddCatchTests
* Change regex to allow parentheses inside the test macro for a type list
* Append a wildcard to the CTestName if the test case is a template
* Also change the regular expression so parentheses are allowed in names
  (fixes #1848)
2020-09-24 22:42:32 +02:00
Martin Hořeňovský
314a05d809 Merge pull request #2023 from globberwops/feature/add-reporter-and-output-dir
Add REPORTER and OUTPUT_DIR args to catch_discover_tests
2020-09-23 22:47:21 +02:00
Martin Stump
eadf4e32b6 Add REPORTER and OUTPUT_* args 2020-09-23 19:12:06 +02:00
Florian Berchtold
f9620d11be Docu/Show how to use CMake FetchContent (#2028) 2020-09-20 18:09:33 +02:00
Will Pazner
00db4fb497 Disable __builtin_constant_p when compiling with nvcc 2020-09-18 16:07:18 +02:00
kotaiadam
2fc83e7e9c fixes bug in example - undeclared identifier
j was not declared in `SECTION("two")`
2020-09-12 11:40:30 +02:00
Travis Wilson
a2e5ce2418 Make experimental capture work on Windows with read-write temp file behavior 2020-09-10 20:14:18 +02:00
41 changed files with 1080 additions and 414 deletions

View File

@@ -3,8 +3,15 @@ load("@rules_cc//cc:defs.bzl", "cc_library")
# Header-only rule to export catch2/catch.hpp.
cc_library(
name = "catch2",
hdrs = ["single_include/catch2/catch.hpp"],
visibility = ["//visibility:public"],
includes = ["single_include/"],
name = "catch2",
hdrs = ["single_include/catch2/catch.hpp"],
includes = ["single_include/"],
visibility = ["//visibility:public"],
)
cc_library(
name = "catch2_with_main",
srcs = ["src/catch_with_main.cpp"],
visibility = ["//visibility:public"],
deps = ["//:catch2"],
)

View File

@@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.5)
# disable testsuite in that case
if(NOT DEFINED PROJECT_NAME)
set(NOT_SUBPROJECT ON)
else()
set(NOT_SUBPROJECT OFF)
endif()
# Catch2's build breaks if done in-tree. You probably should not build
@@ -14,7 +16,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2 LANGUAGES CXX VERSION 2.13.1)
project(Catch2 LANGUAGES CXX VERSION 2.13.6)
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
@@ -25,12 +27,12 @@ option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF)
option(CATCH_BUILD_STATIC_LIBRARY "Builds static library from the main implementation. EXPERIMENTAL" OFF)
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
# define some folders
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
@@ -103,6 +105,19 @@ endif()
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2)
# Hacky support for compiling the impl into a static lib
if (CATCH_BUILD_STATIC_LIBRARY)
add_library(Catch2WithMain ${CMAKE_CURRENT_LIST_DIR}/src/catch_with_main.cpp)
target_link_libraries(Catch2WithMain PUBLIC Catch2)
add_library(Catch2::Catch2WithMain ALIAS Catch2WithMain)
# Make the build reproducible on versions of g++ and clang that supports -ffile-prefix-map
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 8) OR
("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 10))
target_compile_options(Catch2WithMain PRIVATE "-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.")
endif()
endif(CATCH_BUILD_STATIC_LIBRARY)
# Only perform the installation steps when Catch is not being used as
# a subproject via `add_subdirectory`, or the destinations will break,
# see https://github.com/catchorg/Catch2/issues/1373
@@ -117,11 +132,17 @@ if (NOT_SUBPROJECT)
${CATCH_CMAKE_CONFIG_DESTINATION}
)
# Workaround lack of generator expressions in install(TARGETS
set(InstallationTargets Catch2)
if (TARGET Catch2WithMain)
list(APPEND InstallationTargets Catch2WithMain)
endif()
# create and install an export set for catch target as Catch2::Catch
install(
TARGETS
Catch2
${InstallationTargets}
EXPORT
Catch2Targets
DESTINATION

View File

@@ -2,14 +2,14 @@
![catch logo](artwork/catch2-logo-small.png)
[![Github Releases](https://img.shields.io/github/release/catchorg/catch2.svg)](https://github.com/catchorg/catch2/releases)
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
[![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=v2.x)](https://travis-ci.org/catchorg/Catch2)
[![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![codecov](https://codecov.io/gh/catchorg/Catch2/branch/v2.x/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/6JUH8Eybx4CtvkJS)
[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
<a href="https://github.com/catchorg/Catch2/releases/download/v2.13.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
<a href="https://github.com/catchorg/Catch2/releases/download/v2.13.6/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released!

View File

@@ -19,7 +19,7 @@ coverage:
codecov:
branch: master
branch: v2.x
comment:
layout: "diff"

View File

@@ -10,7 +10,7 @@ class CatchConan(ConanFile):
homepage = url
license = "BSL-1.0"
exports = "LICENSE.txt"
exports_sources = ("single_include/*", "CMakeLists.txt", "CMake/*", "contrib/*")
exports_sources = ("single_include/*", "CMakeLists.txt", "CMake/*", "contrib/*", "src/*")
generators = "cmake"
def package(self):

View File

@@ -33,6 +33,10 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
[REPORTER reporter]
[OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix}
[OUTPUT_SUFFIX suffix]
)
``catch_discover_tests`` sets up a post-build command on the test executable
@@ -90,6 +94,28 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
``REPORTER reporter``
Use the specified reporter when running the test case. The reporter will
be passed to the Catch executable as ``--reporter reporter``.
``OUTPUT_DIR dir``
If specified, the parameter is passed along as
``--out dir/<test_name>`` to Catch executable. The actual file name is the
same as the test name. This should be used instead of
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
when using parallel test execution.
``OUTPUT_PREFIX prefix``
May be used in conjunction with ``OUTPUT_DIR``.
If specified, ``prefix`` is added to each output file name, like so
``--out dir/prefix<test_name>``.
``OUTPUT_SUFFIX suffix``
May be used in conjunction with ``OUTPUT_DIR``.
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
the output e.g. ".xml".
#]=======================================================================]
#------------------------------------------------------------------------------
@@ -97,7 +123,7 @@ function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
@@ -110,7 +136,7 @@ function(catch_discover_tests TARGET)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
@@ -134,6 +160,10 @@ function(catch_discover_tests TARGET)
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "TEST_REPORTER=${_REPORTER}"
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
@@ -172,4 +202,5 @@ endfunction()
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
)

View File

@@ -6,13 +6,20 @@ 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(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
math(EXPR _last_arg ${ARGC}-1)
foreach(_n RANGE 1 ${_last_arg})
set(_arg "${ARGV${_n}}")
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
@@ -32,6 +39,7 @@ execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
@@ -48,6 +56,44 @@ endif()
string(REPLACE "\n" ";" output "${output}")
# Run test executable to get list of available reporters
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters
OUTPUT_VARIABLE reporters_output
RESULT_VARIABLE reporters_result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
if(${reporters_result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no reporters!\n"
)
elseif(${reporters_result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${reporters_result}\n"
" Output: ${reporters_output}\n"
)
endif()
string(FIND "${reporters_output}" "${reporter}" reporter_is_valid)
if(reporter AND ${reporter_is_valid} EQUAL -1)
message(FATAL_ERROR
"\"${reporter}\" is not a valid reporter!\n"
)
endif()
# Prepare reporter
if(reporter)
set(reporter_arg "--reporter ${reporter}")
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})
file(MAKE_DIRECTORY ${output_dir})
endif()
endif()
# Parse output
foreach(line ${output})
set(test ${line})
@@ -56,6 +102,12 @@ foreach(line ${output})
foreach(char , [ ])
string(REPLACE ${char} "\\${char}" test_name ${test_name})
endforeach(char)
# ...add output dir
if(output_dir)
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}")
endif()
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
@@ -63,6 +115,8 @@ foreach(line ${output})
"${TEST_EXECUTABLE}"
"${test_name}"
${extra_args}
"${reporter_arg}"
"${output_dir_arg}"
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"

View File

@@ -1,9 +1,11 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - TEMPLATE_TEST_CASE #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_TEMPLATE_TEST_CASE #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
@@ -106,7 +108,8 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
ParseAndAddCatchTests_RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
# https://regex101.com/r/JygOND/1
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \t\n]*\{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
@@ -117,13 +120,21 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
)
endif()
# check CMP0110 policy for new add_test() behavior
if(POLICY CMP0110)
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
else()
# just to be thorough explicitly set the variable
set(_cmp0110_value)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
@@ -189,11 +200,21 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary,
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18")
# And properly introduced in 3.19 with the CMP0110 policy
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
else()
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
set(CTestName "\"${CTestName}\"")
endif()
# Handle template test cases
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
set(Name "${Name} - *")
endif()
# Add the test and set its properties
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
@@ -220,6 +241,7 @@ endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")

View File

@@ -36,6 +36,20 @@ add_subdirectory(lib/Catch2)
target_link_libraries(tests Catch2::Catch2)
```
Another possibility is to use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):
```cmake
Include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.13.1)
FetchContent_MakeAvailable(Catch2)
target_link_libraries(tests Catch2::Catch2)
```
## Automatic test registration
Catch2's repository also contains two CMake scripts that help users
@@ -43,7 +57,7 @@ with automatically registering their `TEST_CASE`s with CTest. They
can be found in the `contrib` folder, and are
1) `Catch.cmake` (and its dependency `CatchAddTests.cmake`)
2) `ParseAndAddCatchTests.cmake`
2) `ParseAndAddCatchTests.cmake` (deprecated)
If Catch2 has been installed in system, both of these can be used after
doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
@@ -83,6 +97,10 @@ catch_discover_tests(target
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
[REPORTER reporter]
[OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix]
[OUTPUT_SUFFIX suffix]
)
```
@@ -129,13 +147,46 @@ default `<target>_TESTS`. This can be useful when the same test
executable is being used in multiple calls to `catch_discover_tests()`.
Note that this variable is only available in CTest.
* `REPORTER reporter`
Use the specified reporter when running the test case. The reporter will
be passed to the test runner as `--reporter reporter`.
* `OUTPUT_DIR dir`
If specified, the parameter is passed along as
`--out dir/<test_name>` to test executable. The actual file name is the
same as the test name. This should be used instead of
`EXTRA_ARGS --out foo` to avoid race conditions writing the result output
when using parallel test execution.
* `OUTPUT_PREFIX prefix`
May be used in conjunction with `OUTPUT_DIR`.
If specified, `prefix` is added to each output file name, like so
`--out dir/prefix<test_name>`.
* `OUTPUT_SUFFIX suffix`
May be used in conjunction with `OUTPUT_DIR`.
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
the output file name e.g. ".xml".
### `ParseAndAddCatchTests.cmake`
⚠ This script is [deprecated](https://github.com/catchorg/Catch2/pull/2120)
in Catch 2.13.4 and superseded by the above approach using `catch_discover_tests`.
See [#2092](https://github.com/catchorg/Catch2/issues/2092) for details.
`ParseAndAddCatchTests` works by parsing all implementation files
associated with the provided target, and registering them via CTest's
`add_test`. This approach has some limitations, such as the fact that
commented-out tests will be registered anyway.
commented-out tests will be registered anyway. More serious, only a
subset of the assertion macros currently available in Catch can be
detected by this script and tests with any macros that cannot be
parsed are *silently ignored*.
#### Usage

View File

@@ -21,12 +21,12 @@ to the codebase itself.
## Using Git(Hub)
Ongoing development happens in the `master` branch for Catch2 v2, and in
`dev-v3` for the next major version, v3.
Ongoing development happens in the `v2.x` branch for Catch2 v2, and in
`devel` for the next major version, v3.
Commits should be small and atomic. A commit is atomic when, after it is
applied, the codebase, tests and all, still works as expected. Small
commits are also prefered, as they make later operations with git history,
commits are also preferred, as they make later operations with git history,
whether it is bisecting, reverting, or something else, easier.
_When submitting a pull request please do not include changes to the

View File

@@ -72,6 +72,13 @@ Instead you will have to write this:
REQUIRE_THAT(foo(), m1 || m2 || m3);
```
### `ParseAndAddCatchTests.cmake`
The CMake/CTest integration using `ParseAndAddCatchTests.cmake` is deprecated,
as it can be replaced by `Catch.cmake` that provides the function
`catch_discover_tests` to get tests directly from a CMake target via the
command line interface instead of parsing C++ code with regular expressions.
## Planned changes

View File

@@ -42,7 +42,7 @@ that allows users to implement their own generators.
effects. The simplest usage is shown below, where the `SECTION` "one"
runs 4 (2\*2) times, and `SECTION` "two" is run 6 times (2\*3).
```
```cpp
TEST_CASE("Generators") {
auto i = GENERATE(1, 2);
SECTION("one") {
@@ -51,7 +51,7 @@ TEST_CASE("Generators") {
}
SECTION("two") {
auto k = GENERATE(4, 5, 6);
REQUIRE(j != k);
REQUIRE(i != k);
}
}
```

View File

@@ -94,6 +94,9 @@ A thread-safe header-only mocking framework for C++14.
## Applications & Tools
### [App Mesh](https://github.com/laoshanxi/app-mesh)
A high available cloud native micro-service application management platform implemented by modern C++.
### [ArangoDB](https://github.com/arangodb/arangodb)
ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values.

View File

@@ -2,6 +2,11 @@
# Release notes
**Contents**<br>
[2.13.6](#2136)<br>
[2.13.5](#2135)<br>
[2.13.4](#2134)<br>
[2.13.3](#2133)<br>
[2.13.2](#2132)<br>
[2.13.1](#2131)<br>
[2.13.0](#2130)<br>
[2.12.4](#2124)<br>
@@ -42,6 +47,82 @@
[Even Older versions](#even-older-versions)<br>
## 2.13.6
### Fixes
* Disabling all signal handlers no longer breaks compilation (#2212, #2213)
### Miscellaneous
* `catch_discover_tests` should handle escaped semicolon (`;`) better (#2214, #2215)
## 2.13.5
### Improvements
* Detection of MAC and IPHONE platforms has been improved (#2140, #2157)
* Added workaround for bug in XLC 16.1.0.1 (#2155)
* Add detection for LCC when it is masquerading as GCC (#2199)
* Modified posix signal handling so it supports newer libcs (#2178)
* `MINSIGSTKSZ` was no longer usable in constexpr context.
### Fixes
* Fixed compilation of benchmarking when `min` and `max` macros are defined (#2159)
* Including `windows.h` without `NOMINMAX` remains a really bad idea, don't do it
### Miscellaneous
* `Catch2WithMain` target (static library) is no longer built by default (#2142)
* Building it by default was at best unnecessary overhead for people not using it, and at worst it caused trouble with install paths
* To have it built, set CMake option `CATCH_BUILD_STATIC_LIBRARY` to `ON`
* The check whether Catch2 is being built as a subproject is now more reliable (#2202, #2204)
* The problem was that if the variable name used internally was defined the project including Catch2 as subproject, it would not be properly overwritten for Catch2's CMake.
## 2.13.4
### Improvements
* Improved the hashing algorithm used for shuffling test cases (#2070)
* `TEST_CASE`s that differ only in the last character should be properly shuffled
* Note that this means that v2.13.4 gives you a different order of test cases than 2.13.3, even given the same seed.
### Miscellaneous
* Deprecated `ParseAndAddCatchTests` CMake integration (#2092)
* It is impossible to implement it properly for all the different test case variants Catch2 provides, and there are better options provided.
* Use `catch_discover_tests` instead, which uses runtime information about available tests.
* Fixed bug in `catch_discover_tests` that would cause it to fail when used in specific project structures (#2119)
* Added Bazel build file
* Added an experimental static library target to CMake
## 2.13.3
### Fixes
* Fixed possible infinite loop when combining generators with section filter (`-c` option) (#2025)
### Miscellaneous
* Fixed `ParseAndAddCatchTests` not finding `TEST_CASE`s without tags (#2055, #2056)
* `ParseAndAddCatchTests` supports `CMP0110` policy for changing behaviour of `add_test` (#2057)
* This was the shortlived change in CMake 3.18.0 that temporarily broke `ParseAndAddCatchTests`
## 2.13.2
### Improvements
* Implemented workaround for AppleClang shadowing bug (#2030)
* Implemented workaround for NVCC ICE (#2005, #2027)
### Fixes
* Fixed detection of `std::uncaught_exceptions` support under non-msvc platforms (#2021)
* Fixed the experimental stdout/stderr capture under Windows (#2013)
### Miscellaneous
* `catch_discover_tests` has been improved significantly (#2023, #2039)
* You can now specify which reporter should be used
* You can now modify where the output will be written
* `WORKING_DIRECTORY` setting is respected
* `ParseAndAddCatchTests` now supports `TEMPLATE_TEST_CASE` macros (#2031)
* Various documentation fixes and improvements (#2022, #2028, #2034)
## 2.13.1
### Improvements
@@ -646,7 +727,7 @@ than `single_include/catch.hpp`.**
* CLR objects (`T^`) can now be stringified (#1216)
* This affects code compiled as C++/CLI
* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236)
* See [documentation for details](https://github.com/catchorg/Catch2/blob/master/docs/matchers.md)
* See [documentation for details](https://github.com/catchorg/Catch2/blob/v2.x/docs/matchers.md)
### Others
* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
@@ -674,7 +755,7 @@ than `single_include/catch.hpp`.**
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
* Use as `-w NoTests`
* Added provisional support for Emscripten (#1114)
* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/master/docs/configuration.md#fallback-stringifier) (#1024)
* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/v2.x/docs/configuration.md#fallback-stringifier) (#1024)
* This allows project's own stringification machinery to be easily reused for Catch
* `Catch::Session::run()` now accepts `char const * const *`, allowing it to accept array of string literals (#1031, #1178)
* The embedded version of Clara was bumped to v1.1.3

View File

@@ -5,6 +5,7 @@
[Short answer](#short-answer)<br>
[Long answer](#long-answer)<br>
[Practical example](#practical-example)<br>
[Using the static library Catch2WithMain](#using-the-static-library-catch2withmain)<br>
[Other possible solutions](#other-possible-solutions)<br>
Several people have reported that test code written with Catch takes much longer to compile than they would expect. Why is that?
@@ -64,6 +65,39 @@ tests-factorial.cpp:11: failed: Factorial(0) == 1 for: 0 == 1
Failed 1 test case, failed 1 assertion.
```
## Using the static library Catch2WithMain
Catch2 also provides a static library that implements the runner. Note
that this support is experimental, due to interactions between Catch2 v2
implementation and C++ linking limitations.
As with the `Catch2` target, the `Catch2WithMain` CMake target can be used
either from a subdirectory, or from installed build.
### CMake
```cmake
add_executable(tests-factorial tests-factorial.cpp)
target_link_libraries(tests-factorial Catch2::Catch2WithMain)
```
### bazel
```python
cc_test(
name = "hello_world_test",
srcs = [
"test/hello_world_test.cpp",
],
deps = [
"lib_hello_world",
"@catch2//:catch2_with_main",
],
)
```
## Other possible solutions
You can also opt to sacrifice some features in order to speed-up Catch's compilation times. For details see the [documentation on Catch's compile-time configuration](configuration.md#other-toggles).

View File

@@ -13,7 +13,7 @@
## Getting Catch2
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
Alternative ways of getting Catch2 include using your system package
manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).

View File

@@ -43,7 +43,7 @@ TEST_CASE("Table allows pre-computed test inputs and outputs", "[example][genera
/* 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
* https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
*

View File

@@ -11,7 +11,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 1
#define CATCH_VERSION_PATCH 6
#ifdef __clang__
# pragma clang system_header

View File

@@ -68,7 +68,9 @@ namespace Catch {
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_limit = (std::min)(
resolution * clock_cost_estimation_tick_limit,
FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_clock = [](int k) {
return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) {

View File

@@ -152,7 +152,7 @@ namespace Catch {
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 sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
@@ -171,7 +171,7 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2);
};
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
}

View File

@@ -138,8 +138,8 @@ namespace Catch {
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
auto lo = std::max(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1);
auto lo = (std::max)(cumn(a1), 0);
auto hi = (std::min)(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level };
}

View File

@@ -39,13 +39,9 @@
#endif
#if defined(__cpp_lib_uncaught_exceptions)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
// We have to avoid both ICC and Clang, because they try to mask themselves
// as gcc, and we want only GCC in this block
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -69,7 +65,7 @@
// ```
//
// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
# if !defined(__ibmxl__)
# if !defined(__ibmxl__) && !defined(__CUDACC__)
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
# endif
@@ -153,9 +149,6 @@
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
# endif
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
@@ -287,10 +280,6 @@
# define CATCH_CONFIG_CPP17_OPTIONAL
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
# define CATCH_CONFIG_CPP17_STRING_VIEW
#endif

View File

@@ -0,0 +1,44 @@
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
/** \file
* Wrapper for UNCAUGHT_EXCEPTIONS configuration option
*
* For some functionality, Catch2 requires to know whether there is
* an active exception. Because `std::uncaught_exception` is deprecated
* in C++17, we want to use `std::uncaught_exceptions` if possible.
*/
#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
#if defined(_MSC_VER)
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
# endif
#endif
#include <exception>
#if defined(__cpp_lib_uncaught_exceptions) \
&& !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif // __cpp_lib_uncaught_exceptions
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
&& !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
&& !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP

View File

@@ -22,7 +22,7 @@ namespace Catch {
// Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":"
// Find last occurrence of ":"
size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start;

View File

@@ -7,30 +7,72 @@
*
*/
/** \file
* This file provides platform specific implementations of FatalConditionHandler
*
* This means that there is a lot of conditional compilation, and platform
* specific code. Currently, Catch2 supports a dummy handler (if no
* handler is desired), and 2 platform specific handlers:
* * Windows' SEH
* * POSIX signals
*
* Consequently, various pieces of code below are compiled if either of
* the platform specific handlers is enabled, or if none of them are
* enabled. It is assumed that both cannot be enabled at the same time,
* and doing so should cause a compilation error.
*
* If another platform specific handler is added, the compile guards
* below will need to be updated taking these assumptions into account.
*/
#include "catch_fatal_condition.h"
#include "catch_context.h"
#include "catch_interfaces_capture.h"
#include "catch_enforce.h"
#include "catch_run_context.h"
#include "catch_windows_h_proxy.h"
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#include <algorithm>
#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace Catch {
// If neither SEH nor signal handling is required, the handler impls
// do not have to do anything, and can be empty.
void FatalConditionHandler::engage_platform() {}
void FatalConditionHandler::disengage_platform() {}
FatalConditionHandler::FatalConditionHandler() = default;
FatalConditionHandler::~FatalConditionHandler() = default;
} // end namespace Catch
#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
// Report the error condition
//! Signals fatal error message to the run context
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
}
#endif // signals/SEH handling
//! Minimal size Catch2 needs for its own fatal error handling.
//! Picked anecdotally, so it might not be sufficient on all
//! platforms, and for all configurations.
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
} // end unnamed namespace
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
@@ -43,7 +85,7 @@ namespace Catch {
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
};
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
@@ -54,39 +96,52 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
// Since we do not support multiple instantiations, we put these
// into global variables and rely on cleaning them up in outlined
// constructors/destructors
static PVOID exceptionHandlerHandle = nullptr;
void FatalConditionHandler::reset() {
if (isSet) {
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
isSet = false;
// For MSVC, we reserve part of the stack memory for handling
// memory overflow structured exception.
FatalConditionHandler::FatalConditionHandler() {
ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
if (!SetThreadStackGuarantee(&guaranteeSize)) {
// We do not want to fully error out, because needing
// the stack reserve should be rare enough anyway.
Catch::cerr()
<< "Failed to reserve piece of stack."
<< " Stack overflows will not be reported successfully.";
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
// We do not attempt to unset the stack guarantee, because
// Windows does not support lowering the stack size guarantee.
FatalConditionHandler::~FatalConditionHandler() = default;
void FatalConditionHandler::engage_platform() {
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
if (!exceptionHandlerHandle) {
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
}
}
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
void FatalConditionHandler::disengage_platform() {
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
exceptionHandlerHandle = nullptr;
}
} // end namespace Catch
} // namespace Catch
#endif // CATCH_CONFIG_WINDOWS_SEH
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
@@ -94,10 +149,6 @@ namespace Catch {
int id;
const char* name;
};
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@@ -108,8 +159,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
// which is zero initialization, but not explicit. We want to avoid
// that.
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
void FatalConditionHandler::handleSignal( int sig ) {
static char* altStackMem = nullptr;
static std::size_t altStackSize = 0;
static stack_t oldSigStack{};
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
static void restorePreviousSignalHandlers() {
// We set signal handlers back to the previous ones. Hopefully
// nobody overwrote them in the meantime, and doesn't expect
// their signal handlers to live past ours given that they
// installed them after ours..
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
}
static void handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
@@ -117,16 +192,33 @@ namespace Catch {
break;
}
}
reset();
reportFatal(name);
// We need to restore previous signal handlers and let them do
// their thing, so that the users can have the debugger break
// when a signal is raised, and so on.
restorePreviousSignalHandlers();
reportFatal( name );
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
if (altStackSize == 0) {
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
}
altStackMem = new char[altStackSize]();
}
FatalConditionHandler::~FatalConditionHandler() {
delete[] altStackMem;
// We signal that another instance can be constructed by zeroing
// out the pointer.
altStackMem = nullptr;
}
void FatalConditionHandler::engage_platform() {
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = sigStackSize;
sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
@@ -138,39 +230,15 @@ namespace Catch {
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
void FatalConditionHandler::reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
isSet = false;
}
}
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[sigStackSize] = {};
} // namespace Catch
#else
namespace Catch {
void FatalConditionHandler::reset() {}
}
#endif // signals/SEH handling
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
void FatalConditionHandler::disengage_platform() {
restorePreviousSignalHandlers();
}
} // end namespace Catch
#endif // CATCH_CONFIG_POSIX_SIGNALS

View File

@@ -11,59 +11,58 @@
#include "catch_platform.h"
#include "catch_compiler_capabilities.h"
#include "catch_windows_h_proxy.h"
#if defined( CATCH_CONFIG_WINDOWS_SEH )
#include <cassert>
namespace Catch {
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
FatalConditionHandler();
static void reset();
~FatalConditionHandler();
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
} // namespace Catch
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];
static stack_t oldSigStack;
static char altStackMem[];
static void handleSignal( int sig );
// Wrapper for platform-specific fatal error (signals/SEH) handlers
//
// Tries to be cooperative with other handlers, and not step over
// other handlers. This means that unknown structured exceptions
// are passed on, previous signal handlers are called, and so on.
//
// Can only be instantiated once, and assumes that once a signal
// is caught, the binary will end up terminating. Thus, there
class FatalConditionHandler {
bool m_started = false;
// Install/disengage implementation for specific platform.
// Should be if-defed to work on current platform, can assume
// engage-disengage 1:1 pairing.
void engage_platform();
void disengage_platform();
public:
// Should also have platform-specific implementations as needed
FatalConditionHandler();
~FatalConditionHandler();
static void reset();
void engage() {
assert(!m_started && "Handler cannot be installed twice.");
m_started = true;
engage_platform();
}
void disengage() {
assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false;
disengage_platform();
}
};
} // namespace Catch
#else
namespace Catch {
struct FatalConditionHandler {
void reset();
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
class FatalConditionHandlerGuard {
FatalConditionHandler* m_handler;
public:
FatalConditionHandlerGuard(FatalConditionHandler* handler):
m_handler(handler) {
m_handler->engage();
}
~FatalConditionHandlerGuard() {
m_handler->disengage();
}
};
}
#endif
} // end namespace Catch
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED

View File

@@ -55,7 +55,8 @@ namespace {
return lhs == rhs;
}
auto ulpDiff = std::abs(lc - rc);
// static cast as a workaround for IBM XLC
auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
@@ -234,4 +235,3 @@ Floating::WithinRelMatcher WithinRel(float target) {
} // namespace Matchers
} // namespace Catch

View File

@@ -66,7 +66,7 @@ namespace Catch {
if (tmpnam_s(m_buffer)) {
CATCH_RUNTIME_ERROR("Could not get a temp filename");
}
if (fopen_s(&m_file, m_buffer, "w")) {
if (fopen_s(&m_file, m_buffer, "w+")) {
char buffer[100];
if (strerror_s(buffer, errno)) {
CATCH_RUNTIME_ERROR("Could not translate errno to a string");

View File

@@ -9,13 +9,16 @@
#ifndef TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
// See e.g.:
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
# endif
# include <TargetConditionals.h>
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
(defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
# define CATCH_PLATFORM_MAC
# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
# define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX

View File

@@ -71,13 +71,53 @@ namespace Catch {
// `SECTION`s.
// **The check for m_children.empty cannot be removed**.
// doing so would break `GENERATE` _not_ followed by `SECTION`s.
const bool should_wait_for_child =
!m_children.empty() &&
std::find_if( m_children.begin(),
m_children.end(),
[]( TestCaseTracking::ITrackerPtr tracker ) {
return tracker->hasStarted();
} ) == m_children.end();
const bool should_wait_for_child = [&]() {
// No children -> nobody to wait for
if ( m_children.empty() ) {
return false;
}
// If at least one child started executing, don't wait
if ( std::find_if(
m_children.begin(),
m_children.end(),
[]( TestCaseTracking::ITrackerPtr tracker ) {
return tracker->hasStarted();
} ) != m_children.end() ) {
return false;
}
// No children have started. We need to check if they _can_
// start, and thus we should wait for them, or they cannot
// start (due to filters), and we shouldn't wait for them
auto* parent = m_parent;
// This is safe: there is always at least one section
// tracker in a test case tracking tree
while ( !parent->isSectionTracker() ) {
parent = &( parent->parent() );
}
assert( parent &&
"Missing root (test case) level section" );
auto const& parentSection =
static_cast<SectionTracker&>( *parent );
auto const& filters = parentSection.getFilters();
// No filters -> no restrictions on running sections
if ( filters.empty() ) {
return true;
}
for ( auto const& child : m_children ) {
if ( child->isSectionTracker() &&
std::find( filters.begin(),
filters.end(),
static_cast<SectionTracker&>( *child )
.trimmedName() ) !=
filters.end() ) {
return true;
}
}
return false;
}();
// This check is a bit tricky, because m_generator->next()
// has a side-effect, where it consumes generator's current
@@ -412,9 +452,8 @@ namespace Catch {
}
void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {

View File

@@ -146,6 +146,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;

View File

@@ -22,24 +22,28 @@ namespace Catch {
namespace {
struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng) {
basis = rng();
basis <<= 32;
basis |= rng();
}
using hash_t = uint64_t;
uint64_t basis;
explicit TestHasher( hash_t hashSuffix ):
m_hashSuffix{ hashSuffix } {}
uint64_t operator()(TestCase const& t) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for (const char c : t.name) {
uint32_t operator()( TestCase const& t ) const {
// FNV-1a hash with multiplication fold.
const hash_t prime = 1099511628211u;
hash_t hash = 14695981039346656037u;
for ( const char c : t.name ) {
hash ^= c;
hash *= prime;
}
return hash;
hash ^= m_hashSuffix;
hash *= prime;
const uint32_t low{ static_cast<uint32_t>( hash ) };
const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
return low * high;
}
private:
hash_t m_hashSuffix;
};
} // end unnamed namespace
@@ -58,9 +62,9 @@ namespace Catch {
case RunTests::InRandomOrder: {
seedRng( config );
TestHasher h( rng() );
TestHasher h{ config.rngSeed() };
using hashedTest = std::pair<uint64_t, TestCase const*>;
using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() );

View File

@@ -233,6 +233,14 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
std::vector<std::string> const& SectionTracker::getFilters() const {
return m_filters;
}
std::string const& SectionTracker::trimmedName() const {
return m_trimmed_name;
}
} // namespace TestCaseTracking
using TestCaseTracking::ITracker;

View File

@@ -163,6 +163,10 @@ namespace TestCaseTracking {
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<std::string> const& filters );
//! Returns filters active in this tracker
std::vector<std::string> const& getFilters() const;
//! Returns whitespace-trimmed name of the tracked section
std::string const& trimmedName() const;
};
} // namespace TestCaseTracking

View File

@@ -8,6 +8,8 @@
#include "catch_compiler_capabilities.h"
#include "catch_uncaught_exceptions.h"
#include "catch_config_uncaught_exceptions.hpp"
#include <exception>
namespace Catch {

View File

@@ -37,7 +37,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 13, 1, "", 0 );
static Version version( 2, 13, 6, "", 0 );
return version;
}

View File

@@ -124,6 +124,7 @@ set(INTERNAL_HEADERS
${HEADER_DIR}/internal/catch_common.h
${HEADER_DIR}/internal/catch_compiler_capabilities.h
${HEADER_DIR}/internal/catch_config.hpp
${HEADER_DIR}/internal/catch_config_uncaught_exceptions.hpp
${HEADER_DIR}/internal/catch_console_colour.h
${HEADER_DIR}/internal/catch_context.h
${HEADER_DIR}/internal/catch_debug_console.h
@@ -418,6 +419,33 @@ set_tests_properties(FilteredSection-1 PROPERTIES FAIL_REGULAR_EXPRESSION "No te
add_test(NAME FilteredSection-2 COMMAND $<TARGET_FILE:SelfTest> \#1394\ nested -c NestedRunSection -c s1)
set_tests_properties(FilteredSection-2 PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran")
add_test(
NAME
FilteredSection::GeneratorsDontCauseInfiniteLoop-1
COMMAND
$<TARGET_FILE:SelfTest> "#2025: original repro" -c "fov_0"
)
set_tests_properties(FilteredSection::GeneratorsDontCauseInfiniteLoop-1
PROPERTIES
PASS_REGULAR_EXPRESSION "inside with fov: 0" # This should happen
FAIL_REGULAR_EXPRESSION "inside with fov: 1" # This would mean there was no filtering
)
# GENERATE between filtered sections (both are selected)
add_test(
NAME
FilteredSection::GeneratorsDontCauseInfiniteLoop-2
COMMAND
$<TARGET_FILE:SelfTest> "#2025: same-level sections"
-c "A"
-c "B"
)
set_tests_properties(FilteredSection::GeneratorsDontCauseInfiniteLoop-2
PROPERTIES
PASS_REGULAR_EXPRESSION "All tests passed \\(4 assertions in 1 test case\\)"
)
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
add_test(NAME ApprovalTests COMMAND ${PYTHON_EXECUTABLE} ${CATCH_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")

View File

@@ -402,3 +402,28 @@ TEST_CASE("#1514: stderr/stdout is not captured in tests aborted by an exception
// FAIL aborts the test by throwing a Catch exception
FAIL("1514");
}
TEST_CASE( "#2025: -c shouldn't cause infinite loop", "[sections][generators][regression][.approvals]" ) {
SECTION( "Check cursor from buffer offset" ) {
auto bufPos = GENERATE_REF( range( 0, 44 ) );
WHEN( "Buffer position is " << bufPos ) { REQUIRE( 1 == 1 ); }
}
}
TEST_CASE("#2025: original repro", "[sections][generators][regression][.approvals]") {
auto fov = GENERATE(true, false);
DYNAMIC_SECTION("fov_" << fov) {
std::cout << "inside with fov: " << fov << '\n';
}
}
TEST_CASE("#2025: same-level sections", "[sections][generators][regression][.approvals]") {
SECTION("A") {
SUCCEED();
}
auto i = GENERATE(1, 2, 3);
SECTION("B") {
REQUIRE(i < 4);
}
}

View File

@@ -79,13 +79,15 @@ class Version:
f.write( line + "\n" )
def updateReadmeFile(version):
import updateWandbox
# Wandbox no longer accepts the single-header upload, skip
# import updateWandbox
downloadParser = re.compile( r'<a href=\"https://github.com/catchorg/Catch2/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles()
if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink))
exit(1)
# success, wandboxLink = updateWandbox.uploadFiles()
# if not success:
# print('Error when uploading to wandbox: {}'.format(wandboxLink))
# exit(1)
f = open( readmePath, 'r' )
lines = []
for line in f:
@@ -94,8 +96,8 @@ def updateReadmeFile(version):
f = open( readmePath, 'w' )
for line in lines:
line = downloadParser.sub( r'<a href="https://github.com/catchorg/Catch2/releases/download/v{0}/catch.hpp">'.format(version.getVersionString()) , line)
if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line:
line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
# if '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]' in line:
# line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
f.write( line + "\n" )
@@ -127,8 +129,8 @@ def updateVersionDefine(version):
def updateVersionPlaceholder(filename, version):
with open(filename, 'rb') as file:
lines = file.readlines()
placeholderRegex = re.compile(b' in Catch X.Y.Z')
replacement = ' in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii')
placeholderRegex = re.compile(b'in Catch X.Y.Z')
replacement = 'in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii')
with open(filename, 'wb') as file:
for line in lines:
file.write(placeholderRegex.sub(replacement, line))

View File

@@ -1,9 +1,9 @@
/*
* Catch v2.13.1
* Generated: 2020-09-07 12:12:38.090364
* Catch v2.13.6
* Generated: 2021-04-16 18:23:38.044268
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
* Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,7 +15,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 1
#define CATCH_VERSION_PATCH 6
#ifdef __clang__
# pragma clang system_header
@@ -66,13 +66,16 @@
#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
// See e.g.:
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
# endif
# include <TargetConditionals.h>
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
(defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
# define CATCH_PLATFORM_MAC
# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
# define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
@@ -132,13 +135,9 @@ namespace Catch {
#endif
#if defined(__cpp_lib_uncaught_exceptions)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
// We have to avoid both ICC and Clang, because they try to mask themselves
// as gcc, and we want only GCC in this block
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -162,7 +161,7 @@ namespace Catch {
// ```
//
// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
# if !defined(__ibmxl__)
# if !defined(__ibmxl__) && !defined(__CUDACC__)
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
# endif
@@ -244,10 +243,6 @@ namespace Catch {
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
# endif
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
@@ -376,10 +371,6 @@ namespace Catch {
# define CATCH_CONFIG_CPP17_OPTIONAL
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
# define CATCH_CONFIG_CPP17_STRING_VIEW
#endif
@@ -7066,8 +7057,8 @@ namespace Catch {
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
auto lo = std::max(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1);
auto lo = (std::max)(cumn(a1), 0);
auto hi = (std::min)(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level };
}
@@ -7136,7 +7127,9 @@ namespace Catch {
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_limit = (std::min)(
resolution * clock_cost_estimation_tick_limit,
FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_clock = [](int k) {
return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) {
@@ -7614,6 +7607,10 @@ namespace TestCaseTracking {
void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( std::vector<std::string> const& filters );
//! Returns filters active in this tracker
std::vector<std::string> const& getFilters() const;
//! Returns whitespace-trimmed name of the tracked section
std::string const& trimmedName() const;
};
} // namespace TestCaseTracking
@@ -7779,7 +7776,7 @@ namespace Catch {
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 sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
@@ -7798,7 +7795,7 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2);
};
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
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, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
@@ -7988,86 +7985,58 @@ namespace Catch {
// start catch_fatal_condition.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#if defined( CATCH_CONFIG_WINDOWS_SEH )
#include <cassert>
namespace Catch {
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
FatalConditionHandler();
static void reset();
~FatalConditionHandler();
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
} // namespace Catch
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];
static stack_t oldSigStack;
static char altStackMem[];
static void handleSignal( int sig );
// Wrapper for platform-specific fatal error (signals/SEH) handlers
//
// Tries to be cooperative with other handlers, and not step over
// other handlers. This means that unknown structured exceptions
// are passed on, previous signal handlers are called, and so on.
//
// Can only be instantiated once, and assumes that once a signal
// is caught, the binary will end up terminating. Thus, there
class FatalConditionHandler {
bool m_started = false;
// Install/disengage implementation for specific platform.
// Should be if-defed to work on current platform, can assume
// engage-disengage 1:1 pairing.
void engage_platform();
void disengage_platform();
public:
// Should also have platform-specific implementations as needed
FatalConditionHandler();
~FatalConditionHandler();
static void reset();
void engage() {
assert(!m_started && "Handler cannot be installed twice.");
m_started = true;
engage_platform();
}
void disengage() {
assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false;
disengage_platform();
}
};
} // namespace Catch
#else
namespace Catch {
struct FatalConditionHandler {
void reset();
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
class FatalConditionHandlerGuard {
FatalConditionHandler* m_handler;
public:
FatalConditionHandlerGuard(FatalConditionHandler* handler):
m_handler(handler) {
m_handler->engage();
}
~FatalConditionHandlerGuard() {
m_handler->disengage();
}
};
}
#endif
} // end namespace Catch
// end catch_fatal_condition.h
#include <string>
@@ -8193,6 +8162,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
@@ -10065,6 +10035,36 @@ namespace Catch {
}
// end catch_errno_guard.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#include <sstream>
namespace Catch {
@@ -10581,7 +10581,7 @@ namespace Catch {
// Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":"
// Find last occurrence of ":"
size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start;
@@ -10743,25 +10743,47 @@ namespace Catch {
// end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#include <algorithm>
#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace Catch {
// If neither SEH nor signal handling is required, the handler impls
// do not have to do anything, and can be empty.
void FatalConditionHandler::engage_platform() {}
void FatalConditionHandler::disengage_platform() {}
FatalConditionHandler::FatalConditionHandler() = default;
FatalConditionHandler::~FatalConditionHandler() = default;
} // end namespace Catch
#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
// Report the error condition
//! Signals fatal error message to the run context
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
}
#endif // signals/SEH handling
//! Minimal size Catch2 needs for its own fatal error handling.
//! Picked anecdotally, so it might not be sufficient on all
//! platforms, and for all configurations.
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
} // end unnamed namespace
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
@@ -10774,7 +10796,7 @@ namespace Catch {
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
};
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
@@ -10785,38 +10807,50 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
// Since we do not support multiple instantiations, we put these
// into global variables and rely on cleaning them up in outlined
// constructors/destructors
static PVOID exceptionHandlerHandle = nullptr;
void FatalConditionHandler::reset() {
if (isSet) {
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
isSet = false;
// For MSVC, we reserve part of the stack memory for handling
// memory overflow structured exception.
FatalConditionHandler::FatalConditionHandler() {
ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
if (!SetThreadStackGuarantee(&guaranteeSize)) {
// We do not want to fully error out, because needing
// the stack reserve should be rare enough anyway.
Catch::cerr()
<< "Failed to reserve piece of stack."
<< " Stack overflows will not be reported successfully.";
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
// We do not attempt to unset the stack guarantee, because
// Windows does not support lowering the stack size guarantee.
FatalConditionHandler::~FatalConditionHandler() = default;
void FatalConditionHandler::engage_platform() {
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
if (!exceptionHandlerHandle) {
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
}
}
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
void FatalConditionHandler::disengage_platform() {
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
exceptionHandlerHandle = nullptr;
}
} // namespace Catch
} // end namespace Catch
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
#endif // CATCH_CONFIG_WINDOWS_SEH
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
@@ -10825,10 +10859,6 @@ namespace Catch {
const char* name;
};
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
@@ -10838,7 +10868,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
void FatalConditionHandler::handleSignal( int sig ) {
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
// which is zero initialization, but not explicit. We want to avoid
// that.
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
static char* altStackMem = nullptr;
static std::size_t altStackSize = 0;
static stack_t oldSigStack{};
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
static void restorePreviousSignalHandlers() {
// We set signal handlers back to the previous ones. Hopefully
// nobody overwrote them in the meantime, and doesn't expect
// their signal handlers to live past ours given that they
// installed them after ours..
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
}
static void handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
@@ -10846,16 +10901,33 @@ namespace Catch {
break;
}
}
reset();
reportFatal(name);
// We need to restore previous signal handlers and let them do
// their thing, so that the users can have the debugger break
// when a signal is raised, and so on.
restorePreviousSignalHandlers();
reportFatal( name );
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
if (altStackSize == 0) {
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
}
altStackMem = new char[altStackSize]();
}
FatalConditionHandler::~FatalConditionHandler() {
delete[] altStackMem;
// We signal that another instance can be constructed by zeroing
// out the pointer.
altStackMem = nullptr;
}
void FatalConditionHandler::engage_platform() {
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = sigStackSize;
sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
@@ -10867,40 +10939,17 @@ namespace Catch {
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
void FatalConditionHandler::reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
isSet = false;
}
}
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[sigStackSize] = {};
} // namespace Catch
#else
namespace Catch {
void FatalConditionHandler::reset() {}
}
#endif // signals/SEH handling
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
void FatalConditionHandler::disengage_platform() {
restorePreviousSignalHandlers();
}
} // end namespace Catch
#endif // CATCH_CONFIG_POSIX_SIGNALS
// end catch_fatal_condition.cpp
// start catch_generators.cpp
@@ -11455,7 +11504,8 @@ namespace {
return lhs == rhs;
}
auto ulpDiff = std::abs(lc - rc);
// static cast as a workaround for IBM XLC
auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
@@ -11629,7 +11679,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
} // namespace Matchers
} // namespace Catch
// end catch_matchers_floating.cpp
// start catch_matchers_generic.cpp
@@ -12045,7 +12094,7 @@ namespace Catch {
if (tmpnam_s(m_buffer)) {
CATCH_RUNTIME_ERROR("Could not get a temp filename");
}
if (fopen_s(&m_file, m_buffer, "w")) {
if (fopen_s(&m_file, m_buffer, "w+")) {
char buffer[100];
if (strerror_s(buffer, errno)) {
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
@@ -12583,13 +12632,53 @@ namespace Catch {
// `SECTION`s.
// **The check for m_children.empty cannot be removed**.
// doing so would break `GENERATE` _not_ followed by `SECTION`s.
const bool should_wait_for_child =
!m_children.empty() &&
std::find_if( m_children.begin(),
m_children.end(),
[]( TestCaseTracking::ITrackerPtr tracker ) {
return tracker->hasStarted();
} ) == m_children.end();
const bool should_wait_for_child = [&]() {
// No children -> nobody to wait for
if ( m_children.empty() ) {
return false;
}
// If at least one child started executing, don't wait
if ( std::find_if(
m_children.begin(),
m_children.end(),
[]( TestCaseTracking::ITrackerPtr tracker ) {
return tracker->hasStarted();
} ) != m_children.end() ) {
return false;
}
// No children have started. We need to check if they _can_
// start, and thus we should wait for them, or they cannot
// start (due to filters), and we shouldn't wait for them
auto* parent = m_parent;
// This is safe: there is always at least one section
// tracker in a test case tracking tree
while ( !parent->isSectionTracker() ) {
parent = &( parent->parent() );
}
assert( parent &&
"Missing root (test case) level section" );
auto const& parentSection =
static_cast<SectionTracker&>( *parent );
auto const& filters = parentSection.getFilters();
// No filters -> no restrictions on running sections
if ( filters.empty() ) {
return true;
}
for ( auto const& child : m_children ) {
if ( child->isSectionTracker() &&
std::find( filters.begin(),
filters.end(),
static_cast<SectionTracker&>( *child )
.trimmedName() ) !=
filters.end() ) {
return true;
}
}
return false;
}();
// This check is a bit tricky, because m_generator->next()
// has a side-effect, where it consumes generator's current
@@ -12923,9 +13012,8 @@ namespace Catch {
}
void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {
@@ -14094,24 +14182,28 @@ namespace Catch {
namespace {
struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng) {
basis = rng();
basis <<= 32;
basis |= rng();
}
using hash_t = uint64_t;
uint64_t basis;
explicit TestHasher( hash_t hashSuffix ):
m_hashSuffix{ hashSuffix } {}
uint64_t operator()(TestCase const& t) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for (const char c : t.name) {
uint32_t operator()( TestCase const& t ) const {
// FNV-1a hash with multiplication fold.
const hash_t prime = 1099511628211u;
hash_t hash = 14695981039346656037u;
for ( const char c : t.name ) {
hash ^= c;
hash *= prime;
}
return hash;
hash ^= m_hashSuffix;
hash *= prime;
const uint32_t low{ static_cast<uint32_t>( hash ) };
const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
return low * high;
}
private:
hash_t m_hashSuffix;
};
} // end unnamed namespace
@@ -14129,9 +14221,9 @@ namespace Catch {
case RunTests::InRandomOrder: {
seedRng( config );
TestHasher h( rng() );
TestHasher h{ config.rngSeed() };
using hashedTest = std::pair<uint64_t, TestCase const*>;
using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() );
@@ -14461,6 +14553,14 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
}
std::vector<std::string> const& SectionTracker::getFilters() const {
return m_filters;
}
std::string const& SectionTracker::trimmedName() const {
return m_trimmed_name;
}
} // namespace TestCaseTracking
using TestCaseTracking::ITracker;
@@ -15195,6 +15295,41 @@ namespace Catch {
// end catch_totals.cpp
// start catch_uncaught_exceptions.cpp
// start catch_config_uncaught_exceptions.hpp
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
#if defined(_MSC_VER)
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
# endif
#endif
#include <exception>
#if defined(__cpp_lib_uncaught_exceptions) \
&& !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif // __cpp_lib_uncaught_exceptions
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
&& !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
&& !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
#endif
#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP
// end catch_config_uncaught_exceptions.hpp
#include <exception>
namespace Catch {
@@ -15241,7 +15376,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 13, 1, "", 0 );
static Version version( 2, 13, 6, "", 0 );
return version;
}

2
src/catch_with_main.cpp Normal file
View File

@@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>