Compare commits

..

17 Commits

Author SHA1 Message Date
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
25 changed files with 357 additions and 81 deletions

View File

@@ -3,8 +3,15 @@ load("@rules_cc//cc:defs.bzl", "cc_library")
# Header-only rule to export catch2/catch.hpp. # Header-only rule to export catch2/catch.hpp.
cc_library( cc_library(
name = "catch2", name = "catch2",
hdrs = ["single_include/catch2/catch.hpp"], hdrs = ["single_include/catch2/catch.hpp"],
visibility = ["//visibility:public"], includes = ["single_include/"],
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

@@ -14,7 +14,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif() endif()
project(Catch2 LANGUAGES CXX VERSION 2.13.2) project(Catch2 LANGUAGES CXX VERSION 2.13.4)
# Provide path for scripts # Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
@@ -103,6 +103,12 @@ endif()
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project # provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
add_library(Catch2::Catch2 ALIAS Catch2) add_library(Catch2::Catch2 ALIAS Catch2)
# Hacky support for compiling the impl into a static lib
add_library(Catch2WithMain ${CMAKE_CURRENT_LIST_DIR}/src/catch_with_main.cpp)
target_link_libraries(Catch2WithMain PUBLIC Catch2)
add_library(Catch2::Catch2WithMain ALIAS Catch2WithMain)
# Only perform the installation steps when Catch is not being used as # Only perform the installation steps when Catch is not being used as
# a subproject via `add_subdirectory`, or the destinations will break, # a subproject via `add_subdirectory`, or the destinations will break,
# see https://github.com/catchorg/Catch2/issues/1373 # see https://github.com/catchorg/Catch2/issues/1373
@@ -121,7 +127,7 @@ if (NOT_SUBPROJECT)
# create and install an export set for catch target as Catch2::Catch # create and install an export set for catch target as Catch2::Catch
install( install(
TARGETS TARGETS
Catch2 Catch2 Catch2WithMain
EXPORT EXPORT
Catch2Targets Catch2Targets
DESTINATION DESTINATION

View File

@@ -2,14 +2,14 @@
![catch logo](artwork/catch2-logo-small.png) ![catch logo](artwork/catch2-logo-small.png)
[![Github Releases](https://img.shields.io/github/release/catchorg/catch2.svg)](https://github.com/catchorg/catch2/releases) [![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) [![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) [![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) [![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.2/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.4/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
## Catch2 is released! ## Catch2 is released!

View File

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

View File

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

View File

@@ -202,4 +202,5 @@ endfunction()
set(_CATCH_DISCOVER_TESTS_SCRIPT set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake ${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
) )

View File

@@ -108,7 +108,8 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
ParseAndAddCatchTests_RemoveComments(Contents) ParseAndAddCatchTests_RemoveComments(Contents)
# Find definition of test names # Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*,[ \t\n]*\"[^\"]*\"([^\(\)]+(\\([^\)]*\\))*)*\\)+[ \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) if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property") ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
@@ -119,6 +120,14 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
) )
endif() 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}) foreach(TestName ${Tests})
# Strip newlines # Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}") string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
@@ -193,14 +202,18 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# 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 neccessary,
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1 # 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}\"") set(CTestName "\"${CTestName}\"")
endif() endif()
# Handle template test cases # Handle template test cases
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*") if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
set(Name "${Name} - *") set(Name "${Name} - *")
endif() endif()
# Add the test and set its properties # Add the test and set its properties
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters}) add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
@@ -228,6 +241,7 @@ endfunction()
# entry point # entry point
function(ParseAndAddCatchTests TestTarget) 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}") ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES) get_target_property(SourceFiles ${TestTarget} SOURCES)
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}") ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")

View File

@@ -57,7 +57,7 @@ with automatically registering their `TEST_CASE`s with CTest. They
can be found in the `contrib` folder, and are can be found in the `contrib` folder, and are
1) `Catch.cmake` (and its dependency `CatchAddTests.cmake`) 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 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 doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
@@ -176,10 +176,17 @@ the output file name e.g. ".xml".
### `ParseAndAddCatchTests.cmake` ### `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 `ParseAndAddCatchTests` works by parsing all implementation files
associated with the provided target, and registering them via CTest's associated with the provided target, and registering them via CTest's
`add_test`. This approach has some limitations, such as the fact that `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 #### Usage

View File

@@ -21,8 +21,8 @@ to the codebase itself.
## Using Git(Hub) ## Using Git(Hub)
Ongoing development happens in the `master` branch for Catch2 v2, and in Ongoing development happens in the `v2.x` branch for Catch2 v2, and in
`dev-v3` for the next major version, v3. `devel` for the next major version, v3.
Commits should be small and atomic. A commit is atomic when, after it is 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 applied, the codebase, tests and all, still works as expected. Small

View File

@@ -72,6 +72,13 @@ Instead you will have to write this:
REQUIRE_THAT(foo(), m1 || m2 || m3); 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 ## Planned changes

View File

@@ -94,6 +94,9 @@ A thread-safe header-only mocking framework for C++14.
## Applications & Tools ## 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](https://github.com/arangodb/arangodb)
ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values. ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values.

View File

@@ -2,6 +2,8 @@
# Release notes # Release notes
**Contents**<br> **Contents**<br>
[2.13.4](#2134)<br>
[2.13.3](#2133)<br>
[2.13.2](#2132)<br> [2.13.2](#2132)<br>
[2.13.1](#2131)<br> [2.13.1](#2131)<br>
[2.13.0](#2130)<br> [2.13.0](#2130)<br>
@@ -43,6 +45,33 @@
[Even Older versions](#even-older-versions)<br> [Even Older versions](#even-older-versions)<br>
## 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 ## 2.13.2
### Improvements ### Improvements
@@ -666,7 +695,7 @@ than `single_include/catch.hpp`.**
* CLR objects (`T^`) can now be stringified (#1216) * CLR objects (`T^`) can now be stringified (#1216)
* This affects code compiled as C++/CLI * This affects code compiled as C++/CLI
* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236) * 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 ### Others
* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239) * Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
@@ -694,7 +723,7 @@ than `single_include/catch.hpp`.**
* Added an option to warn (+ exit with error) when no tests were ran (#1158) * Added an option to warn (+ exit with error) when no tests were ran (#1158)
* Use as `-w NoTests` * Use as `-w NoTests`
* Added provisional support for Emscripten (#1114) * 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 * 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) * `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 * The embedded version of Clara was bumped to v1.1.3

View File

@@ -5,6 +5,7 @@
[Short answer](#short-answer)<br> [Short answer](#short-answer)<br>
[Long answer](#long-answer)<br> [Long answer](#long-answer)<br>
[Practical example](#practical-example)<br> [Practical example](#practical-example)<br>
[Using the static library Catch2WithMain](#using-the-static-library-catch2withmain)<br>
[Other possible solutions](#other-possible-solutions)<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? 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. 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 ## 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). 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 ## 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 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). manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).

View File

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

View File

@@ -71,13 +71,53 @@ namespace Catch {
// `SECTION`s. // `SECTION`s.
// **The check for m_children.empty cannot be removed**. // **The check for m_children.empty cannot be removed**.
// doing so would break `GENERATE` _not_ followed by `SECTION`s. // doing so would break `GENERATE` _not_ followed by `SECTION`s.
const bool should_wait_for_child = const bool should_wait_for_child = [&]() {
!m_children.empty() && // No children -> nobody to wait for
std::find_if( m_children.begin(), if ( m_children.empty() ) {
m_children.end(), return false;
[]( TestCaseTracking::ITrackerPtr tracker ) { }
return tracker->hasStarted(); // If at least one child started executing, don't wait
} ) == m_children.end(); 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() // This check is a bit tricky, because m_generator->next()
// has a side-effect, where it consumes generator's current // has a side-effect, where it consumes generator's current

View File

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

View File

@@ -233,6 +233,14 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); 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 } // namespace TestCaseTracking
using TestCaseTracking::ITracker; using TestCaseTracking::ITracker;

View File

@@ -163,6 +163,10 @@ namespace TestCaseTracking {
void addInitialFilters( std::vector<std::string> const& filters ); void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( 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 } // namespace TestCaseTracking

View File

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

View File

@@ -419,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) 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") 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 # 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>) 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") 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 aborts the test by throwing a Catch exception
FAIL("1514"); 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" ) f.write( line + "\n" )
def updateReadmeFile(version): 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\">' ) downloadParser = re.compile( r'<a href=\"https://github.com/catchorg/Catch2/releases/download/v\d+\.\d+\.\d+/catch.hpp\">' )
success, wandboxLink = updateWandbox.uploadFiles() # success, wandboxLink = updateWandbox.uploadFiles()
if not success: # if not success:
print('Error when uploading to wandbox: {}'.format(wandboxLink)) # print('Error when uploading to wandbox: {}'.format(wandboxLink))
exit(1) # exit(1)
f = open( readmePath, 'r' ) f = open( readmePath, 'r' )
lines = [] lines = []
for line in f: for line in f:
@@ -94,8 +96,8 @@ def updateReadmeFile(version):
f = open( readmePath, 'w' ) f = open( readmePath, 'w' )
for line in lines: 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) 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: # 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) # line = '[![Try online](https://img.shields.io/badge/try-online-blue.svg)]({0})'.format(wandboxLink)
f.write( line + "\n" ) f.write( line + "\n" )
@@ -127,8 +129,8 @@ def updateVersionDefine(version):
def updateVersionPlaceholder(filename, version): def updateVersionPlaceholder(filename, version):
with open(filename, 'rb') as file: with open(filename, 'rb') as file:
lines = file.readlines() lines = file.readlines()
placeholderRegex = re.compile(b' in Catch X.Y.Z') placeholderRegex = re.compile(b'in Catch X.Y.Z')
replacement = ' in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii') replacement = 'in Catch {}.{}.{}'.format(version.majorVersion, version.minorVersion, version.patchNumber).encode('ascii')
with open(filename, 'wb') as file: with open(filename, 'wb') as file:
for line in lines: for line in lines:
file.write(placeholderRegex.sub(replacement, line)) file.write(placeholderRegex.sub(replacement, line))

View File

@@ -1,6 +1,6 @@
/* /*
* Catch v2.13.2 * Catch v2.13.4
* Generated: 2020-10-07 11:32:53.302017 * Generated: 2020-12-29 14:48:00.116107
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * 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) 2020 Two Blue Cubes Ltd. All rights reserved.
@@ -15,7 +15,7 @@
#define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 2 #define CATCH_VERSION_PATCH 4
#ifdef __clang__ #ifdef __clang__
# pragma clang system_header # pragma clang system_header
@@ -7602,6 +7602,10 @@ namespace TestCaseTracking {
void addInitialFilters( std::vector<std::string> const& filters ); void addInitialFilters( std::vector<std::string> const& filters );
void addNextFilters( 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 } // namespace TestCaseTracking
@@ -12571,13 +12575,53 @@ namespace Catch {
// `SECTION`s. // `SECTION`s.
// **The check for m_children.empty cannot be removed**. // **The check for m_children.empty cannot be removed**.
// doing so would break `GENERATE` _not_ followed by `SECTION`s. // doing so would break `GENERATE` _not_ followed by `SECTION`s.
const bool should_wait_for_child = const bool should_wait_for_child = [&]() {
!m_children.empty() && // No children -> nobody to wait for
std::find_if( m_children.begin(), if ( m_children.empty() ) {
m_children.end(), return false;
[]( TestCaseTracking::ITrackerPtr tracker ) { }
return tracker->hasStarted(); // If at least one child started executing, don't wait
} ) == m_children.end(); 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() // This check is a bit tricky, because m_generator->next()
// has a side-effect, where it consumes generator's current // has a side-effect, where it consumes generator's current
@@ -14082,24 +14126,28 @@ namespace Catch {
namespace { namespace {
struct TestHasher { struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng_instance) { using hash_t = uint64_t;
basis = rng_instance();
basis <<= 32;
basis |= rng_instance();
}
uint64_t basis; explicit TestHasher( hash_t hashSuffix ):
m_hashSuffix{ hashSuffix } {}
uint64_t operator()(TestCase const& t) const { uint32_t operator()( TestCase const& t ) const {
// Modified FNV-1a hash // FNV-1a hash with multiplication fold.
static constexpr uint64_t prime = 1099511628211; const hash_t prime = 1099511628211u;
uint64_t hash = basis; hash_t hash = 14695981039346656037u;
for (const char c : t.name) { for ( const char c : t.name ) {
hash ^= c; hash ^= c;
hash *= prime; 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 } // end unnamed namespace
@@ -14117,9 +14165,9 @@ namespace Catch {
case RunTests::InRandomOrder: { case RunTests::InRandomOrder: {
seedRng( config ); 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; std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() ); indexed_tests.reserve( unsortedTestCases.size() );
@@ -14449,6 +14497,14 @@ namespace TestCaseTracking {
m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); 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 } // namespace TestCaseTracking
using TestCaseTracking::ITracker; using TestCaseTracking::ITracker;
@@ -15264,7 +15320,7 @@ namespace Catch {
} }
Version const& libraryVersion() { Version const& libraryVersion() {
static Version version( 2, 13, 2, "", 0 ); static Version version( 2, 13, 4, "", 0 );
return version; return version;
} }

2
src/catch_with_main.cpp Normal file
View File

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