mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 08:25:40 +02:00
Compare commits
135 Commits
remove_red
...
v2.13.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fd9f5ac661 | ||
![]() |
f0dc4d9be0 | ||
![]() |
284672cc84 | ||
![]() |
2b34b5c7d0 | ||
![]() |
708487d201 | ||
![]() |
6859c683e0 | ||
![]() |
de3a208e16 | ||
![]() |
229cc4823c | ||
![]() |
7f21cc6c55 | ||
![]() |
4c85248179 | ||
![]() |
b4e2237152 | ||
![]() |
40937b67c7 | ||
![]() |
0d5b131394 | ||
![]() |
ad3b90553b | ||
![]() |
b1c45652e5 | ||
![]() |
b79a83e4aa | ||
![]() |
89fe35d515 | ||
![]() |
115d6a1c40 | ||
![]() |
91576352f9 | ||
![]() |
6f7c191513 | ||
![]() |
4eb9d37e05 | ||
![]() |
53d8af8e96 | ||
![]() |
46fde0c597 | ||
![]() |
de103db696 | ||
![]() |
fedc3a7b7b | ||
![]() |
c299133a31 | ||
![]() |
09b8017ea3 | ||
![]() |
bad3c93049 | ||
![]() |
0f05c034c2 | ||
![]() |
ee4538c0c6 | ||
![]() |
dc7a20fc74 | ||
![]() |
018dc0b74f | ||
![]() |
ad1940f336 | ||
![]() |
5399921622 | ||
![]() |
e815acddf8 | ||
![]() |
e7189f1e4f | ||
![]() |
1806b21545 | ||
![]() |
288416f501 | ||
![]() |
cbbebb65b6 | ||
![]() |
fb08596b1b | ||
![]() |
0614a4acb3 | ||
![]() |
0f12995501 | ||
![]() |
0807fdb175 | ||
![]() |
9500ded83b | ||
![]() |
6c6ebe374a | ||
![]() |
b1b5cb8122 | ||
![]() |
77dc8cfc45 | ||
![]() |
ddc9f4c61d | ||
![]() |
bed47374ce | ||
![]() |
0e9bae1cdb | ||
![]() |
f133277910 | ||
![]() |
f764ee3d30 | ||
![]() |
c190061001 | ||
![]() |
b1dcdc5032 | ||
![]() |
f0e596e252 | ||
![]() |
594cab31ed | ||
![]() |
89f5f84351 | ||
![]() |
2e61d38c7c | ||
![]() |
5c9f09e94a | ||
![]() |
f4fc2dab2c | ||
![]() |
cfb6956698 | ||
![]() |
e59fc2c3b3 | ||
![]() |
4e4171420d | ||
![]() |
37cbf4a4fe | ||
![]() |
38f897c887 | ||
![]() |
fa4a93e051 | ||
![]() |
6fbe5efc71 | ||
![]() |
bad0fb51f8 | ||
![]() |
a2fc7cf8c0 | ||
![]() |
da9e3eec65 | ||
![]() |
f696ab836b | ||
![]() |
5d32ce26f4 | ||
![]() |
035a062596 | ||
![]() |
d399a308d0 | ||
![]() |
b8ce814ee6 | ||
![]() |
6260962108 | ||
![]() |
b4c8967ac5 | ||
![]() |
7900fb3abb | ||
![]() |
01bdfe3312 | ||
![]() |
e5c9a58d66 | ||
![]() |
255aa5f2af | ||
![]() |
3a33315ff8 | ||
![]() |
5f94c8dafb | ||
![]() |
695a356f93 | ||
![]() |
020b655635 | ||
![]() |
5561d0342d | ||
![]() |
3a15315a37 | ||
![]() |
b7b346c3e5 | ||
![]() |
9e09d79946 | ||
![]() |
7048c2c269 | ||
![]() |
6f77d59b16 | ||
![]() |
022b61ff92 | ||
![]() |
87b5bf77bc | ||
![]() |
81d52c4a5f | ||
![]() |
200b8b6fc0 | ||
![]() |
e70fd2a4b9 | ||
![]() |
36170d60ca | ||
![]() |
917e92c162 | ||
![]() |
f54950744f | ||
![]() |
b3b07215d1 | ||
![]() |
2652bb86e3 | ||
![]() |
1715b6b923 | ||
![]() |
f20a9dbc6e | ||
![]() |
273c3f85eb | ||
![]() |
6a3d0dc176 | ||
![]() |
ccb1f70629 | ||
![]() |
4a5bc0f39a | ||
![]() |
f96e89e016 | ||
![]() |
481f54b357 | ||
![]() |
2d172dc688 | ||
![]() |
587a20b312 | ||
![]() |
bff44f8b01 | ||
![]() |
4ea74ff966 | ||
![]() |
d10b9bd02e | ||
![]() |
55794e9b27 | ||
![]() |
fa6211bfc2 | ||
![]() |
4e90f910dc | ||
![]() |
0c59cc83cf | ||
![]() |
e4004e0adb | ||
![]() |
6c9a255dc2 | ||
![]() |
9a8963133f | ||
![]() |
cfba9dce97 | ||
![]() |
a537ccae22 | ||
![]() |
e1c9d5569d | ||
![]() |
d512decaac | ||
![]() |
f23f96883a | ||
![]() |
d7b8c3ace3 | ||
![]() |
32733e08c0 | ||
![]() |
930f49a641 | ||
![]() |
c409dccee5 | ||
![]() |
95bfb33167 | ||
![]() |
59d2d08c0f | ||
![]() |
fa6d52e2a3 | ||
![]() |
5ac348cd6e | ||
![]() |
776a4686c7 |
25
.clang-format
Normal file
25
.clang-format
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
AccessModifierOffset: '-4'
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AllowAllConstructorInitializersOnNextLine: 'true'
|
||||||
|
BinPackArguments: 'false'
|
||||||
|
BinPackParameters: 'false'
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||||
|
DerivePointerAlignment: 'false'
|
||||||
|
FixNamespaceComments: 'true'
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IndentCaseLabels: 'false'
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: '4'
|
||||||
|
Language: Cpp
|
||||||
|
NamespaceIndentation: All
|
||||||
|
PointerAlignment: Left
|
||||||
|
SpaceBeforeCtorInitializerColon: 'false'
|
||||||
|
SpaceInEmptyParentheses: 'false'
|
||||||
|
SpacesInParentheses: 'true'
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
@@ -31,7 +31,7 @@ class BuilderSettings(object):
|
|||||||
not match the stable pattern. Otherwise it will upload to stable
|
not match the stable pattern. Otherwise it will upload to stable
|
||||||
channel.
|
channel.
|
||||||
"""
|
"""
|
||||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/Catch2")
|
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/catch2")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def upload_only_when_stable(self):
|
def upload_only_when_stable(self):
|
||||||
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
|||||||
patreon: horenmar
|
custom: "https://www.paypal.me/horenmar"
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ Build
|
|||||||
cmake-build-*
|
cmake-build-*
|
||||||
benchmark-dir
|
benchmark-dir
|
||||||
.conan/test_package/build
|
.conan/test_package/build
|
||||||
|
bazel-*
|
||||||
|
10
BUILD.bazel
Normal file
10
BUILD.bazel
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Load the cc_library rule.
|
||||||
|
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/"],
|
||||||
|
)
|
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
# detect if Catch is being bundled,
|
# detect if Catch is being bundled,
|
||||||
# disable testsuite in that case
|
# disable testsuite in that case
|
||||||
if(NOT DEFINED PROJECT_NAME)
|
if(NOT DEFINED PROJECT_NAME)
|
||||||
set(NOT_SUBPROJECT ON)
|
set(NOT_SUBPROJECT ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Catch2's build breaks if done in-tree. You probably should not build
|
# Catch2's build breaks if done in-tree. You probably should not build
|
||||||
@@ -14,14 +14,12 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
project(Catch2 LANGUAGES CXX VERSION 2.10.2)
|
project(Catch2 LANGUAGES CXX VERSION 2.13.1)
|
||||||
|
|
||||||
# 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")
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
include(CTest)
|
|
||||||
|
|
||||||
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
|
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
|
||||||
option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
|
option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
|
||||||
@@ -33,8 +31,6 @@ option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
|
|||||||
option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
|
option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
|
||||||
|
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
|
||||||
|
|
||||||
# define some folders
|
# define some folders
|
||||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||||
@@ -45,12 +41,16 @@ if(USE_WMAIN)
|
|||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
if(NOT_SUBPROJECT)
|
||||||
find_package(PythonInterp)
|
include(CTest)
|
||||||
if (NOT PYTHONINTERP_FOUND)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
message(FATAL_ERROR "Python not found, but required for tests")
|
if(BUILD_TESTING AND CATCH_BUILD_TESTING)
|
||||||
|
find_package(PythonInterp)
|
||||||
|
if (NOT PYTHONINTERP_FOUND)
|
||||||
|
message(FATAL_ERROR "Python not found, but required for tests")
|
||||||
|
endif()
|
||||||
|
add_subdirectory(projects)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(projects)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CATCH_BUILD_EXAMPLES)
|
if(CATCH_BUILD_EXAMPLES)
|
||||||
@@ -107,6 +107,7 @@ add_library(Catch2::Catch2 ALIAS Catch2)
|
|||||||
# 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
|
||||||
if (NOT_SUBPROJECT)
|
if (NOT_SUBPROJECT)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||||
|
|
||||||
configure_package_config_file(
|
configure_package_config_file(
|
||||||
|
@@ -5,11 +5,11 @@
|
|||||||
[](https://travis-ci.org/catchorg/Catch2)
|
[](https://travis-ci.org/catchorg/Catch2)
|
||||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||||
[](https://codecov.io/gh/catchorg/Catch2)
|
[](https://codecov.io/gh/catchorg/Catch2)
|
||||||
[](https://wandbox.org/permlink/LzYWgcPrcy9yQmed)
|
[](https://wandbox.org/permlink/6JUH8Eybx4CtvkJS)
|
||||||
[](https://discord.gg/4CWS9zD)
|
[](https://discord.gg/4CWS9zD)
|
||||||
|
|
||||||
|
|
||||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.10.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.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||||
|
|
||||||
## Catch2 is released!
|
## Catch2 is released!
|
||||||
|
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
# version string format -- This will be overwritten later anyway
|
# version string format -- This will be overwritten later anyway
|
||||||
version: "{build}"
|
version: "{build}"
|
||||||
|
|
||||||
|
# We need a more up to date pip because Python 2.7 is EOL soon
|
||||||
|
init:
|
||||||
|
- set PATH=C:\Python35\Scripts;%PATH%
|
||||||
|
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
- /dev-travis.+/
|
- /dev-travis.+/
|
||||||
@@ -62,7 +67,7 @@ matrix:
|
|||||||
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
|
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { pip --disable-pip-version-check install codecov }
|
||||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
|
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
|
||||||
|
|
||||||
# Win32 and x64 are CMake-compatible solution platform names.
|
# Win32 and x64 are CMake-compatible solution platform names.
|
||||||
|
@@ -25,3 +25,6 @@ class CatchConan(ConanFile):
|
|||||||
|
|
||||||
def package_id(self):
|
def package_id(self):
|
||||||
self.info.header_only()
|
self.info.header_only()
|
||||||
|
|
||||||
|
def package_info(self):
|
||||||
|
self.cpp_info.builddirs.append("lib/cmake/Catch2")
|
||||||
|
@@ -144,7 +144,7 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
|||||||
if("${TestType}" STREQUAL "SCENARIO")
|
if("${TestType}" STREQUAL "SCENARIO")
|
||||||
set(Name "Scenario: ${Name}")
|
set(Name "Scenario: ${Name}")
|
||||||
endif()
|
endif()
|
||||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture )
|
||||||
set(CTestName "${TestFixture}:${Name}")
|
set(CTestName "${TestFixture}:${Name}")
|
||||||
else()
|
else()
|
||||||
set(CTestName "${Name}")
|
set(CTestName "${Name}")
|
||||||
@@ -189,24 +189,29 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
|||||||
# Escape commas in the test spec
|
# Escape commas in the test spec
|
||||||
string(REPLACE "," "\\," Name ${Name})
|
string(REPLACE "," "\\," Name ${Name})
|
||||||
|
|
||||||
|
# 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
|
||||||
|
if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18")
|
||||||
|
set(CTestName "\"${CTestName}\"")
|
||||||
|
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})
|
||||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
||||||
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
|
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
|
||||||
else()
|
else()
|
||||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||||
LABELS "${Labels}")
|
LABELS "${Labels}")
|
||||||
endif()
|
endif()
|
||||||
set_property(
|
set_property(
|
||||||
TARGET ${TestTarget}
|
TARGET ${TestTarget}
|
||||||
APPEND
|
APPEND
|
||||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||||
set_property(
|
set_property(
|
||||||
SOURCE ${SourceFile}
|
SOURCE ${SourceFile}
|
||||||
APPEND
|
APPEND
|
||||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ FAQ:
|
|||||||
Other:
|
Other:
|
||||||
* [Why Catch?](why-catch.md#top)
|
* [Why Catch?](why-catch.md#top)
|
||||||
* [Open Source Projects using Catch](opensource-users.md#top)
|
* [Open Source Projects using Catch](opensource-users.md#top)
|
||||||
|
* [Commercial Projects using Catch](commercial-users.md#top)
|
||||||
* [Contributing](contributing.md#top)
|
* [Contributing](contributing.md#top)
|
||||||
* [Release Notes](release-notes.md#top)
|
* [Release Notes](release-notes.md#top)
|
||||||
* [Deprecations and incoming changes](deprecations.md#top)
|
* [Deprecations and incoming changes](deprecations.md#top)
|
||||||
|
@@ -168,7 +168,7 @@ Note that it is not possible to simply use the same instance for different runs
|
|||||||
and resetting it between each run since that would pollute the measurements with
|
and resetting it between each run since that would pollute the measurements with
|
||||||
the resetting code.
|
the resetting code.
|
||||||
|
|
||||||
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
|
It is also possible to just provide an argument name to the simple `BENCHMARK` macro to get
|
||||||
the same semantics as providing a callable to `meter.measure` with `int` argument:
|
the same semantics as providing a callable to `meter.measure` with `int` argument:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
@@ -189,19 +189,17 @@ construct and destroy objects without dynamic allocation and in a way that lets
|
|||||||
you measure construction and destruction separately.
|
you measure construction and destruction separately.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter)
|
BENCHMARK_ADVANCED("construct")(Catch::Benchmark::Chronometer meter) {
|
||||||
{
|
|
||||||
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
std::vector<Catch::Benchmark::storage_for<std::string>> storage(meter.runs());
|
||||||
meter.measure([&](int i) { storage[i].construct("thing"); });
|
meter.measure([&](int i) { storage[i].construct("thing"); });
|
||||||
})
|
};
|
||||||
|
|
||||||
BENCHMARK_ADVANCED("destroy", [](Catch::Benchmark::Chronometer meter)
|
BENCHMARK_ADVANCED("destroy")(Catch::Benchmark::Chronometer meter) {
|
||||||
{
|
|
||||||
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
std::vector<Catch::Benchmark::destructable_object<std::string>> storage(meter.runs());
|
||||||
for(auto&& o : storage)
|
for(auto&& o : storage)
|
||||||
o.construct("thing");
|
o.construct("thing");
|
||||||
meter.measure([&](int i) { storage[i].destruct(); });
|
meter.measure([&](int i) { storage[i].destruct(); });
|
||||||
})
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
|
`Catch::Benchmark::storage_for<T>` objects are just pieces of raw storage suitable for `T`
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
[Automatic test registration](#automatic-test-registration)<br>
|
[Automatic test registration](#automatic-test-registration)<br>
|
||||||
[CMake project options](#cmake-project-options)<br>
|
[CMake project options](#cmake-project-options)<br>
|
||||||
[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
|
[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
|
||||||
|
[Installing Catch2 from vcpkg](#installing-catch2-from-vcpkg)<br>
|
||||||
|
|
||||||
Because we use CMake to build Catch2, we also provide a couple of
|
Because we use CMake to build Catch2, we also provide a couple of
|
||||||
integration points for our users.
|
integration points for our users.
|
||||||
@@ -220,6 +221,19 @@ when configuring the build, and then modify your calls to
|
|||||||
[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
|
[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
|
||||||
accordingly.
|
accordingly.
|
||||||
|
|
||||||
|
## Installing Catch2 from vcpkg
|
||||||
|
|
||||||
|
Alternatively, you can build and install Catch2 using [vcpkg](https://github.com/microsoft/vcpkg/) dependency manager:
|
||||||
|
```
|
||||||
|
git clone https://github.com/Microsoft/vcpkg.git
|
||||||
|
cd vcpkg
|
||||||
|
./bootstrap-vcpkg.sh
|
||||||
|
./vcpkg integrate install
|
||||||
|
./vcpkg install catch2
|
||||||
|
```
|
||||||
|
|
||||||
|
The catch2 port in vcpkg is kept up to date by microsoft team members and community contributors.
|
||||||
|
If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
[Specify the number of resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
|
[Specify the number of resamples for bootstrapping](#specify-the-number-of-resamples-for-bootstrapping)<br>
|
||||||
[Specify the confidence-interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
|
[Specify the confidence-interval for bootstrapping](#specify-the-confidence-interval-for-bootstrapping)<br>
|
||||||
[Disable statistical analysis of collected benchmark samples](#disable-statistical-analysis-of-collected-benchmark-samples)<br>
|
[Disable statistical analysis of collected benchmark samples](#disable-statistical-analysis-of-collected-benchmark-samples)<br>
|
||||||
|
[Specify the amount of time in milliseconds spent on warming up each test](#specify-the-amount-of-time-in-milliseconds-spent-on-warming-up-each-test)<br>
|
||||||
[Usage](#usage)<br>
|
[Usage](#usage)<br>
|
||||||
[Specify the section to run](#specify-the-section-to-run)<br>
|
[Specify the section to run](#specify-the-section-to-run)<br>
|
||||||
[Filenames as tags](#filenames-as-tags)<br>
|
[Filenames as tags](#filenames-as-tags)<br>
|
||||||
@@ -64,6 +65,7 @@ Click one of the following links to take you straight to that option - or scroll
|
|||||||
<a href="#benchmark-resamples"> ` --benchmark-resamples`</a><br />
|
<a href="#benchmark-resamples"> ` --benchmark-resamples`</a><br />
|
||||||
<a href="#benchmark-confidence-interval"> ` --benchmark-confidence-interval`</a><br />
|
<a href="#benchmark-confidence-interval"> ` --benchmark-confidence-interval`</a><br />
|
||||||
<a href="#benchmark-no-analysis"> ` --benchmark-no-analysis`</a><br />
|
<a href="#benchmark-no-analysis"> ` --benchmark-no-analysis`</a><br />
|
||||||
|
<a href="#benchmark-warmup-time"> ` --benchmark-warmup-time`</a><br />
|
||||||
<a href="#use-colour"> ` --use-colour`</a><br />
|
<a href="#use-colour"> ` --use-colour`</a><br />
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
@@ -220,6 +222,16 @@ available warnings
|
|||||||
|
|
||||||
When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not.
|
When set to ```yes``` Catch will report the duration of each test case, in milliseconds. Note that it does this regardless of whether a test case passes or fails. Note, also, the certain reporters (e.g. Junit) always report test case durations regardless of this option being set or not.
|
||||||
|
|
||||||
|
<pre>-D, --min-duration <value></pre>
|
||||||
|
|
||||||
|
> `--min-duration` was [introduced](https://github.com/catchorg/Catch2/pull/1910) in Catch 2.13.0
|
||||||
|
|
||||||
|
When set, Catch will report the duration of each test case that took more
|
||||||
|
than <value> seconds, in milliseconds. This option is overriden by both
|
||||||
|
`-d yes` and `-d no`, so that either all durations are reported, or none
|
||||||
|
are.
|
||||||
|
|
||||||
|
|
||||||
<a id="input-file"></a>
|
<a id="input-file"></a>
|
||||||
## Load test names to run from a file
|
## Load test names to run from a file
|
||||||
<pre>-f, --input-file <filename></pre>
|
<pre>-f, --input-file <filename></pre>
|
||||||
@@ -241,15 +253,25 @@ This option lists all available tests in a non-indented form, one on each line.
|
|||||||
|
|
||||||
Test cases are ordered one of three ways:
|
Test cases are ordered one of three ways:
|
||||||
|
|
||||||
|
|
||||||
### decl
|
### decl
|
||||||
Declaration order (this is the default order if no --order argument is provided). The order the tests were originally declared in. Note that ordering between files is not guaranteed and is implementation dependent.
|
Declaration order (this is the default order if no --order argument is provided).
|
||||||
|
Tests in the same TU are sorted using their declaration orders, different
|
||||||
|
TUs are in an implementation (linking) dependent order.
|
||||||
|
|
||||||
|
|
||||||
### lex
|
### lex
|
||||||
Lexicographically sorted. Tests are sorted, alpha-numerically, by name.
|
Lexicographic order. Tests are sorted by their name, their tags are ignored.
|
||||||
|
|
||||||
|
|
||||||
### rand
|
### rand
|
||||||
Randomly sorted. Test names are sorted using ```std::random_shuffle()```. By default the random number generator is seeded with 0 - and so the order is repeatable. To control the random seed see <a href="#rng-seed">rng-seed</a>.
|
|
||||||
|
Randomly sorted. The order is dependent on Catch2's random seed (see
|
||||||
|
[`--rng-seed`](#rng-seed)), and is subset invariant. What this means
|
||||||
|
is that as long as the random seed is fixed, running only some tests
|
||||||
|
(e.g. via tag) does not change their relative order.
|
||||||
|
|
||||||
|
> The subset stability was introduced in Catch2 v2.12.0
|
||||||
|
|
||||||
|
|
||||||
<a id="rng-seed"></a>
|
<a id="rng-seed"></a>
|
||||||
## Specify a seed for the Random Number Generator
|
## Specify a seed for the Random Number Generator
|
||||||
@@ -269,7 +291,7 @@ See [The LibIdentify repo for more information and examples](https://github.com/
|
|||||||
|
|
||||||
<a id="wait-for-keypress"></a>
|
<a id="wait-for-keypress"></a>
|
||||||
## Wait for key before continuing
|
## Wait for key before continuing
|
||||||
<pre>--wait-for-keypress <start|exit|both></pre>
|
<pre>--wait-for-keypress <never|start|exit|both></pre>
|
||||||
|
|
||||||
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
|
Will cause the executable to print a message and wait until the return/ enter key is pressed before continuing -
|
||||||
either before running any tests, after running all tests - or both, depending on the argument.
|
either before running any tests, after running all tests - or both, depending on the argument.
|
||||||
@@ -317,6 +339,14 @@ Must be between 0 and 1 and defaults to 0.95.
|
|||||||
When this flag is specified no bootstrapping or any other statistical analysis is performed.
|
When this flag is specified no bootstrapping or any other statistical analysis is performed.
|
||||||
Instead the user code is only measured and the plain mean from the samples is reported.
|
Instead the user code is only measured and the plain mean from the samples is reported.
|
||||||
|
|
||||||
|
<a id="benchmark-warmup-time"></a>
|
||||||
|
## Specify the amount of time in milliseconds spent on warming up each test
|
||||||
|
<pre>--benchmark-warmup-time</pre>
|
||||||
|
|
||||||
|
> [Introduced](https://github.com/catchorg/Catch2/pull/1844) in Catch 2.11.2.
|
||||||
|
|
||||||
|
Configure the amount of time spent warming up each test.
|
||||||
|
|
||||||
<a id="usage"></a>
|
<a id="usage"></a>
|
||||||
## Usage
|
## Usage
|
||||||
<pre>-h, -?, --help</pre>
|
<pre>-h, -?, --help</pre>
|
||||||
|
@@ -17,4 +17,6 @@ fact then please let us know - either directly, via a PR or
|
|||||||
- NASA
|
- NASA
|
||||||
- [Inscopix Inc.](https://www.inscopix.com/)
|
- [Inscopix Inc.](https://www.inscopix.com/)
|
||||||
- [Makimo](https://makimo.pl/)
|
- [Makimo](https://makimo.pl/)
|
||||||
- [UX3D] (https://ux3d.io)
|
- [UX3D](https://ux3d.io)
|
||||||
|
- [King](https://king.com)
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
[Windows header clutter](#windows-header-clutter)<br>
|
[Windows header clutter](#windows-header-clutter)<br>
|
||||||
[Enabling stringification](#enabling-stringification)<br>
|
[Enabling stringification](#enabling-stringification)<br>
|
||||||
[Disabling exceptions](#disabling-exceptions)<br>
|
[Disabling exceptions](#disabling-exceptions)<br>
|
||||||
|
[Overriding Catch's debug break (`-b`)](#overriding-catchs-debug-break--b)<br>
|
||||||
|
|
||||||
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
|
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
|
||||||
|
|
||||||
@@ -257,6 +258,18 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Overriding Catch's debug break (`-b`)
|
||||||
|
|
||||||
|
> [Introduced](https://github.com/catchorg/Catch2/pull/1846) in Catch 2.11.2.
|
||||||
|
|
||||||
|
You can override Catch2's break-into-debugger code by defining the
|
||||||
|
`CATCH_BREAK_INTO_DEBUGGER()` macro. This can be used if e.g. Catch2 does
|
||||||
|
not know your platform, or your platform is misdetected.
|
||||||
|
|
||||||
|
The macro will be used as is, that is, `CATCH_BREAK_INTO_DEBUGGER();`
|
||||||
|
must compile and must break into debugger.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -1,100 +1,134 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Contributing to Catch
|
# Contributing to Catch2
|
||||||
|
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
[Branches](#branches)<br>
|
[Using Git(Hub)](#using-github)<br>
|
||||||
[Directory structure](#directory-structure)<br>
|
|
||||||
[Testing your changes](#testing-your-changes)<br>
|
[Testing your changes](#testing-your-changes)<br>
|
||||||
[Documenting your code](#documenting-your-code)<br>
|
[Writing documentation](#writing-documentation)<br>
|
||||||
[Code constructs to watch out for](#code-constructs-to-watch-out-for)<br>
|
[Writing code](#writing-code)<br>
|
||||||
|
[CoC](#coc)<br>
|
||||||
|
|
||||||
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
|
So you want to contribute something to Catch2? That's great! Whether it's
|
||||||
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
|
a bug fix, a new feature, support for additional compilers - or just
|
||||||
Of course so are bug reports and other comments and questions.
|
a fix to the documentation - all contributions are very welcome and very
|
||||||
|
much appreciated. Of course so are bug reports, other comments, and
|
||||||
|
questions, but generally it is a better idea to ask questions in our
|
||||||
|
[Discord](https://discord.gg/4CWS9zD), than in the issue tracker.
|
||||||
|
|
||||||
If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to
|
|
||||||
help you find your way around. As this is liable to drift out of date please raise an issue or, better still, a pull
|
|
||||||
request for this file, if you notice that.
|
|
||||||
|
|
||||||
## Branches
|
This page covers some guidelines and helpful tips for contributing
|
||||||
|
to the codebase itself.
|
||||||
|
|
||||||
Ongoing development is currently on _master_. At some point an integration branch will be set-up and PRs should target
|
## Using Git(Hub)
|
||||||
that - but for now it's all against master. You may see feature branches come and go from time to time, too.
|
|
||||||
|
|
||||||
## Directory structure
|
Ongoing development happens in the `master` branch for Catch2 v2, and in
|
||||||
|
`dev-v3` for the next major version, v3.
|
||||||
|
|
||||||
_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
|
Commits should be small and atomic. A commit is atomic when, after it is
|
||||||
primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
|
applied, the codebase, tests and all, still works as expected. Small
|
||||||
`projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
|
commits are also prefered, as they make later operations with git history,
|
||||||
project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion,
|
whether it is bisecting, reverting, or something else, easier.
|
||||||
it can work with the CMake file directly.
|
|
||||||
|
|
||||||
As well as the runtime test files you'll also see a `SurrogateCpps` directory under `projects/SelfTest`.
|
_When submitting a pull request please do not include changes to the
|
||||||
This contains a set of .cpp files that each `#include` a single header.
|
single include. This means do not include them in your git commits!_
|
||||||
While these files are not essential to compilation they help to keep the implementation headers self-contained.
|
|
||||||
At time of writing this set is not complete but has reasonable coverage.
|
|
||||||
If you add additional headers please try to remember to add a surrogate cpp for it.
|
|
||||||
|
|
||||||
The other directories are `scripts` which contains a set of python scripts to help in testing Catch as well as
|
|
||||||
generating the single include, and `docs`, which contains the documentation as a set of markdown files.
|
|
||||||
|
|
||||||
__When submitting a pull request please do not include changes to the single include, or to the version number file
|
When addressing review comments in a MR, please do not rebase/squash the
|
||||||
as these are managed by the scripts!__
|
commits immediately. Doing so makes it harder to review the new changes,
|
||||||
|
slowing down the process of merging a MR. Instead, when addressing review
|
||||||
|
comments, you should append new commits to the branch and only squash
|
||||||
|
them into other commits when the MR is ready to be merged. We recommend
|
||||||
|
creating new commits with `git commit --fixup` (or `--squash`) and then
|
||||||
|
later squashing them with `git rebase --autosquash` to make things easier.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Testing your changes
|
## Testing your changes
|
||||||
|
|
||||||
Obviously all changes to Catch's code should be tested. If you added new
|
_Note: Running Catch2's tests requires Python3_
|
||||||
functionality, you should add tests covering and showcasing it. Even if you have
|
|
||||||
only made changes to Catch internals (i.e. you implemented some performance
|
|
||||||
improvements), you should still test your changes.
|
|
||||||
|
|
||||||
This means 2 things
|
|
||||||
|
|
||||||
* Compiling Catch's SelfTest project:
|
Catch2 has multiple layers of tests that are then run as part of our CI.
|
||||||
|
The most obvious one are the unit tests compiled into the `SelfTest`
|
||||||
|
binary. These are then used in "Approval tests", which run (almost) all
|
||||||
|
tests from `SelfTest` through a specific reporter and then compare the
|
||||||
|
generated output with a known good output ("Baseline"). By default, new
|
||||||
|
tests should be placed here.
|
||||||
|
|
||||||
|
However, not all tests can be written as plain unit tests. For example,
|
||||||
|
checking that Catch2 orders tests randomly when asked to, and that this
|
||||||
|
random ordering is subset-invariant, is better done as an integration
|
||||||
|
test using an external check script. Catch2 integration tests are written
|
||||||
|
using CTest, either as a direct command invocation + pass/fail regex,
|
||||||
|
or by delegating the check to a Python script.
|
||||||
|
|
||||||
|
There are also two more kinds of tests, examples and "ExtraTests".
|
||||||
|
Examples serve as a compilation test on the single-header distribution,
|
||||||
|
and present a small and self-contained snippets of using Catch2 for
|
||||||
|
writing tests. ExtraTests then are tests that either take a long time
|
||||||
|
to run, or require separate compilation, e.g. because of testing compile
|
||||||
|
time configuration options, and take a long time because of that.
|
||||||
|
|
||||||
|
Both of these are compiled against the single-header distribution of
|
||||||
|
Catch2, and thus might require you to regenerate it manually. This is
|
||||||
|
done by calling the `generateSingleHeader.py` script in `scripts`.
|
||||||
|
|
||||||
|
Examples and ExtraTests are not compiled by default. To compile them,
|
||||||
|
add `-DCATCH_BUILD_EXAMPLES=ON` and `-DCATCH_BUILD_EXTRA_TESTS=ON` to
|
||||||
|
the invocation of CMake configuration step.
|
||||||
|
|
||||||
|
Bringing this all together, the steps below should configure, build,
|
||||||
|
and run all tests in the `Debug` compilation.
|
||||||
|
|
||||||
|
1. Regenerate the single header distribution
|
||||||
```
|
```
|
||||||
$ cd Catch2
|
$ cd Catch2
|
||||||
$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug
|
$ ./scripts/generateSingleHeader.py
|
||||||
|
```
|
||||||
|
2. Configure the full test build
|
||||||
|
```
|
||||||
|
$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug -DCATCH_BUILD_EXAMPLES=ON -DCATCH_BUILD_EXTRA_TESTS=ON
|
||||||
|
```
|
||||||
|
3. Run the actual build
|
||||||
|
```
|
||||||
$ cmake --build debug-build
|
$ cmake --build debug-build
|
||||||
```
|
```
|
||||||
because code that does not compile is evidently incorrect. Obviously,
|
4. Run the tests using CTest
|
||||||
you are not expected to have access to all the compilers and platforms
|
|
||||||
supported by Catch2, but you should at least smoke test your changes
|
|
||||||
on your platform. Our CI pipeline will check your PR against most of
|
|
||||||
the supported platforms, but it takes an hour to finish -- compiling
|
|
||||||
locally takes just a few minutes.
|
|
||||||
|
|
||||||
|
|
||||||
* Running the tests via CTest:
|
|
||||||
```
|
```
|
||||||
$ cd debug-build
|
$ cd debug-build
|
||||||
$ ctest -j 2 --output-on-failure
|
$ ctest -j 4 --output-on-failure -C Debug
|
||||||
```
|
```
|
||||||
__Note:__ When running your tests with multi-configuration generators like
|
|
||||||
Visual Studio, you might get errors "Test not available without configuration."
|
|
||||||
You then have to pick one configuration (e.g. ` -C Debug`) in the `ctest` call.
|
|
||||||
|
|
||||||
If you added new tests, approval tests are very likely to fail. If they
|
|
||||||
do not, it means that your changes weren't run as part of them. This
|
|
||||||
_might_ be intentional, but usually is not.
|
|
||||||
|
|
||||||
The approval tests compare current output of the SelfTest binary in various
|
|
||||||
configurations against known good outputs. The reason it fails is,
|
|
||||||
_usually_, that you've added new tests but have not yet approved the changes
|
|
||||||
they introduce. This is done with the `scripts/approve.py` script, but
|
|
||||||
before you do so, you need to check that the introduced changes are indeed
|
|
||||||
intentional.
|
|
||||||
|
|
||||||
|
|
||||||
## Documenting your code
|
## Writing documentation
|
||||||
|
|
||||||
If you have added new feature to Catch2, it needs documentation, so that
|
If you have added new feature to Catch2, it needs documentation, so that
|
||||||
other people can use it as well. This section collects some technical
|
other people can use it as well. This section collects some technical
|
||||||
information that you will need for updating Catch2's documentation, and
|
information that you will need for updating Catch2's documentation, and
|
||||||
possibly some generic advise as well.
|
possibly some generic advise as well.
|
||||||
|
|
||||||
|
### Technicalities
|
||||||
|
|
||||||
First, the technicalities:
|
First, the technicalities:
|
||||||
|
|
||||||
|
* If you have introduced a new document, there is a simple template you
|
||||||
|
should use. It provides you with the top anchor mentioned to link to
|
||||||
|
(more below), and also with a backlink to the top of the documentation:
|
||||||
|
```markdown
|
||||||
|
<a id="top"></a>
|
||||||
|
# Cool feature
|
||||||
|
|
||||||
|
Text that explains how to use the cool feature.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Home](Readme.md#top)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Crosslinks to different pages should target the `top` anchor, like this
|
||||||
|
`[link to contributing](contributing.md#top)`.
|
||||||
|
|
||||||
* We introduced version tags to the documentation, which show users in
|
* We introduced version tags to the documentation, which show users in
|
||||||
which version a specific feature was introduced. This means that newly
|
which version a specific feature was introduced. This means that newly
|
||||||
written documentation should be tagged with a placeholder, that will
|
written documentation should be tagged with a placeholder, that will
|
||||||
@@ -106,23 +140,8 @@ tags for other features).
|
|||||||
placeholder is usually used after a section heading
|
placeholder is usually used after a section heading
|
||||||
* `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
|
* `> X (Y and Z) was [introduced](link-to-issue-or-PR) in Catch X.Y.Z`
|
||||||
- this placeholder is used when you need to tag a subpart of something,
|
- this placeholder is used when you need to tag a subpart of something,
|
||||||
e.g. list
|
e.g. a list
|
||||||
* Crosslinks to different pages should target the `top` anchor, like this
|
|
||||||
`[link to contributing](contributing.md#top)`.
|
|
||||||
* If you have introduced a new document, there is a simple template you
|
|
||||||
should use. It provides you with the top anchor mentioned above, and also
|
|
||||||
with a backlink to the top of the documentation:
|
|
||||||
```markdown
|
|
||||||
<a id="top"></a>
|
|
||||||
# Cool feature
|
|
||||||
|
|
||||||
Text that explains how to use the cool feature.
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
|
||||||
```
|
|
||||||
* For pages with more than 4 subheadings, we provide a table of contents
|
* For pages with more than 4 subheadings, we provide a table of contents
|
||||||
(ToC) at the top of the page. Because GitHub markdown does not support
|
(ToC) at the top of the page. Because GitHub markdown does not support
|
||||||
automatic generation of ToC, it has to be handled semi-manually. Thus,
|
automatic generation of ToC, it has to be handled semi-manually. Thus,
|
||||||
@@ -130,21 +149,54 @@ if you've added a new subheading to some page, you should add it to the
|
|||||||
ToC. This can be done either manually, or by running the
|
ToC. This can be done either manually, or by running the
|
||||||
`updateDocumentToC.py` script in the `scripts/` folder.
|
`updateDocumentToC.py` script in the `scripts/` folder.
|
||||||
|
|
||||||
|
### Contents
|
||||||
|
|
||||||
Now, for the generic tips:
|
Now, for some content tips:
|
||||||
* Usage examples are good
|
|
||||||
* Don't be afraid to introduce new pages
|
* Usage examples are good. However, having large code snippets inline
|
||||||
* Try to be reasonably consistent with the surrounding documentation
|
can make the documentation less readable, and so the inline snippets
|
||||||
|
should be kept reasonably short. To provide more complex compilable
|
||||||
|
examples, consider adding new .cpp file to `examples/`.
|
||||||
|
|
||||||
|
* Don't be afraid to introduce new pages. The current documentation
|
||||||
|
tends towards long pages, but a lot of that is caused by legacy, and
|
||||||
|
we know that some of the pages are overly big and unfocused.
|
||||||
|
|
||||||
|
* When adding information to an existing page, please try to keep your
|
||||||
|
formatting, style and changes consistent with the rest of the page.
|
||||||
|
|
||||||
|
* Any documentation has multiple different audiences, that desire
|
||||||
|
different information from the text. The 3 basic user-types to try and
|
||||||
|
cover are:
|
||||||
|
* A beginner to Catch2, who requires closer guidance for the usage of Catch2.
|
||||||
|
* Advanced user of Catch2, who want to customize their usage.
|
||||||
|
* Experts, looking for full reference of Catch2's capabilities.
|
||||||
|
|
||||||
|
|
||||||
|
## Writing code
|
||||||
|
|
||||||
|
If want to contribute code, this section contains some simple rules
|
||||||
|
and tips on things like code formatting, code constructions to avoid,
|
||||||
|
and so on.
|
||||||
|
|
||||||
|
|
||||||
## Code constructs to watch out for
|
### Formatting
|
||||||
|
|
||||||
|
To make code formatting simpler for the contributors, Catch2 provides
|
||||||
|
its own config for `clang-format`. However, because it is currently
|
||||||
|
impossible to replicate existing Catch2's formatting in clang-format,
|
||||||
|
using it to reformat a whole file would cause massive diffs. To keep
|
||||||
|
the size of your diffs reasonable, you should only use clang-format
|
||||||
|
on the newly changed code.
|
||||||
|
|
||||||
|
|
||||||
|
### Code constructs to watch out for
|
||||||
|
|
||||||
This section is a (sadly incomplete) listing of various constructs that
|
This section is a (sadly incomplete) listing of various constructs that
|
||||||
are problematic and are not always caught by our CI infrastructure.
|
are problematic and are not always caught by our CI infrastructure.
|
||||||
|
|
||||||
### Naked exceptions and exceptions-related function
|
|
||||||
|
#### Naked exceptions and exceptions-related function
|
||||||
|
|
||||||
If you are throwing an exception, it should be done via `CATCH_ERROR`
|
If you are throwing an exception, it should be done via `CATCH_ERROR`
|
||||||
or `CATCH_RUNTIME_ERROR` in `catch_enforce.h`. These macros will handle
|
or `CATCH_RUNTIME_ERROR` in `catch_enforce.h`. These macros will handle
|
||||||
@@ -155,7 +207,8 @@ CI, but luckily there should not be too many reasons to use these.
|
|||||||
However, if you do, they should be kept behind a
|
However, if you do, they should be kept behind a
|
||||||
`CATCH_CONFIG_DISABLE_EXCEPTIONS` macro.
|
`CATCH_CONFIG_DISABLE_EXCEPTIONS` macro.
|
||||||
|
|
||||||
### Unqualified usage of functions from C's stdlib
|
|
||||||
|
#### Unqualified usage of functions from C's stdlib
|
||||||
|
|
||||||
If you are using a function from C's stdlib, please include the header
|
If you are using a function from C's stdlib, please include the header
|
||||||
as `<cfoo>` and call the function qualified. The common knowledge that
|
as `<cfoo>` and call the function qualified. The common knowledge that
|
||||||
@@ -163,7 +216,12 @@ there is no difference is wrong, QNX and VxWorks won't compile if you
|
|||||||
include the header as `<cfoo>` and call the function unqualified.
|
include the header as `<cfoo>` and call the function unqualified.
|
||||||
|
|
||||||
|
|
||||||
----
|
## CoC
|
||||||
|
|
||||||
|
This project has a [CoC](../CODE_OF_CONDUCT.md). Please adhere to it
|
||||||
|
while contributing to Catch2.
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
_This documentation will always be in-progress as new information comes
|
_This documentation will always be in-progress as new information comes
|
||||||
up, but we are trying to keep it as up to date as possible._
|
up, but we are trying to keep it as up to date as possible._
|
||||||
|
@@ -45,6 +45,34 @@ There should be no reason to ever have an empty `SourceLineInfo`, so the
|
|||||||
method will be removed.
|
method will be removed.
|
||||||
|
|
||||||
|
|
||||||
|
### Composing lvalues of already composed matchers
|
||||||
|
|
||||||
|
Because a significant bug in this use case has persisted for 2+ years
|
||||||
|
without a bug report, and to simplify the implementation, code that
|
||||||
|
composes lvalues of composed matchers will not compile. That is,
|
||||||
|
this code will no longer work:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto m1 = Contains("string");
|
||||||
|
auto m2 = Contains("random");
|
||||||
|
auto composed1 = m1 || m2;
|
||||||
|
auto m3 = Contains("different");
|
||||||
|
auto composed2 = composed1 || m3;
|
||||||
|
REQUIRE_THAT(foo(), !composed1);
|
||||||
|
REQUIRE_THAT(foo(), composed2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Instead you will have to write this:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto m1 = Contains("string");
|
||||||
|
auto m2 = Contains("random");
|
||||||
|
auto m3 = Contains("different");
|
||||||
|
REQUIRE_THAT(foo(), !(m1 || m2));
|
||||||
|
REQUIRE_THAT(foo(), m1 || m2 || m3);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Planned changes
|
## Planned changes
|
||||||
|
|
||||||
|
|
||||||
|
@@ -12,23 +12,88 @@ are run once per each value in a generator.
|
|||||||
This is best explained with an example:
|
This is best explained with an example:
|
||||||
```cpp
|
```cpp
|
||||||
TEST_CASE("Generators") {
|
TEST_CASE("Generators") {
|
||||||
auto i = GENERATE(1, 2, 3);
|
auto i = GENERATE(1, 3, 5);
|
||||||
SECTION("one") {
|
REQUIRE(is_odd(i));
|
||||||
auto j = GENERATE( -3, -2, -1 );
|
|
||||||
REQUIRE(j < i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The assertion in this test case will be run 9 times, because there
|
The "Generators" `TEST_CASE` will be entered 3 times, and the value of
|
||||||
are 3 possible values for `i` (1, 2, and 3) and there are 3 possible
|
`i` will be 1, 3, and 5 in turn. `GENERATE`s can also be used multiple
|
||||||
values for `j` (-3, -2, and -1).
|
times at the same scope, in which case the result will be a cartesian
|
||||||
|
product of all elements in the generators. This means that in the snippet
|
||||||
|
below, the test case will be run 6 (2\*3) times.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("Generators") {
|
||||||
|
auto i = GENERATE(1, 2);
|
||||||
|
auto j = GENERATE(3, 4, 5);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
There are 2 parts to generators in Catch2, the `GENERATE` macro together
|
There are 2 parts to generators in Catch2, the `GENERATE` macro together
|
||||||
with the already provided generators, and the `IGenerator<T>` interface
|
with the already provided generators, and the `IGenerator<T>` interface
|
||||||
that allows users to implement their own generators.
|
that allows users to implement their own generators.
|
||||||
|
|
||||||
|
|
||||||
|
## Combining `GENERATE` and `SECTION`.
|
||||||
|
|
||||||
|
`GENERATE` can be seen as an implicit `SECTION`, that goes from the place
|
||||||
|
`GENERATE` is used, to the end of the scope. This can be used for various
|
||||||
|
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).
|
||||||
|
|
||||||
|
```
|
||||||
|
TEST_CASE("Generators") {
|
||||||
|
auto i = GENERATE(1, 2);
|
||||||
|
SECTION("one") {
|
||||||
|
auto j = GENERATE(-3, -2);
|
||||||
|
REQUIRE(j < i);
|
||||||
|
}
|
||||||
|
SECTION("two") {
|
||||||
|
auto k = GENERATE(4, 5, 6);
|
||||||
|
REQUIRE(j != k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The specific order of the `SECTION`s will be "one", "one", "two", "two",
|
||||||
|
"two", "one"...
|
||||||
|
|
||||||
|
|
||||||
|
The fact that `GENERATE` introduces a virtual `SECTION` can also be used
|
||||||
|
to make a generator replay only some `SECTION`s, without having to
|
||||||
|
explicitly add a `SECTION`. As an example, the code below reports 3
|
||||||
|
assertions, because the "first" section is run once, but the "second"
|
||||||
|
section is run twice.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("GENERATE between SECTIONs") {
|
||||||
|
SECTION("first") { REQUIRE(true); }
|
||||||
|
auto _ = GENERATE(1, 2);
|
||||||
|
SECTION("second") { REQUIRE(true); }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This can lead to surprisingly complex test flows. As an example, the test
|
||||||
|
below will report 14 assertions:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("Complex mix of sections and generates") {
|
||||||
|
auto i = GENERATE(1, 2);
|
||||||
|
SECTION("A") {
|
||||||
|
SUCCEED("A");
|
||||||
|
}
|
||||||
|
auto j = GENERATE(3, 4);
|
||||||
|
SECTION("B") {
|
||||||
|
SUCCEED("B");
|
||||||
|
}
|
||||||
|
auto k = GENERATE(5, 6);
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> The ability to place `GENERATE` between two `SECTION`s was [introduced](https://github.com/catchorg/Catch2/issues/1938) in Catch 2.13.0.
|
||||||
|
|
||||||
## Provided generators
|
## Provided generators
|
||||||
|
|
||||||
Catch2's provided generator functionality consists of three parts,
|
Catch2's provided generator functionality consists of three parts,
|
||||||
@@ -78,7 +143,7 @@ type, making their usage much nicer. These are
|
|||||||
|
|
||||||
> `from_range` has been introduced in Catch 2.10.0
|
> `from_range` has been introduced in Catch 2.10.0
|
||||||
|
|
||||||
> `range()` for floating point numbers has been introduced in Catch X.Y.Z
|
> `range()` for floating point numbers has been introduced in Catch 2.11.0
|
||||||
|
|
||||||
And can be used as shown in the example below to create a generator
|
And can be used as shown in the example below to create a generator
|
||||||
that returns 100 odd random number:
|
that returns 100 odd random number:
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
||||||
- Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
|
- Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
|
||||||
- Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
|
- Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
|
||||||
|
- Generators: [Run test with a table of input values](../examples/302-Gen-Table.cpp)
|
||||||
- Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
|
- Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
|
||||||
- Generators: [Use custom variable capture in generator expressions](../examples/311-Gen-CustomCapture.cpp)
|
- Generators: [Use custom variable capture in generator expressions](../examples/311-Gen-CustomCapture.cpp)
|
||||||
|
|
||||||
|
@@ -20,18 +20,21 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
|||||||
### [ApprovalTests.cpp](https://github.com/approvals/ApprovalTests.cpp)
|
### [ApprovalTests.cpp](https://github.com/approvals/ApprovalTests.cpp)
|
||||||
C++11 implementation of Approval Tests, for quick, convenient testing of legacy code.
|
C++11 implementation of Approval Tests, for quick, convenient testing of legacy code.
|
||||||
|
|
||||||
|
### [args](https://github.com/Taywee/args)
|
||||||
|
A simple header-only C++ argument parser library.
|
||||||
|
|
||||||
### [Azmq](https://github.com/zeromq/azmq)
|
### [Azmq](https://github.com/zeromq/azmq)
|
||||||
Boost Asio style bindings for ZeroMQ.
|
Boost Asio style bindings for ZeroMQ.
|
||||||
|
|
||||||
### [Cataclysm: Dark Days Ahead](https://github.com/CleverRaven/Cataclysm-DDA)
|
### [Cataclysm: Dark Days Ahead](https://github.com/CleverRaven/Cataclysm-DDA)
|
||||||
Post-apocalyptic survival RPG.
|
Post-apocalyptic survival RPG.
|
||||||
|
|
||||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
|
||||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
|
|
||||||
|
|
||||||
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques.
|
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques.
|
||||||
|
|
||||||
|
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||||
|
The core part of the Chakra JavaScript engine that powers Microsoft Edge.
|
||||||
|
|
||||||
### [Clara](https://github.com/philsquared/Clara)
|
### [Clara](https://github.com/philsquared/Clara)
|
||||||
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
||||||
|
|
||||||
@@ -65,9 +68,6 @@ A small C++ library wrapper for the native C ODBC API.
|
|||||||
### [Nonius](https://github.com/libnonius/nonius)
|
### [Nonius](https://github.com/libnonius/nonius)
|
||||||
A header-only framework for benchmarking small snippets of C++ code.
|
A header-only framework for benchmarking small snippets of C++ code.
|
||||||
|
|
||||||
### [SOCI](https://github.com/SOCI/soci)
|
|
||||||
The C++ Database Access Library.
|
|
||||||
|
|
||||||
### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
|
### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
|
||||||
A polymorphic value-type for C++.
|
A polymorphic value-type for C++.
|
||||||
|
|
||||||
@@ -77,18 +77,21 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
|
|||||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||||
A library of algorithms for values-distributed-in-time.
|
A library of algorithms for values-distributed-in-time.
|
||||||
|
|
||||||
### [thor](https://github.com/xorz57/thor)
|
### [SOCI](https://github.com/SOCI/soci)
|
||||||
Wrapper Library for CUDA.
|
The C++ Database Access Library.
|
||||||
|
|
||||||
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
||||||
A small, single-header-only, library for wrapping and composing columns of text.
|
A small, single-header-only, library for wrapping and composing columns of text.
|
||||||
|
|
||||||
|
### [thor](https://github.com/xorz57/thor)
|
||||||
|
Wrapper Library for CUDA.
|
||||||
|
|
||||||
|
### [toml++](https://github.com/marzer/tomlplusplus)
|
||||||
|
A header-only TOML parser and serializer for modern C++.
|
||||||
|
|
||||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||||
A thread-safe header-only mocking framework for C++14.
|
A thread-safe header-only mocking framework for C++14.
|
||||||
|
|
||||||
### [args](https://github.com/Taywee/args)
|
|
||||||
A simple header-only C++ argument parser library.
|
|
||||||
|
|
||||||
## Applications & Tools
|
## Applications & Tools
|
||||||
|
|
||||||
### [ArangoDB](https://github.com/arangodb/arangodb)
|
### [ArangoDB](https://github.com/arangodb/arangodb)
|
||||||
@@ -103,6 +106,9 @@ MAME originally stood for Multiple Arcade Machine Emulator.
|
|||||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||||
|
|
||||||
|
### [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead)
|
||||||
|
A 2D, Zombie, RPG game which is being made on our own engine.
|
||||||
|
|
||||||
### [raspigcd](https://github.com/pantadeusz/raspigcd)
|
### [raspigcd](https://github.com/pantadeusz/raspigcd)
|
||||||
Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks).
|
Low level CLI app and library for execution of GCODE on Raspberry Pi without any additional microcontrolers (just RPi + Stepsticks).
|
||||||
|
|
||||||
@@ -112,9 +118,6 @@ SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gr
|
|||||||
### [Standardese](https://github.com/foonathan/standardese)
|
### [Standardese](https://github.com/foonathan/standardese)
|
||||||
Standardese aims to be a nextgen Doxygen.
|
Standardese aims to be a nextgen Doxygen.
|
||||||
|
|
||||||
### [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead)
|
|
||||||
A 2D, Zombie, RPG game which is being made on our own engine.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -11,9 +11,9 @@ The easiest way to use Catch is to let it supply ```main()``` for you and handle
|
|||||||
|
|
||||||
This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
|
This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
|
||||||
|
|
||||||
Sometimes, though, you need to write your own version of main(). You can do this by writing ```#define CATCH_CONFIG_RUNNER``` instead. Now you are free to write ```main()``` as normal and call into Catch yourself manually.
|
Sometimes, though, you need to write your own version of main(). You can do this by writing ```#define CATCH_CONFIG_RUNNER``` instead. Now you are free to write ```main()``` as normal and call into Catch yourself manually. You now have a lot of flexibility - but here are three recipes to get your started:
|
||||||
|
|
||||||
You now have a lot of flexibility - but here are three recipes to get your started:
|
**Important note: you can only provide `main` in the same file you defined `CATCH_CONFIG_RUNNER`.**
|
||||||
|
|
||||||
## Let Catch take full control of args and config
|
## Let Catch take full control of args and config
|
||||||
|
|
||||||
|
@@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
# Release notes
|
# Release notes
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
|
[2.13.1](#2131)<br>
|
||||||
|
[2.13.0](#2130)<br>
|
||||||
|
[2.12.4](#2124)<br>
|
||||||
|
[2.12.3](#2123)<br>
|
||||||
|
[2.12.2](#2122)<br>
|
||||||
|
[2.12.1](#2121)<br>
|
||||||
|
[2.12.0](#2120)<br>
|
||||||
|
[2.11.3](#2113)<br>
|
||||||
|
[2.11.2](#2112)<br>
|
||||||
|
[2.11.1](#2111)<br>
|
||||||
|
[2.11.0](#2110)<br>
|
||||||
[2.10.2](#2102)<br>
|
[2.10.2](#2102)<br>
|
||||||
[2.10.1](#2101)<br>
|
[2.10.1](#2101)<br>
|
||||||
[2.10.0](#2100)<br>
|
[2.10.0](#2100)<br>
|
||||||
@@ -31,6 +42,162 @@
|
|||||||
[Even Older versions](#even-older-versions)<br>
|
[Even Older versions](#even-older-versions)<br>
|
||||||
|
|
||||||
|
|
||||||
|
## 2.13.1
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* `ParseAndAddCatchTests` handles CMake v3.18.0 correctly (#1984)
|
||||||
|
* Improved autodetection of `std::byte` (#1992)
|
||||||
|
* Simplified implementation of templated test cases (#2007)
|
||||||
|
* This should have a tiny positive effect on its compilation throughput
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Automatic stringification of ranges handles sentinel ranges properly (#2004)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.13.0
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* `GENERATE` can now follow a `SECTION` at the same level of nesting (#1938)
|
||||||
|
* The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will.
|
||||||
|
* Added `-D`/`--min-duration` command line flag (#1910)
|
||||||
|
* If a test takes longer to finish than the provided value, its name and duration will be printed.
|
||||||
|
* This flag is overriden by setting `-d`/`--duration`.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* `TAPReporter` no longer skips successful assertions (#1983)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.12.4
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added support for MacOS on ARM (#1971)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.12.3
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* `GENERATE` nested in a for loop no longer creates multiple generators (#1913)
|
||||||
|
* Fixed copy paste error breaking `TEMPLATE_TEST_CASE_SIG` for 6 or more arguments (#1954)
|
||||||
|
* Fixed potential UB when handling non-ASCII characters in CLI args (#1943)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* There can be multiple calls to `GENERATE` on a single line
|
||||||
|
* Improved `fno-except` support for platforms that do not provide shims for exception-related std functions (#1950)
|
||||||
|
* E.g. the Green Hills C++ compiler
|
||||||
|
* XmlReporter now also reports test-case-level statistics (#1958)
|
||||||
|
* This is done via a new element, `OverallResultsCases`
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* Added `.clang-format` file to the repo (#1182, #1920)
|
||||||
|
* Rewrote contributing docs
|
||||||
|
* They should explain the different levels of testing and so on much better
|
||||||
|
|
||||||
|
|
||||||
|
## 2.12.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed compilation failure if `is_range` ADL found deleted function (#1929)
|
||||||
|
* Fixed potential UB in `CAPTURE` if the expression contained non-ASCII characters (#1925)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* `std::result_of` is not used if `std::invoke_result` is available (#1934)
|
||||||
|
* JUnit reporter writes out `status` attribute for tests (#1899)
|
||||||
|
* Suppresed clang-tidy's `hicpp-vararg` warning (#1921)
|
||||||
|
* Catch2 was already suppressing the `cppcoreguidelines-pro-type-vararg` alias of the warning
|
||||||
|
|
||||||
|
|
||||||
|
## 2.12.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Vector matchers now support initializer list literals better
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added support for `^` (bitwise xor) to `CHECK` and `REQUIRE`
|
||||||
|
|
||||||
|
|
||||||
|
## 2.12.0
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Running tests in random order (`--order rand`) has been reworked significantly (#1908)
|
||||||
|
* Given same seed, all platforms now produce the same order
|
||||||
|
* Given same seed, the relative order of tests does not change if you select only a subset of them
|
||||||
|
* Vector matchers support custom allocators (#1909)
|
||||||
|
* `|` and `&` (bitwise or and bitwise and) are now supported in `CHECK` and `REQUIRE`
|
||||||
|
* The resulting type must be convertible to `bool`
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed computation of benchmarking column widths in ConsoleReporter (#1885, #1886)
|
||||||
|
* Suppressed clang-tidy's `cppcoreguidelines-pro-type-vararg` in assertions (#1901)
|
||||||
|
* It was a false positive trigered by the new warning support workaround
|
||||||
|
* Fixed bug in test specification parser handling of OR'd patterns using escaping (#1905)
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* Worked around IBM XL's codegen bug (#1907)
|
||||||
|
* It would emit code for _destructors_ of temporaries in an unevaluated context
|
||||||
|
* Improved detection of stdlib's support for `std::uncaught_exceptions` (#1911)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.11.3
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed compilation error caused by lambdas in assertions under MSVC
|
||||||
|
|
||||||
|
|
||||||
|
## 2.11.2
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* GCC and Clang now issue warnings for suspicious code in assertions (#1880)
|
||||||
|
* E.g. `REQUIRE( int != unsigned int )` will now issue mixed signedness comparison warning
|
||||||
|
* This has always worked on MSVC, but it now also works for GCC and current Clang versions
|
||||||
|
* Colorization of "Test filters" output should be more robust now
|
||||||
|
* `--wait-for-keypress` now also accepts `never` as an option (#1866)
|
||||||
|
* Reporters no longer round-off nanoseconds when reporting benchmarking results (#1876)
|
||||||
|
* Catch2's debug break now supports iOS while using Thumb instruction set (#1862)
|
||||||
|
* It is now possible to customize benchmark's warm-up time when running the test binary (#1844)
|
||||||
|
* `--benchmark-warmup-time {ms}`
|
||||||
|
* User can now specify how Catch2 should break into debugger (#1846)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixes missing `<random>` include in benchmarking (#1831)
|
||||||
|
* Fixed missing `<iterator>` include in benchmarking (#1874)
|
||||||
|
* Hidden test cases are now also tagged with `[!hide]` as per documentation (#1847)
|
||||||
|
* Detection of whether libc provides `std::nextafter` has been improved (#1854)
|
||||||
|
* Detection of `wmain` no longer incorrectly looks for `WIN32` macro (#1849)
|
||||||
|
* Now it just detects Windows platform
|
||||||
|
* Composing already-composed matchers no longer modifies the partially-composed matcher expression
|
||||||
|
* This bug has been present for the last ~2 years and nobody reported it
|
||||||
|
|
||||||
|
|
||||||
|
## 2.11.1
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Breaking into debugger is supported on iOS (#1817)
|
||||||
|
* `google-build-using-namespace` clang-tidy warning is suppressed (#1799)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Clang on Windows is no longer assumed to implement MSVC's traditional preprocessor (#1806)
|
||||||
|
* `ObjectStorage` now behaves properly in `const` contexts (#1820)
|
||||||
|
* `GENERATE_COPY(a, b)` now compiles properly (#1809, #1815)
|
||||||
|
* Some more cleanups in the benchmarking support
|
||||||
|
|
||||||
|
|
||||||
|
## 2.11.0
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* JUnit reporter output now contains more details in case of failure (#1347, #1719)
|
||||||
|
* Added SonarQube Test Data reporter (#1738)
|
||||||
|
* It is in a separate header, just like the TAP, Automake, and TeamCity reporters
|
||||||
|
* `range` generator now allows floating point numbers (#1776)
|
||||||
|
* Reworked part of internals to increase throughput
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* The single header version should contain full benchmarking support (#1800)
|
||||||
|
* `[.foo]` is now properly parsed as `[.][foo]` when used on the command line (#1798)
|
||||||
|
* Fixed compilation of benchmarking on platforms where `steady_clock::period` is not `std::nano` (#1794)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 2.10.2
|
## 2.10.2
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
@@ -67,6 +67,7 @@ $ gpg2 --armor --output catch.hpp.asc --detach-sig catch.hpp
|
|||||||
$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
|
$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
|
||||||
$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
|
$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
|
||||||
$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
|
$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
|
||||||
|
$ gpg2 --armor --output catch_reporter_sonarqube.hpp.asc --detach-sig catch_reporter_sonarqube.hpp
|
||||||
```
|
```
|
||||||
|
|
||||||
_GPG does not support signing multiple files in single invocation._
|
_GPG does not support signing multiple files in single invocation._
|
||||||
|
@@ -22,7 +22,7 @@ But functions and methods can also be written inline in header files. The downsi
|
|||||||
|
|
||||||
Because Catch is implemented *entirely* in headers you might think that the whole of Catch must be compiled into every translation unit that uses it! Actually it's not quite as bad as that. Catch mitigates this situation by effectively maintaining the traditional separation between the implementation code and declarations. Internally the implementation code is protected by ```#ifdef```s and is conditionally compiled into only one translation unit. This translation unit is that one that ```#define```s ```CATCH_CONFIG_MAIN``` or ```CATCH_CONFIG_RUNNER```. Let's call this the main source file.
|
Because Catch is implemented *entirely* in headers you might think that the whole of Catch must be compiled into every translation unit that uses it! Actually it's not quite as bad as that. Catch mitigates this situation by effectively maintaining the traditional separation between the implementation code and declarations. Internally the implementation code is protected by ```#ifdef```s and is conditionally compiled into only one translation unit. This translation unit is that one that ```#define```s ```CATCH_CONFIG_MAIN``` or ```CATCH_CONFIG_RUNNER```. Let's call this the main source file.
|
||||||
|
|
||||||
As a result the main source file *does* compile the whole of Catch every time! So it makes sense to dedicate this file to *only* ```#define```-ing the identifier and ```#include```-ing Catch (and implementing the runner code, if you're doing that). Keep all your test cases in other files. This way you won't pay the recompilation cost for the whole of Catch
|
As a result the main source file *does* compile the whole of Catch every time! So it makes sense to dedicate this file to *only* ```#define```-ing the identifier and ```#include```-ing Catch (and implementing the runner code, if you're doing that). Keep all your test cases in other files. This way you won't pay the recompilation cost for the whole of Catch.
|
||||||
|
|
||||||
## Practical example
|
## Practical example
|
||||||
Assume you have the `Factorial` function from the [tutorial](tutorial.md#top) in `factorial.cpp` (with forward declaration in `factorial.h`) and want to test it and keep the compile times down when adding new tests. Then you should have 2 files, `tests-main.cpp` and `tests-factorial.cpp`:
|
Assume you have the `Factorial` function from the [tutorial](tutorial.md#top) in `factorial.cpp` (with forward declaration in `factorial.h`) and want to test it and keep the compile times down when adding new tests. Then you should have 2 files, `tests-main.cpp` and `tests-factorial.cpp`:
|
||||||
|
@@ -106,7 +106,7 @@ Of course there are still more issues to deal with. For example we'll hit proble
|
|||||||
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
|
Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
|
||||||
|
|
||||||
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
|
1. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
|
||||||
2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>, ). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
|
2. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
|
||||||
3. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names.
|
3. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names.
|
||||||
4. We write our individual test assertions using the ```REQUIRE``` macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced.
|
4. We write our individual test assertions using the ```REQUIRE``` macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced.
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ std::string ws(int const level) {
|
|||||||
template< typename T >
|
template< typename T >
|
||||||
std::ostream& operator<<( std::ostream& os, std::vector<T> const& v ) {
|
std::ostream& operator<<( std::ostream& os, std::vector<T> const& v ) {
|
||||||
os << "{ ";
|
os << "{ ";
|
||||||
for ( auto x : v )
|
for ( const auto& x : v )
|
||||||
os << x << ", ";
|
os << x << ", ";
|
||||||
return os << "}";
|
return os << "}";
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ void print( std::ostream& os, int const level, Catch::MessageInfo const& info )
|
|||||||
|
|
||||||
void print( std::ostream& os, int const level, std::string const& title, std::vector<Catch::MessageInfo> const& v ) {
|
void print( std::ostream& os, int const level, std::string const& title, std::vector<Catch::MessageInfo> const& v ) {
|
||||||
os << ws(level ) << title << ":\n";
|
os << ws(level ) << title << ":\n";
|
||||||
for ( auto x : v )
|
for ( const auto& x : v )
|
||||||
{
|
{
|
||||||
os << ws(level+1) << "{\n";
|
os << ws(level+1) << "{\n";
|
||||||
print( os, level+2, x );
|
print( os, level+2, x );
|
||||||
@@ -300,7 +300,7 @@ char const * dashed_line =
|
|||||||
struct MyListener : Catch::TestEventListenerBase {
|
struct MyListener : Catch::TestEventListenerBase {
|
||||||
|
|
||||||
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
|
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
|
||||||
|
|
||||||
// Get rid of Wweak-tables
|
// Get rid of Wweak-tables
|
||||||
~MyListener();
|
~MyListener();
|
||||||
|
|
||||||
|
@@ -10,12 +10,13 @@
|
|||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
|
||||||
class out_buff : public std::stringbuf {
|
class out_buff : public std::stringbuf {
|
||||||
std::FILE* m_stream;
|
std::FILE* m_stream;
|
||||||
public:
|
public:
|
||||||
out_buff(std::FILE* stream) :m_stream(stream) {}
|
out_buff(std::FILE* stream):m_stream(stream) {}
|
||||||
~out_buff() { pubsync(); }
|
~out_buff();
|
||||||
int sync() {
|
int sync() override {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (unsigned char c : str()) {
|
for (unsigned char c : str()) {
|
||||||
if (putc(c, m_stream) == EOF) {
|
if (putc(c, m_stream) == EOF) {
|
||||||
@@ -29,6 +30,12 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
out_buff::~out_buff() { pubsync(); }
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic ignored "-Wexit-time-destructors" // static variables in cout/cerr/clog
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
std::ostream& cout() {
|
std::ostream& cout() {
|
||||||
static std::ostream ret(new out_buff(stdout));
|
static std::ostream ret(new out_buff(stdout));
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
// 301-Gen-MapTypeConversion.cpp
|
// 301-Gen-MapTypeConversion.cpp
|
||||||
// Shows how to use map to modify generator's return type.
|
// Shows how to use map to modify generator's return type.
|
||||||
|
|
||||||
// TODO
|
// Specifically we wrap a std::string returning generator with a generator
|
||||||
|
// that converts the strings using stoi, so the returned type is actually
|
||||||
|
// an int.
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
@@ -22,15 +24,17 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& get() const override {
|
std::string const& get() const override;
|
||||||
return m_line;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool next() override {
|
bool next() override {
|
||||||
return !!std::getline(m_stream, m_line);
|
return !!std::getline(m_stream, m_line);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string const& LineGenerator::get() const {
|
||||||
|
return m_line;
|
||||||
|
}
|
||||||
|
|
||||||
// This helper function provides a nicer UX when instantiating the generator
|
// This helper function provides a nicer UX when instantiating the generator
|
||||||
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
// Notice that it returns an instance of GeneratorWrapper<std::string>, which
|
||||||
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
|
||||||
|
54
examples/302-Gen-Table.cpp
Normal file
54
examples/302-Gen-Table.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// 302-Gen-Table.cpp
|
||||||
|
// Shows how to use table to run a test many times with different inputs. Lifted from examples on
|
||||||
|
// issue #850.
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct TestSubject {
|
||||||
|
// this is the method we are going to test. It returns the length of the
|
||||||
|
// input string.
|
||||||
|
size_t GetLength( const std::string& input ) const { return input.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Table allows pre-computed test inputs and outputs", "[example][generator]") {
|
||||||
|
using std::make_tuple;
|
||||||
|
// do setup here as normal
|
||||||
|
TestSubject subj;
|
||||||
|
|
||||||
|
SECTION("This section is run for each row in the table") {
|
||||||
|
std::string test_input;
|
||||||
|
size_t expected_output;
|
||||||
|
std::tie( test_input, expected_output ) =
|
||||||
|
GENERATE( table<std::string, size_t>(
|
||||||
|
{ /* In this case one of the parameters to our test case is the
|
||||||
|
* expected output, but this is not required. There could be
|
||||||
|
* multiple expected values in the table, which can have any
|
||||||
|
* (fixed) number of columns.
|
||||||
|
*/
|
||||||
|
make_tuple( "one", 3 ),
|
||||||
|
make_tuple( "two", 3 ),
|
||||||
|
make_tuple( "three", 5 ),
|
||||||
|
make_tuple( "four", 4 ) } ) );
|
||||||
|
|
||||||
|
// run the test
|
||||||
|
auto result = subj.GetLength(test_input);
|
||||||
|
// capture the input data to go with the outputs.
|
||||||
|
CAPTURE(test_input);
|
||||||
|
// check it matches the pre-calculated data
|
||||||
|
REQUIRE(result == expected_output);
|
||||||
|
} // end section
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Possible simplifications where less legacy toolchain support is needed:
|
||||||
|
*
|
||||||
|
* - With libstdc++6 or newer, the make_tuple() calls can be ommitted
|
||||||
|
* (technically C++17 but does not require -std in GCC/Clang). See
|
||||||
|
* https://stackoverflow.com/questions/12436586/tuple-vector-and-initializer-list
|
||||||
|
*
|
||||||
|
* - In C++17 mode std::tie() and the preceeding variable delcarations can be
|
||||||
|
* replaced by structured bindings: auto [test_input, expected] = GENERATE(
|
||||||
|
* table<std::string, size_t>({ ...
|
||||||
|
*/
|
||||||
|
// Compiling and running this file will result in 4 successful assertions
|
@@ -23,11 +23,11 @@ TEST_CASE("Generate random doubles across different ranges",
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
auto r2(r1);
|
auto r2(r1);
|
||||||
|
|
||||||
// This will take r1 by reference and r2 by value.
|
// This will take r1 by reference and r2 by value.
|
||||||
// Note that there are no advantages for doing so in this example,
|
// Note that there are no advantages for doing so in this example,
|
||||||
// it is done only for expository purposes.
|
// it is done only for expository purposes.
|
||||||
auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
|
auto number = Catch::Generators::generate( "custom capture generator", CATCH_INTERNAL_LINEINFO,
|
||||||
[&r1, r2]{
|
[&r1, r2]{
|
||||||
using namespace Catch::Generators;
|
using namespace Catch::Generators;
|
||||||
return makeGenerators(take(50, random(std::get<0>(r1), std::get<1>(r2))));
|
return makeGenerators(take(50, random(std::get<0>(r1), std::get<1>(r2))));
|
||||||
|
@@ -46,6 +46,7 @@ set( SOURCES_IDIOMATIC_TESTS
|
|||||||
210-Evt-EventListeners.cpp
|
210-Evt-EventListeners.cpp
|
||||||
300-Gen-OwnGenerator.cpp
|
300-Gen-OwnGenerator.cpp
|
||||||
301-Gen-MapTypeConversion.cpp
|
301-Gen-MapTypeConversion.cpp
|
||||||
|
302-Gen-Table.cpp
|
||||||
310-Gen-VariablesInGenerators.cpp
|
310-Gen-VariablesInGenerators.cpp
|
||||||
311-Gen-CustomCapture.cpp
|
311-Gen-CustomCapture.cpp
|
||||||
)
|
)
|
||||||
|
@@ -10,8 +10,8 @@
|
|||||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 2
|
#define CATCH_VERSION_MAJOR 2
|
||||||
#define CATCH_VERSION_MINOR 10
|
#define CATCH_VERSION_MINOR 13
|
||||||
#define CATCH_VERSION_PATCH 2
|
#define CATCH_VERSION_PATCH 1
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
# pragma clang system_header
|
# pragma clang system_header
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||||
#include "internal/benchmark/catch_benchmark.hpp"
|
#include "internal/benchmark/catch_benchmarking_all.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // ! CATCH_CONFIG_IMPL_ONLY
|
#endif // ! CATCH_CONFIG_IMPL_ONLY
|
||||||
|
2
include/external/clara.hpp
vendored
2
include/external/clara.hpp
vendored
@@ -667,7 +667,7 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
|
inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
|
||||||
std::string srcLC = source;
|
std::string srcLC = source;
|
||||||
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
|
std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
|
||||||
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||||
target = true;
|
target = true;
|
||||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||||
|
@@ -44,10 +44,10 @@ namespace Catch {
|
|||||||
template <typename Clock>
|
template <typename Clock>
|
||||||
ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
|
||||||
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
||||||
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(Detail::warmup_time));
|
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
||||||
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
|
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
|
||||||
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
||||||
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(Detail::warmup_time), Detail::warmup_iterations };
|
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Clock = default_clock>
|
template <typename Clock = default_clock>
|
||||||
@@ -79,7 +79,7 @@ namespace Catch {
|
|||||||
});
|
});
|
||||||
|
|
||||||
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
|
||||||
BenchmarkStats<std::chrono::duration<double, std::nano>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
|
||||||
getResultCapture().benchmarkEnded(stats);
|
getResultCapture().benchmarkEnded(stats);
|
||||||
|
|
||||||
} CATCH_CATCH_ALL{
|
} CATCH_CATCH_ALL{
|
||||||
|
29
include/internal/benchmark/catch_benchmarking_all.hpp
Normal file
29
include/internal/benchmark/catch_benchmarking_all.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// A proxy header that includes all of the benchmarking headers to allow
|
||||||
|
// concise include of the benchmarking features. You should prefer the
|
||||||
|
// individual includes in standard use.
|
||||||
|
|
||||||
|
#include "catch_benchmark.hpp"
|
||||||
|
#include "catch_chronometer.hpp"
|
||||||
|
#include "catch_clock.hpp"
|
||||||
|
#include "catch_constructor.hpp"
|
||||||
|
#include "catch_environment.hpp"
|
||||||
|
#include "catch_estimate.hpp"
|
||||||
|
#include "catch_execution_plan.hpp"
|
||||||
|
#include "catch_optimizer.hpp"
|
||||||
|
#include "catch_outlier_classification.hpp"
|
||||||
|
#include "catch_sample_analysis.hpp"
|
||||||
|
#include "detail/catch_analyse.hpp"
|
||||||
|
#include "detail/catch_benchmark_function.hpp"
|
||||||
|
#include "detail/catch_complete_invoke.hpp"
|
||||||
|
#include "detail/catch_estimate_clock.hpp"
|
||||||
|
#include "detail/catch_measure.hpp"
|
||||||
|
#include "detail/catch_repeat.hpp"
|
||||||
|
#include "detail/catch_run_for_at_least.hpp"
|
||||||
|
#include "detail/catch_stats.hpp"
|
||||||
|
#include "detail/catch_timing.hpp"
|
@@ -14,60 +14,66 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Detail {
|
namespace Benchmark {
|
||||||
template <typename T, bool Destruct>
|
namespace Detail {
|
||||||
struct ObjectStorage
|
template <typename T, bool Destruct>
|
||||||
{
|
struct ObjectStorage
|
||||||
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
|
||||||
|
|
||||||
ObjectStorage() : data() {}
|
|
||||||
|
|
||||||
ObjectStorage(const ObjectStorage& other)
|
|
||||||
{
|
{
|
||||||
new(&data) T(other.stored_object());
|
using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
|
||||||
}
|
|
||||||
|
|
||||||
ObjectStorage(ObjectStorage&& other)
|
ObjectStorage() : data() {}
|
||||||
{
|
|
||||||
new(&data) T(std::move(other.stored_object()));
|
|
||||||
}
|
|
||||||
|
|
||||||
~ObjectStorage() { destruct_on_exit<T>(); }
|
ObjectStorage(const ObjectStorage& other)
|
||||||
|
{
|
||||||
|
new(&data) T(other.stored_object());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
ObjectStorage(ObjectStorage&& other)
|
||||||
void construct(Args&&... args)
|
{
|
||||||
{
|
new(&data) T(std::move(other.stored_object()));
|
||||||
new (&data) T(std::forward<Args>(args)...);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <bool AllowManualDestruction = !Destruct>
|
~ObjectStorage() { destruct_on_exit<T>(); }
|
||||||
typename std::enable_if<AllowManualDestruction>::type destruct()
|
|
||||||
{
|
|
||||||
stored_object().~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
template <typename... Args>
|
||||||
// If this is a constructor benchmark, destruct the underlying object
|
void construct(Args&&... args)
|
||||||
template <typename U>
|
{
|
||||||
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
|
new (&data) T(std::forward<Args>(args)...);
|
||||||
// Otherwise, don't
|
}
|
||||||
template <typename U>
|
|
||||||
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
|
|
||||||
|
|
||||||
T& stored_object()
|
template <bool AllowManualDestruction = !Destruct>
|
||||||
{
|
typename std::enable_if<AllowManualDestruction>::type destruct()
|
||||||
return *static_cast<T*>(static_cast<void*>(&data));
|
{
|
||||||
}
|
stored_object().~T();
|
||||||
|
}
|
||||||
|
|
||||||
TStorage data;
|
private:
|
||||||
};
|
// If this is a constructor benchmark, destruct the underlying object
|
||||||
|
template <typename U>
|
||||||
|
void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }
|
||||||
|
// Otherwise, don't
|
||||||
|
template <typename U>
|
||||||
|
void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }
|
||||||
|
|
||||||
|
T& stored_object() {
|
||||||
|
return *static_cast<T*>(static_cast<void*>(&data));
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& stored_object() const {
|
||||||
|
return *static_cast<T*>(static_cast<void*>(&data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TStorage data;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using storage_for = Detail::ObjectStorage<T, true>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using destructable_object = Detail::ObjectStorage<T, false>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using storage_for = Detail::ObjectStorage<T, true>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using destructable_object = Detail::ObjectStorage<T, false>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_CONSTRUCTOR_HPP_INCLUDED
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#define TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_DETAIL_COMPLETE_INVOKE_HPP_INCLUDED
|
||||||
|
|
||||||
#include "../../catch_enforce.h"
|
#include "../../catch_enforce.h"
|
||||||
|
#include "../../catch_meta.hpp"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -42,20 +43,18 @@ namespace Catch {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename Sig>
|
|
||||||
using ResultOf_t = typename std::result_of<Sig>::type;
|
|
||||||
|
|
||||||
// invoke and not return void :(
|
// invoke and not return void :(
|
||||||
template <typename Fun, typename... Args>
|
template <typename Fun, typename... Args>
|
||||||
CompleteType_t<ResultOf_t<Fun(Args...)>> complete_invoke(Fun&& fun, Args&&... args) {
|
CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
|
||||||
return CompleteInvoker<ResultOf_t<Fun(Args...)>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
|
return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
|
const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
|
||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
|
|
||||||
template <typename Fun>
|
template <typename Fun>
|
||||||
Detail::CompleteType_t<Detail::ResultOf_t<Fun()>> user_code(Fun&& fun) {
|
Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
|
||||||
CATCH_TRY{
|
CATCH_TRY{
|
||||||
return Detail::complete_invoke(std::forward<Fun>(fun));
|
return Detail::complete_invoke(std::forward<Fun>(fun));
|
||||||
} CATCH_CATCH_ALL{
|
} CATCH_CATCH_ALL{
|
||||||
|
@@ -21,7 +21,7 @@ namespace Catch {
|
|||||||
namespace Benchmark {
|
namespace Benchmark {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
template <typename Clock, typename Fun, typename... Args>
|
template <typename Clock, typename Fun, typename... Args>
|
||||||
TimingOf<Clock, Fun(Args...)> measure(Fun&& fun, Args&&... args) {
|
TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
||||||
auto start = Clock::now();
|
auto start = Clock::now();
|
||||||
auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
|
auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);
|
||||||
auto end = Clock::now();
|
auto end = Clock::now();
|
||||||
|
@@ -25,11 +25,11 @@ namespace Catch {
|
|||||||
namespace Benchmark {
|
namespace Benchmark {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
template <typename Clock, typename Fun>
|
template <typename Clock, typename Fun>
|
||||||
TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) {
|
TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
|
||||||
return Detail::measure<Clock>(fun, iters);
|
return Detail::measure<Clock>(fun, iters);
|
||||||
}
|
}
|
||||||
template <typename Clock, typename Fun>
|
template <typename Clock, typename Fun>
|
||||||
TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) {
|
TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
|
||||||
Detail::ChronometerModel<Clock> meter;
|
Detail::ChronometerModel<Clock> meter;
|
||||||
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
|
auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Clock, typename Fun>
|
template <typename Clock, typename Fun>
|
||||||
TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
|
TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {
|
||||||
auto iters = seed;
|
auto iters = seed;
|
||||||
while (iters < (1 << 30)) {
|
while (iters < (1 << 30)) {
|
||||||
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
|
auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
|
||||||
|
@@ -18,11 +18,13 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Benchmark {
|
namespace Benchmark {
|
||||||
|
@@ -25,8 +25,8 @@ namespace Catch {
|
|||||||
Result result;
|
Result result;
|
||||||
int iterations;
|
int iterations;
|
||||||
};
|
};
|
||||||
template <typename Clock, typename Sig>
|
template <typename Clock, typename Func, typename... Args>
|
||||||
using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<Detail::ResultOf_t<Sig>>>;
|
using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
|
||||||
} // namespace Benchmark
|
} // namespace Benchmark
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "catch_interfaces_registry_hub.h"
|
#include "catch_interfaces_registry_hub.h"
|
||||||
#include "catch_capture_matchers.h"
|
#include "catch_capture_matchers.h"
|
||||||
#include "catch_run_context.h"
|
#include "catch_run_context.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
@@ -41,6 +41,8 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
|
/* The expression should not be evaluated, but warnings should hopefully be checked */ \
|
||||||
|
CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||||
@@ -49,8 +51,7 @@
|
|||||||
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
} while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) )
|
||||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
|
||||||
|
@@ -50,14 +50,13 @@ namespace Catch {
|
|||||||
if( !startsWith( line, '"' ) )
|
if( !startsWith( line, '"' ) )
|
||||||
line = '"' + line + '"';
|
line = '"' + line + '"';
|
||||||
config.testsOrTags.push_back( line );
|
config.testsOrTags.push_back( line );
|
||||||
config.testsOrTags.push_back( "," );
|
config.testsOrTags.emplace_back( "," );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Remove comma in the end
|
//Remove comma in the end
|
||||||
if(!config.testsOrTags.empty())
|
if(!config.testsOrTags.empty())
|
||||||
config.testsOrTags.erase( config.testsOrTags.end()-1 );
|
config.testsOrTags.erase( config.testsOrTags.end()-1 );
|
||||||
|
|
||||||
return ParserResult::ok( ParseResultType::Matched );
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
};
|
};
|
||||||
auto const setTestOrder = [&]( std::string const& order ) {
|
auto const setTestOrder = [&]( std::string const& order ) {
|
||||||
@@ -92,14 +91,16 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
|
auto const setWaitForKeypress = [&]( std::string const& keypress ) {
|
||||||
auto keypressLc = toLower( keypress );
|
auto keypressLc = toLower( keypress );
|
||||||
if( keypressLc == "start" )
|
if (keypressLc == "never")
|
||||||
|
config.waitForKeypress = WaitForKeypress::Never;
|
||||||
|
else if( keypressLc == "start" )
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeStart;
|
config.waitForKeypress = WaitForKeypress::BeforeStart;
|
||||||
else if( keypressLc == "exit" )
|
else if( keypressLc == "exit" )
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeExit;
|
config.waitForKeypress = WaitForKeypress::BeforeExit;
|
||||||
else if( keypressLc == "both" )
|
else if( keypressLc == "both" )
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
|
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
|
||||||
else
|
else
|
||||||
return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
|
return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
|
||||||
return ParserResult::ok( ParseResultType::Matched );
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
};
|
};
|
||||||
auto const setVerbosity = [&]( std::string const& verbosity ) {
|
auto const setVerbosity = [&]( std::string const& verbosity ) {
|
||||||
@@ -169,6 +170,9 @@ namespace Catch {
|
|||||||
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
|
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
|
||||||
["-d"]["--durations"]
|
["-d"]["--durations"]
|
||||||
( "show test durations" )
|
( "show test durations" )
|
||||||
|
| Opt( config.minDuration, "seconds" )
|
||||||
|
["-D"]["--min-duration"]
|
||||||
|
( "show test durations for tests taking at least the given number of seconds" )
|
||||||
| Opt( loadTestNamesFromFile, "filename" )
|
| Opt( loadTestNamesFromFile, "filename" )
|
||||||
["-f"]["--input-file"]
|
["-f"]["--input-file"]
|
||||||
( "load test names to run from a file" )
|
( "load test names to run from a file" )
|
||||||
@@ -199,7 +203,7 @@ namespace Catch {
|
|||||||
| Opt( config.libIdentify )
|
| Opt( config.libIdentify )
|
||||||
["--libidentify"]
|
["--libidentify"]
|
||||||
( "report name and version according to libidentify standard" )
|
( "report name and version according to libidentify standard" )
|
||||||
| Opt( setWaitForKeypress, "start|exit|both" )
|
| Opt( setWaitForKeypress, "never|start|exit|both" )
|
||||||
["--wait-for-keypress"]
|
["--wait-for-keypress"]
|
||||||
( "waits for a keypress before exiting" )
|
( "waits for a keypress before exiting" )
|
||||||
| Opt( config.benchmarkSamples, "samples" )
|
| Opt( config.benchmarkSamples, "samples" )
|
||||||
@@ -214,7 +218,10 @@ namespace Catch {
|
|||||||
| Opt( config.benchmarkNoAnalysis )
|
| Opt( config.benchmarkNoAnalysis )
|
||||||
["--benchmark-no-analysis"]
|
["--benchmark-no-analysis"]
|
||||||
( "perform only measurements; do not perform any analysis" )
|
( "perform only measurements; do not perform any analysis" )
|
||||||
| Arg( config.testsOrTags, "test name|pattern|tags" )
|
| Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
|
||||||
|
["--benchmark-warmup-time"]
|
||||||
|
( "amount of time in milliseconds spent on warming up each test (default: 100)" )
|
||||||
|
| Arg( config.testsOrTags, "test name|pattern|tags" )
|
||||||
( "which test or tests to use" );
|
( "which test or tests to use" );
|
||||||
|
|
||||||
return cli;
|
return cli;
|
||||||
|
@@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CATCH_CPP17_OR_GREATER)
|
#if defined(__cpp_lib_uncaught_exceptions)
|
||||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -48,6 +48,9 @@
|
|||||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
|
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
|
||||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
|
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
|
||||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
|
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
|
||||||
|
|
||||||
|
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
@@ -55,6 +58,22 @@
|
|||||||
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
|
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
|
||||||
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
|
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
|
||||||
|
|
||||||
|
// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
|
||||||
|
// which results in calls to destructors being emitted for each temporary,
|
||||||
|
// without a matching initialization. In practice, this can result in something
|
||||||
|
// like `std::string::~string` being called on an uninitialized value.
|
||||||
|
//
|
||||||
|
// For example, this code will likely segfault under IBM XL:
|
||||||
|
// ```
|
||||||
|
// REQUIRE(std::string("12") + "34" == "1234")
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
|
||||||
|
# if !defined(__ibmxl__)
|
||||||
|
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||||
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
|
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
|
||||||
_Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
|
_Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
|
||||||
@@ -149,9 +168,12 @@
|
|||||||
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
|
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
|
||||||
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
|
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
|
||||||
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
|
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
|
||||||
# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
|
# if !defined(__clang__) // Handle Clang masquerading for msvc
|
||||||
# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
|
||||||
# endif
|
# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
|
||||||
|
# endif // MSVC_TRADITIONAL
|
||||||
|
# endif // __clang__
|
||||||
|
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#if defined(_REENTRANT) || defined(_MSC_VER)
|
#if defined(_REENTRANT) || defined(_MSC_VER)
|
||||||
@@ -200,7 +222,7 @@
|
|||||||
#define CATCH_CONFIG_COLOUR_NONE
|
#define CATCH_CONFIG_COLOUR_NONE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__UCLIBC__)
|
#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
|
||||||
#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
|
#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -218,7 +240,10 @@
|
|||||||
|
|
||||||
// Check if byte is available and usable
|
// Check if byte is available and usable
|
||||||
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
|
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
|
# include <cstddef>
|
||||||
|
# if __cpp_lib_byte > 0
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
|
||||||
|
# endif
|
||||||
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
|
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
|
||||||
// Check if variant is available and usable
|
// Check if variant is available and usable
|
||||||
@@ -329,6 +354,11 @@
|
|||||||
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
|
# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The goal of this macro is to avoid evaluation of the arguments, but
|
||||||
|
// still have the compiler warn on problems inside...
|
||||||
|
#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
|
||||||
|
# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
|
#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
|
||||||
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
|
||||||
|
@@ -64,6 +64,7 @@ namespace Catch {
|
|||||||
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
|
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
|
||||||
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
|
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
|
||||||
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||||
|
double Config::minDuration() const { return m_data.minDuration; }
|
||||||
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||||
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
|
UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
|
||||||
@@ -72,10 +73,11 @@ namespace Catch {
|
|||||||
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
bool Config::showInvisibles() const { return m_data.showInvisibles; }
|
||||||
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||||
|
|
||||||
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
|
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
|
||||||
int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
|
int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
|
||||||
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
|
double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
|
||||||
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
|
unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
|
||||||
|
std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
|
||||||
|
|
||||||
IStream const* Config::openStream() {
|
IStream const* Config::openStream() {
|
||||||
return Catch::makeStream(m_data.outputFilename);
|
return Catch::makeStream(m_data.outputFilename);
|
||||||
|
@@ -47,10 +47,12 @@ namespace Catch {
|
|||||||
unsigned int benchmarkSamples = 100;
|
unsigned int benchmarkSamples = 100;
|
||||||
double benchmarkConfidenceInterval = 0.95;
|
double benchmarkConfidenceInterval = 0.95;
|
||||||
unsigned int benchmarkResamples = 100000;
|
unsigned int benchmarkResamples = 100000;
|
||||||
|
std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
|
||||||
|
|
||||||
Verbosity verbosity = Verbosity::Normal;
|
Verbosity verbosity = Verbosity::Normal;
|
||||||
WarnAbout::What warnings = WarnAbout::Nothing;
|
WarnAbout::What warnings = WarnAbout::Nothing;
|
||||||
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
|
ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
|
||||||
|
double minDuration = -1;
|
||||||
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
|
RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
|
||||||
UseColour::YesOrNo useColour = UseColour::Auto;
|
UseColour::YesOrNo useColour = UseColour::Auto;
|
||||||
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
|
||||||
@@ -102,6 +104,7 @@ namespace Catch {
|
|||||||
bool warnAboutMissingAssertions() const override;
|
bool warnAboutMissingAssertions() const override;
|
||||||
bool warnAboutNoTests() const override;
|
bool warnAboutNoTests() const override;
|
||||||
ShowDurations::OrNot showDurations() const override;
|
ShowDurations::OrNot showDurations() const override;
|
||||||
|
double minDuration() const override;
|
||||||
RunTests::InWhatOrder runOrder() const override;
|
RunTests::InWhatOrder runOrder() const override;
|
||||||
unsigned int rngSeed() const override;
|
unsigned int rngSeed() const override;
|
||||||
UseColour::YesOrNo useColour() const override;
|
UseColour::YesOrNo useColour() const override;
|
||||||
@@ -113,6 +116,7 @@ namespace Catch {
|
|||||||
int benchmarkSamples() const override;
|
int benchmarkSamples() const override;
|
||||||
double benchmarkConfidenceInterval() const override;
|
double benchmarkConfidenceInterval() const override;
|
||||||
unsigned int benchmarkResamples() const override;
|
unsigned int benchmarkResamples() const override;
|
||||||
|
std::chrono::milliseconds benchmarkWarmupTime() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@@ -34,7 +34,7 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct NoColourImpl : IColourImpl {
|
struct NoColourImpl : IColourImpl {
|
||||||
void use( Colour::Code ) {}
|
void use( Colour::Code ) override {}
|
||||||
|
|
||||||
static IColourImpl* instance() {
|
static IColourImpl* instance() {
|
||||||
static NoColourImpl s_instance;
|
static NoColourImpl s_instance;
|
||||||
@@ -167,7 +167,7 @@ namespace {
|
|||||||
|
|
||||||
bool useColourOnPlatform() {
|
bool useColourOnPlatform() {
|
||||||
return
|
return
|
||||||
#ifdef CATCH_PLATFORM_MAC
|
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
|
||||||
!isDebuggerActive() &&
|
!isDebuggerActive() &&
|
||||||
#endif
|
#endif
|
||||||
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
|
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
|
||||||
@@ -208,13 +208,13 @@ namespace Catch {
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
||||||
Colour::Colour( Colour&& rhs ) noexcept {
|
Colour::Colour( Colour&& other ) noexcept {
|
||||||
m_moved = rhs.m_moved;
|
m_moved = other.m_moved;
|
||||||
rhs.m_moved = true;
|
other.m_moved = true;
|
||||||
}
|
}
|
||||||
Colour& Colour::operator=( Colour&& rhs ) noexcept {
|
Colour& Colour::operator=( Colour&& other ) noexcept {
|
||||||
m_moved = rhs.m_moved;
|
m_moved = other.m_moved;
|
||||||
rhs.m_moved = true;
|
other.m_moved = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ namespace Catch {
|
|||||||
// However, under some conditions it does happen (see #1626),
|
// However, under some conditions it does happen (see #1626),
|
||||||
// and this change is small enough that we can let practicality
|
// and this change is small enough that we can let practicality
|
||||||
// triumph over purity in this case.
|
// triumph over purity in this case.
|
||||||
if (impl != NULL) {
|
if (impl != nullptr) {
|
||||||
impl->use( _colourCode );
|
impl->use( _colourCode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,10 +12,9 @@
|
|||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
#include "catch_platform.h"
|
#include "catch_platform.h"
|
||||||
|
|
||||||
#ifdef CATCH_PLATFORM_MAC
|
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
|
||||||
|
|
||||||
# include <assert.h>
|
# include <cassert>
|
||||||
# include <stdbool.h>
|
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# include <cstddef>
|
# include <cstddef>
|
||||||
|
@@ -17,7 +17,24 @@ namespace Catch {
|
|||||||
|
|
||||||
#ifdef CATCH_PLATFORM_MAC
|
#ifdef CATCH_PLATFORM_MAC
|
||||||
|
|
||||||
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define CATCH_TRAP() __asm__(".inst 0xd4200000")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(CATCH_PLATFORM_IPHONE)
|
||||||
|
|
||||||
|
// use inline assembler
|
||||||
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
#define CATCH_TRAP() __asm__("int $3")
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define CATCH_TRAP() __asm__(".inst 0xd4200000")
|
||||||
|
#elif defined(__arm__) && !defined(__thumb__)
|
||||||
|
#define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
|
||||||
|
#elif defined(__arm__) && defined(__thumb__)
|
||||||
|
#define CATCH_TRAP() __asm__(".inst 0xde01")
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif defined(CATCH_PLATFORM_LINUX)
|
#elif defined(CATCH_PLATFORM_LINUX)
|
||||||
// If we can use inline assembler, do it because this allows us to break
|
// If we can use inline assembler, do it because this allows us to break
|
||||||
@@ -37,10 +54,12 @@ namespace Catch {
|
|||||||
#define CATCH_TRAP() DebugBreak()
|
#define CATCH_TRAP() DebugBreak()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CATCH_TRAP
|
#ifndef CATCH_BREAK_INTO_DEBUGGER
|
||||||
#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
|
#ifdef CATCH_TRAP
|
||||||
#else
|
#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
|
||||||
#define CATCH_BREAK_INTO_DEBUGGER() []{}()
|
#else
|
||||||
|
#define CATCH_BREAK_INTO_DEBUGGER() []{}()
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
||||||
|
@@ -200,6 +200,18 @@ namespace Catch {
|
|||||||
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
|
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
|
||||||
}
|
}
|
||||||
|
template <typename RhsT>
|
||||||
|
auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
|
return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };
|
||||||
|
}
|
||||||
|
template <typename RhsT>
|
||||||
|
auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
|
return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };
|
||||||
|
}
|
||||||
|
template <typename RhsT>
|
||||||
|
auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
|
return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };
|
||||||
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
|
@@ -9,10 +9,11 @@
|
|||||||
#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
|
||||||
|
|
||||||
#include "catch_session.h"
|
#include "catch_session.h"
|
||||||
|
#include "catch_platform.h"
|
||||||
|
|
||||||
#ifndef __OBJC__
|
#ifndef __OBJC__
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||||
// Standard C/C++ Win32 Unicode wmain entry point
|
// Standard C/C++ Win32 Unicode wmain entry point
|
||||||
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||||
#else
|
#else
|
||||||
|
@@ -60,7 +60,7 @@ namespace Catch {
|
|||||||
assert( valueNames.size() == values.size() );
|
assert( valueNames.size() == values.size() );
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
for( auto value : values )
|
for( auto value : values )
|
||||||
enumInfo->m_values.push_back({ value, valueNames[i++] });
|
enumInfo->m_values.emplace_back(value, valueNames[i++]);
|
||||||
|
|
||||||
return enumInfo;
|
return enumInfo;
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,8 @@ namespace Generators {
|
|||||||
|
|
||||||
GeneratorUntypedBase::~GeneratorUntypedBase() {}
|
GeneratorUntypedBase::~GeneratorUntypedBase() {}
|
||||||
|
|
||||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||||
return getResultCapture().acquireGeneratorTracker( lineInfo );
|
return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Generators
|
} // namespace Generators
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include "catch_interfaces_generatortracker.h"
|
#include "catch_interfaces_generatortracker.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_enforce.h"
|
#include "catch_enforce.h"
|
||||||
|
#include "catch_stringref.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -57,7 +58,6 @@ namespace Generators {
|
|||||||
class SingleValueGenerator final : public IGenerator<T> {
|
class SingleValueGenerator final : public IGenerator<T> {
|
||||||
T m_value;
|
T m_value;
|
||||||
public:
|
public:
|
||||||
SingleValueGenerator(T const& value) : m_value( value ) {}
|
|
||||||
SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
|
SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
|
||||||
|
|
||||||
T const& get() const override {
|
T const& get() const override {
|
||||||
@@ -120,21 +120,21 @@ namespace Generators {
|
|||||||
m_generators.emplace_back(std::move(generator));
|
m_generators.emplace_back(std::move(generator));
|
||||||
}
|
}
|
||||||
void populate(T&& val) {
|
void populate(T&& val) {
|
||||||
m_generators.emplace_back(value(std::move(val)));
|
m_generators.emplace_back(value(std::forward<T>(val)));
|
||||||
}
|
}
|
||||||
template<typename U>
|
template<typename U>
|
||||||
void populate(U&& val) {
|
void populate(U&& val) {
|
||||||
populate(T(std::move(val)));
|
populate(T(std::forward<U>(val)));
|
||||||
}
|
}
|
||||||
template<typename U, typename... Gs>
|
template<typename U, typename... Gs>
|
||||||
void populate(U&& valueOrGenerator, Gs... moreGenerators) {
|
void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {
|
||||||
populate(std::forward<U>(valueOrGenerator));
|
populate(std::forward<U>(valueOrGenerator));
|
||||||
populate(std::forward<Gs>(moreGenerators)...);
|
populate(std::forward<Gs>(moreGenerators)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... Gs>
|
template <typename... Gs>
|
||||||
Generators(Gs... moreGenerators) {
|
Generators(Gs &&... moreGenerators) {
|
||||||
m_generators.reserve(sizeof...(Gs));
|
m_generators.reserve(sizeof...(Gs));
|
||||||
populate(std::forward<Gs>(moreGenerators)...);
|
populate(std::forward<Gs>(moreGenerators)...);
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ namespace Generators {
|
|||||||
struct as {};
|
struct as {};
|
||||||
|
|
||||||
template<typename T, typename... Gs>
|
template<typename T, typename... Gs>
|
||||||
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
|
auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
|
||||||
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
|
return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -174,24 +174,24 @@ namespace Generators {
|
|||||||
return Generators<T>(std::move(generator));
|
return Generators<T>(std::move(generator));
|
||||||
}
|
}
|
||||||
template<typename T, typename... Gs>
|
template<typename T, typename... Gs>
|
||||||
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
|
auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {
|
||||||
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
|
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
}
|
}
|
||||||
template<typename T, typename U, typename... Gs>
|
template<typename T, typename U, typename... Gs>
|
||||||
auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
|
auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
|
||||||
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||||
|
|
||||||
template<typename L>
|
template<typename L>
|
||||||
// Note: The type after -> is weird, because VS2015 cannot parse
|
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||||
// the expression used in the typedef inside, when it is in
|
// the expression used in the typedef inside, when it is in
|
||||||
// return type. Yeah.
|
// return type. Yeah.
|
||||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||||
|
|
||||||
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||||
if (!tracker.hasGenerator()) {
|
if (!tracker.hasGenerator()) {
|
||||||
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
|
tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
|
||||||
}
|
}
|
||||||
@@ -204,10 +204,16 @@ namespace Generators {
|
|||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
#define GENERATE( ... ) \
|
#define GENERATE( ... ) \
|
||||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
#define GENERATE_COPY( ... ) \
|
#define GENERATE_COPY( ... ) \
|
||||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
#define GENERATE_REF( ... ) \
|
#define GENERATE_REF( ... ) \
|
||||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
@@ -44,7 +44,7 @@ namespace Catch {
|
|||||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
||||||
|
|
||||||
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||||
virtual void benchmarkPreparing( std::string const& name ) = 0;
|
virtual void benchmarkPreparing( std::string const& name ) = 0;
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_option.hpp"
|
#include "catch_option.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -68,6 +69,7 @@ namespace Catch {
|
|||||||
virtual int abortAfter() const = 0;
|
virtual int abortAfter() const = 0;
|
||||||
virtual bool showInvisibles() const = 0;
|
virtual bool showInvisibles() const = 0;
|
||||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||||
|
virtual double minDuration() const = 0;
|
||||||
virtual TestSpec const& testSpec() const = 0;
|
virtual TestSpec const& testSpec() const = 0;
|
||||||
virtual bool hasTestFilters() const = 0;
|
virtual bool hasTestFilters() const = 0;
|
||||||
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
|
virtual std::vector<std::string> const& getTestsOrTags() const = 0;
|
||||||
@@ -81,6 +83,7 @@ namespace Catch {
|
|||||||
virtual int benchmarkSamples() const = 0;
|
virtual int benchmarkSamples() const = 0;
|
||||||
virtual double benchmarkConfidenceInterval() const = 0;
|
virtual double benchmarkConfidenceInterval() const = 0;
|
||||||
virtual unsigned int benchmarkResamples() const = 0;
|
virtual unsigned int benchmarkResamples() const = 0;
|
||||||
|
virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using IConfigPtr = std::shared_ptr<IConfig const>;
|
using IConfigPtr = std::shared_ptr<IConfig const>;
|
||||||
|
@@ -46,6 +46,9 @@ namespace Catch {
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
|
std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
return "";
|
||||||
|
#else
|
||||||
try {
|
try {
|
||||||
if( it == itEnd )
|
if( it == itEnd )
|
||||||
std::rethrow_exception(std::current_exception());
|
std::rethrow_exception(std::current_exception());
|
||||||
@@ -55,6 +58,7 @@ namespace Catch {
|
|||||||
catch( T& ex ) {
|
catch( T& ex ) {
|
||||||
return m_translateFunction( ex );
|
return m_translateFunction( ex );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
std::size_t listTests( Config const& config ) {
|
std::size_t listTests( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec const& testSpec = config.testSpec();
|
||||||
if( config.hasTestFilters() )
|
if( config.hasTestFilters() )
|
||||||
Catch::cout() << "Matching test cases:\n";
|
Catch::cout() << "Matching test cases:\n";
|
||||||
else {
|
else {
|
||||||
@@ -62,7 +62,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::size_t listTestsNamesOnly( Config const& config ) {
|
std::size_t listTestsNamesOnly( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec const& testSpec = config.testSpec();
|
||||||
std::size_t matchedTests = 0;
|
std::size_t matchedTests = 0;
|
||||||
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||||
for( auto const& testCaseInfo : matchedTestCases ) {
|
for( auto const& testCaseInfo : matchedTestCases ) {
|
||||||
@@ -100,7 +100,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::size_t listTags( Config const& config ) {
|
std::size_t listTags( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec const& testSpec = config.testSpec();
|
||||||
if( config.hasTestFilters() )
|
if( config.hasTestFilters() )
|
||||||
Catch::cout() << "Tags for matching test cases:\n";
|
Catch::cout() << "Tags for matching test cases:\n";
|
||||||
else {
|
else {
|
||||||
|
@@ -91,9 +91,10 @@ namespace Matchers {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
|
MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {
|
||||||
m_matchers.push_back( &other );
|
auto copy(*this);
|
||||||
return *this;
|
copy.m_matchers.push_back( &other );
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||||
@@ -124,9 +125,10 @@ namespace Matchers {
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
|
MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {
|
||||||
m_matchers.push_back( &other );
|
auto copy(*this);
|
||||||
return *this;
|
copy.m_matchers.push_back( &other );
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||||
|
@@ -59,16 +59,8 @@ namespace {
|
|||||||
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
|
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end anonymous namespace
|
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
// The long double overload is currently unused
|
|
||||||
#pragma clang diagnostic ignored "-Wunused-function"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float nextafter(float x, float y) {
|
float nextafter(float x, float y) {
|
||||||
return ::nextafterf(x, y);
|
return ::nextafterf(x, y);
|
||||||
}
|
}
|
||||||
@@ -77,18 +69,8 @@ namespace {
|
|||||||
return ::nextafter(x, y);
|
return ::nextafter(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
long double nextafter(long double x, long double y) {
|
|
||||||
return ::nextafterl(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
|
#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <typename FP>
|
template <typename FP>
|
||||||
FP step(FP start, FP direction, uint64_t steps) {
|
FP step(FP start, FP direction, uint64_t steps) {
|
||||||
for (uint64_t i = 0; i < steps; ++i) {
|
for (uint64_t i = 0; i < steps; ++i) {
|
||||||
|
@@ -17,12 +17,12 @@ namespace Catch {
|
|||||||
namespace Matchers {
|
namespace Matchers {
|
||||||
|
|
||||||
namespace Vector {
|
namespace Vector {
|
||||||
template<typename T>
|
template<typename T, typename Alloc>
|
||||||
struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
|
struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {
|
||||||
|
|
||||||
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
||||||
|
|
||||||
bool match(std::vector<T> const &v) const override {
|
bool match(std::vector<T, Alloc> const &v) const override {
|
||||||
for (auto const& el : v) {
|
for (auto const& el : v) {
|
||||||
if (el == m_comparator) {
|
if (el == m_comparator) {
|
||||||
return true;
|
return true;
|
||||||
@@ -38,12 +38,12 @@ namespace Matchers {
|
|||||||
T const& m_comparator;
|
T const& m_comparator;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp, typename AllocMatch>
|
||||||
struct ContainsMatcher : MatcherBase<std::vector<T>> {
|
struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
||||||
|
|
||||||
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
|
||||||
|
|
||||||
bool match(std::vector<T> const &v) const override {
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
||||||
// !TBD: see note in EqualsMatcher
|
// !TBD: see note in EqualsMatcher
|
||||||
if (m_comparator.size() > v.size())
|
if (m_comparator.size() > v.size())
|
||||||
return false;
|
return false;
|
||||||
@@ -65,18 +65,18 @@ namespace Matchers {
|
|||||||
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
|
return "Contains: " + ::Catch::Detail::stringify( m_comparator );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<T> const& m_comparator;
|
std::vector<T, AllocComp> const& m_comparator;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp, typename AllocMatch>
|
||||||
struct EqualsMatcher : MatcherBase<std::vector<T>> {
|
struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
||||||
|
|
||||||
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}
|
||||||
|
|
||||||
bool match(std::vector<T> const &v) const override {
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
||||||
// !TBD: This currently works if all elements can be compared using !=
|
// !TBD: This currently works if all elements can be compared using !=
|
||||||
// - a more general approach would be via a compare template that defaults
|
// - a more general approach would be via a compare template that defaults
|
||||||
// to using !=. but could be specialised for, e.g. std::vector<T> etc
|
// to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc
|
||||||
// - then just call that directly
|
// - then just call that directly
|
||||||
if (m_comparator.size() != v.size())
|
if (m_comparator.size() != v.size())
|
||||||
return false;
|
return false;
|
||||||
@@ -88,15 +88,15 @@ namespace Matchers {
|
|||||||
std::string describe() const override {
|
std::string describe() const override {
|
||||||
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
|
return "Equals: " + ::Catch::Detail::stringify( m_comparator );
|
||||||
}
|
}
|
||||||
std::vector<T> const& m_comparator;
|
std::vector<T, AllocComp> const& m_comparator;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp, typename AllocMatch>
|
||||||
struct ApproxMatcher : MatcherBase<std::vector<T>> {
|
struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
||||||
|
|
||||||
ApproxMatcher(std::vector<T> const& comparator) : m_comparator( comparator ) {}
|
ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}
|
||||||
|
|
||||||
bool match(std::vector<T> const &v) const override {
|
bool match(std::vector<T, AllocMatch> const &v) const override {
|
||||||
if (m_comparator.size() != v.size())
|
if (m_comparator.size() != v.size())
|
||||||
return false;
|
return false;
|
||||||
for (std::size_t i = 0; i < v.size(); ++i)
|
for (std::size_t i = 0; i < v.size(); ++i)
|
||||||
@@ -123,16 +123,14 @@ namespace Matchers {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<T> const& m_comparator;
|
std::vector<T, AllocComp> const& m_comparator;
|
||||||
mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
|
mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp, typename AllocMatch>
|
||||||
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
|
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {
|
||||||
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
|
UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}
|
||||||
bool match(std::vector<T> const& vec) const override {
|
bool match(std::vector<T, AllocMatch> const& vec) const override {
|
||||||
// Note: This is a reimplementation of std::is_permutation,
|
|
||||||
// because I don't want to include <algorithm> inside the common path
|
|
||||||
if (m_target.size() != vec.size()) {
|
if (m_target.size() != vec.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -143,7 +141,7 @@ namespace Matchers {
|
|||||||
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
|
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::vector<T> const& m_target;
|
std::vector<T, AllocComp> const& m_target;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vector
|
} // namespace Vector
|
||||||
@@ -151,29 +149,29 @@ namespace Matchers {
|
|||||||
// The following functions create the actual matcher objects.
|
// The following functions create the actual matcher objects.
|
||||||
// This allows the types to be inferred
|
// This allows the types to be inferred
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
||||||
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
|
Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
|
||||||
return Vector::ContainsMatcher<T>( comparator );
|
return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename Alloc = std::allocator<T>>
|
||||||
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
|
Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
|
||||||
return Vector::ContainsElementMatcher<T>( comparator );
|
return Vector::ContainsElementMatcher<T, Alloc>( comparator );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
||||||
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
|
Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
|
||||||
return Vector::EqualsMatcher<T>( comparator );
|
return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
||||||
Vector::ApproxMatcher<T> Approx( std::vector<T> const& comparator ) {
|
Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
|
||||||
return Vector::ApproxMatcher<T>( comparator );
|
return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
|
||||||
Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
|
Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
|
||||||
return Vector::UnorderedEqualsMatcher<T>(target);
|
return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Matchers
|
} // namespace Matchers
|
||||||
|
@@ -69,10 +69,10 @@ namespace Catch {
|
|||||||
|
|
||||||
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
|
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
|
||||||
auto trimmed = [&] (size_t start, size_t end) {
|
auto trimmed = [&] (size_t start, size_t end) {
|
||||||
while (names[start] == ',' || isspace(names[start])) {
|
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
|
||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
while (names[end] == ',' || isspace(names[end])) {
|
while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
|
||||||
--end;
|
--end;
|
||||||
}
|
}
|
||||||
return names.substr(start, end - start + 1);
|
return names.substr(start, end - start + 1);
|
||||||
@@ -111,7 +111,7 @@ namespace Catch {
|
|||||||
pos = skipq(pos, c);
|
pos = skipq(pos, c);
|
||||||
break;
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
if (start != pos && openings.size() == 0) {
|
if (start != pos && openings.empty()) {
|
||||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||||
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
|
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
|
||||||
m_messages.back().message += " := ";
|
m_messages.back().message += " := ";
|
||||||
@@ -119,7 +119,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(openings.size() == 0 && "Mismatched openings");
|
assert(openings.empty() && "Mismatched openings");
|
||||||
m_messages.emplace_back(macroName, lineInfo, resultType);
|
m_messages.emplace_back(macroName, lineInfo, resultType);
|
||||||
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
|
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
|
||||||
m_messages.back().message += " := ";
|
m_messages.back().message += " := ";
|
||||||
|
@@ -32,13 +32,13 @@ namespace Catch {
|
|||||||
|
|
||||||
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
|
||||||
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
|
||||||
// replaced with std::invoke_result here. Also *_t format is preferred over
|
// replaced with std::invoke_result here.
|
||||||
// typename *::type format.
|
template <typename Func, typename... U>
|
||||||
template <typename Func, typename U>
|
using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
|
||||||
using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
|
|
||||||
#else
|
#else
|
||||||
template <typename Func, typename U>
|
// Keep ::type here because we still support C++11
|
||||||
using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
|
template <typename Func, typename... U>
|
||||||
|
using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Jozef on 12/11/2018.
|
* Created by Jozef on 12/11/2018.
|
||||||
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
* Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
@@ -90,7 +91,7 @@
|
|||||||
#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
|
#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
|
#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
|
#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6)
|
#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
|
#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
|
#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
|
||||||
#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
|
#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
|
||||||
|
@@ -59,7 +59,11 @@ namespace Catch {
|
|||||||
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||||
}
|
}
|
||||||
void registerStartupException() noexcept override {
|
void registerStartupException() noexcept override {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
m_exceptionRegistry.add(std::current_exception());
|
m_exceptionRegistry.add(std::current_exception());
|
||||||
|
#else
|
||||||
|
CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
|
||||||
return m_enumValuesRegistry;
|
return m_enumValuesRegistry;
|
||||||
|
@@ -25,17 +25,32 @@ namespace Catch {
|
|||||||
std::shared_ptr<GeneratorTracker> tracker;
|
std::shared_ptr<GeneratorTracker> tracker;
|
||||||
|
|
||||||
ITracker& currentTracker = ctx.currentTracker();
|
ITracker& currentTracker = ctx.currentTracker();
|
||||||
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
// Under specific circumstances, the generator we want
|
||||||
|
// to acquire is also the current tracker. If this is
|
||||||
|
// the case, we have to avoid looking through current
|
||||||
|
// tracker's children, and instead return the current
|
||||||
|
// tracker.
|
||||||
|
// A case where this check is important is e.g.
|
||||||
|
// for (int i = 0; i < 5; ++i) {
|
||||||
|
// int n = GENERATE(1, 2);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// without it, the code above creates 5 nested generators.
|
||||||
|
if (currentTracker.nameAndLocation() == nameAndLocation) {
|
||||||
|
auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
|
||||||
|
assert(thisTracker);
|
||||||
|
assert(thisTracker->isGeneratorTracker());
|
||||||
|
tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
|
||||||
|
} else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||||
assert( childTracker );
|
assert( childTracker );
|
||||||
assert( childTracker->isGeneratorTracker() );
|
assert( childTracker->isGeneratorTracker() );
|
||||||
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );
|
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );
|
||||||
currentTracker.addChild( tracker );
|
currentTracker.addChild( tracker );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
if( !tracker->isComplete() ) {
|
||||||
tracker->open();
|
tracker->open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +64,28 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
void close() override {
|
void close() override {
|
||||||
TrackerBase::close();
|
TrackerBase::close();
|
||||||
// Generator interface only finds out if it has another item on atual move
|
// If a generator has a child (it is followed by a section)
|
||||||
if (m_runState == CompletedSuccessfully && m_generator->next()) {
|
// and none of its children have started, then we must wait
|
||||||
|
// until later to start consuming its values.
|
||||||
|
// This catches cases where `GENERATE` is placed between two
|
||||||
|
// `SECTION`s.
|
||||||
|
// **The check for m_children.empty cannot be removed**.
|
||||||
|
// doing so would break `GENERATE` _not_ followed by `SECTION`s.
|
||||||
|
const bool should_wait_for_child =
|
||||||
|
!m_children.empty() &&
|
||||||
|
std::find_if( m_children.begin(),
|
||||||
|
m_children.end(),
|
||||||
|
[]( TestCaseTracking::ITrackerPtr tracker ) {
|
||||||
|
return tracker->hasStarted();
|
||||||
|
} ) == m_children.end();
|
||||||
|
|
||||||
|
// This check is a bit tricky, because m_generator->next()
|
||||||
|
// has a side-effect, where it consumes generator's current
|
||||||
|
// value, but we do not want to invoke the side-effect if
|
||||||
|
// this generator is still waiting for any child to start.
|
||||||
|
if ( should_wait_for_child ||
|
||||||
|
( m_runState == CompletedSuccessfully &&
|
||||||
|
m_generator->next() ) ) {
|
||||||
m_children.clear();
|
m_children.clear();
|
||||||
m_runState = Executing;
|
m_runState = Executing;
|
||||||
}
|
}
|
||||||
@@ -187,10 +222,10 @@ namespace Catch {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||||
using namespace Generators;
|
using namespace Generators;
|
||||||
GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
|
GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
|
||||||
assert( tracker.isOpen() );
|
TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
|
||||||
m_lastAssertionInfo.lineInfo = lineInfo;
|
m_lastAssertionInfo.lineInfo = lineInfo;
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
@@ -233,17 +268,17 @@ namespace Catch {
|
|||||||
|
|
||||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||||
void RunContext::benchmarkPreparing(std::string const& name) {
|
void RunContext::benchmarkPreparing(std::string const& name) {
|
||||||
m_reporter->benchmarkPreparing(name);
|
m_reporter->benchmarkPreparing(name);
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
|
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
|
||||||
m_reporter->benchmarkStarting( info );
|
m_reporter->benchmarkStarting( info );
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
|
void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
|
||||||
m_reporter->benchmarkEnded( stats );
|
m_reporter->benchmarkEnded( stats );
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkFailed(std::string const & error) {
|
void RunContext::benchmarkFailed(std::string const & error) {
|
||||||
m_reporter->benchmarkFailed(error);
|
m_reporter->benchmarkFailed(error);
|
||||||
}
|
}
|
||||||
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
|
||||||
|
|
||||||
void RunContext::pushScopedMessage(MessageInfo const & message) {
|
void RunContext::pushScopedMessage(MessageInfo const & message) {
|
||||||
|
@@ -80,7 +80,7 @@ namespace Catch {
|
|||||||
void sectionEnded( SectionEndInfo const& endInfo ) override;
|
void sectionEnded( SectionEndInfo const& endInfo ) override;
|
||||||
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
|
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
|
||||||
|
|
||||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
|
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||||
void benchmarkPreparing( std::string const& name ) override;
|
void benchmarkPreparing( std::string const& name ) override;
|
||||||
|
@@ -69,7 +69,7 @@ namespace Catch {
|
|||||||
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
auto const& allTestCases = getAllTestCasesSorted(*m_config);
|
||||||
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
|
m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
|
||||||
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
|
||||||
|
|
||||||
if (m_matches.empty() && invalidArgs.empty()) {
|
if (m_matches.empty() && invalidArgs.empty()) {
|
||||||
for (auto const& test : allTestCases)
|
for (auto const& test : allTestCases)
|
||||||
if (!test.isHidden())
|
if (!test.isHidden())
|
||||||
@@ -97,12 +97,12 @@ namespace Catch {
|
|||||||
totals.error = -1;
|
totals.error = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!invalidArgs.empty()) {
|
if (!invalidArgs.empty()) {
|
||||||
for (auto const& invalidArg: invalidArgs)
|
for (auto const& invalidArg: invalidArgs)
|
||||||
m_context.reporter().reportInvalidArguments(invalidArg);
|
m_context.reporter().reportInvalidArguments(invalidArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
|
m_context.testGroupEnded(m_config->name(), totals, 1, 1);
|
||||||
return totals;
|
return totals;
|
||||||
}
|
}
|
||||||
@@ -220,11 +220,11 @@ namespace Catch {
|
|||||||
char **utf8Argv = new char *[ argc ];
|
char **utf8Argv = new char *[ argc ];
|
||||||
|
|
||||||
for ( int i = 0; i < argc; ++i ) {
|
for ( int i = 0; i < argc; ++i ) {
|
||||||
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
|
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
|
||||||
|
|
||||||
utf8Argv[ i ] = new char[ bufSize ];
|
utf8Argv[ i ] = new char[ bufSize ];
|
||||||
|
|
||||||
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
|
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
int returnCode = applyCommandLine( argc, utf8Argv );
|
int returnCode = applyCommandLine( argc, utf8Argv );
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include "catch_startup_exception_registry.h"
|
#include "catch_startup_exception_registry.h"
|
||||||
#include "catch_compiler_capabilities.h"
|
#include "catch_compiler_capabilities.h"
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
|
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
|
||||||
CATCH_TRY {
|
CATCH_TRY {
|
||||||
@@ -24,3 +25,4 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
#endif
|
||||||
|
@@ -15,11 +15,13 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
class StartupExceptionRegistry {
|
class StartupExceptionRegistry {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
public:
|
public:
|
||||||
void add(std::exception_ptr const& exception) noexcept;
|
void add(std::exception_ptr const& exception) noexcept;
|
||||||
std::vector<std::exception_ptr> const& getExceptions() const noexcept;
|
std::vector<std::exception_ptr> const& getExceptions() const noexcept;
|
||||||
private:
|
private:
|
||||||
std::vector<std::exception_ptr> m_exceptions;
|
std::vector<std::exception_ptr> m_exceptions;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_common.h"
|
||||||
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@@ -28,7 +30,7 @@ namespace Catch {
|
|||||||
|
|
||||||
auto makeStream( StringRef const &filename ) -> IStream const*;
|
auto makeStream( StringRef const &filename ) -> IStream const*;
|
||||||
|
|
||||||
class ReusableStringStream {
|
class ReusableStringStream : NonCopyable {
|
||||||
std::size_t m_index;
|
std::size_t m_index;
|
||||||
std::ostream* m_oss;
|
std::ostream* m_oss;
|
||||||
public:
|
public:
|
||||||
|
@@ -18,7 +18,7 @@ namespace Catch {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
char toLowerCh(char c) {
|
char toLowerCh(char c) {
|
||||||
return static_cast<char>( std::tolower( c ) );
|
return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -89,7 +89,8 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( isHidden ) {
|
if( isHidden ) {
|
||||||
tags.push_back( "." );
|
// Add all "hidden" tags to make them behave identically
|
||||||
|
tags.insert( tags.end(), { ".", "!hide" } );
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
|
TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );
|
||||||
|
@@ -15,27 +15,78 @@
|
|||||||
#include "catch_string_manip.h"
|
#include "catch_string_manip.h"
|
||||||
#include "catch_test_case_info.h"
|
#include "catch_test_case_info.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct TestHasher {
|
||||||
|
explicit TestHasher(Catch::SimplePcg32& rng) {
|
||||||
|
basis = rng();
|
||||||
|
basis <<= 32;
|
||||||
|
basis |= rng();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t basis;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
hash ^= c;
|
||||||
|
hash *= prime;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
||||||
|
|
||||||
std::vector<TestCase> sorted = unsortedTestCases;
|
|
||||||
|
|
||||||
switch( config.runOrder() ) {
|
switch( config.runOrder() ) {
|
||||||
case RunTests::InLexicographicalOrder:
|
|
||||||
std::sort( sorted.begin(), sorted.end() );
|
|
||||||
break;
|
|
||||||
case RunTests::InRandomOrder:
|
|
||||||
seedRng( config );
|
|
||||||
std::shuffle( sorted.begin(), sorted.end(), rng() );
|
|
||||||
break;
|
|
||||||
case RunTests::InDeclarationOrder:
|
case RunTests::InDeclarationOrder:
|
||||||
// already in declaration order
|
// already in declaration order
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RunTests::InLexicographicalOrder: {
|
||||||
|
std::vector<TestCase> sorted = unsortedTestCases;
|
||||||
|
std::sort( sorted.begin(), sorted.end() );
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RunTests::InRandomOrder: {
|
||||||
|
seedRng( config );
|
||||||
|
TestHasher h( rng() );
|
||||||
|
|
||||||
|
using hashedTest = std::pair<uint64_t, TestCase const*>;
|
||||||
|
std::vector<hashedTest> indexed_tests;
|
||||||
|
indexed_tests.reserve( unsortedTestCases.size() );
|
||||||
|
|
||||||
|
for (auto const& testCase : unsortedTestCases) {
|
||||||
|
indexed_tests.emplace_back(h(testCase), &testCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(indexed_tests.begin(), indexed_tests.end(),
|
||||||
|
[](hashedTest const& lhs, hashedTest const& rhs) {
|
||||||
|
if (lhs.first == rhs.first) {
|
||||||
|
return lhs.second->name < rhs.second->name;
|
||||||
|
}
|
||||||
|
return lhs.first < rhs.first;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<TestCase> sorted;
|
||||||
|
sorted.reserve( indexed_tests.size() );
|
||||||
|
|
||||||
|
for (auto const& hashed : indexed_tests) {
|
||||||
|
sorted.emplace_back(*hashed.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sorted;
|
return unsortedTestCases;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
|
bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {
|
||||||
|
@@ -65,15 +65,12 @@ namespace TestCaseTracking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
|
||||||
: m_nameAndLocation( nameAndLocation ),
|
ITracker(nameAndLocation),
|
||||||
m_ctx( ctx ),
|
m_ctx( ctx ),
|
||||||
m_parent( parent )
|
m_parent( parent )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
NameAndLocation const& TrackerBase::nameAndLocation() const {
|
|
||||||
return m_nameAndLocation;
|
|
||||||
}
|
|
||||||
bool TrackerBase::isComplete() const {
|
bool TrackerBase::isComplete() const {
|
||||||
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
||||||
}
|
}
|
||||||
@@ -190,7 +187,8 @@ namespace TestCaseTracking {
|
|||||||
bool SectionTracker::isComplete() const {
|
bool SectionTracker::isComplete() const {
|
||||||
bool complete = true;
|
bool complete = true;
|
||||||
|
|
||||||
if ((m_filters.empty() || m_filters[0] == "")
|
if (m_filters.empty()
|
||||||
|
|| m_filters[0] == ""
|
||||||
|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
|
|| std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
|
||||||
complete = TrackerBase::isComplete();
|
complete = TrackerBase::isComplete();
|
||||||
}
|
}
|
||||||
@@ -225,8 +223,8 @@ namespace TestCaseTracking {
|
|||||||
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
|
void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
|
||||||
if( !filters.empty() ) {
|
if( !filters.empty() ) {
|
||||||
m_filters.reserve( m_filters.size() + filters.size() + 2 );
|
m_filters.reserve( m_filters.size() + filters.size() + 2 );
|
||||||
m_filters.push_back(""); // Root - should never be consulted
|
m_filters.emplace_back(""); // Root - should never be consulted
|
||||||
m_filters.push_back(""); // Test Case - not a section filter
|
m_filters.emplace_back(""); // Test Case - not a section filter
|
||||||
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,23 +23,39 @@ namespace TestCaseTracking {
|
|||||||
SourceLineInfo location;
|
SourceLineInfo location;
|
||||||
|
|
||||||
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
|
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
|
||||||
|
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
|
||||||
|
return lhs.name == rhs.name
|
||||||
|
&& lhs.location == rhs.location;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ITracker;
|
class ITracker;
|
||||||
|
|
||||||
using ITrackerPtr = std::shared_ptr<ITracker>;
|
using ITrackerPtr = std::shared_ptr<ITracker>;
|
||||||
|
|
||||||
struct ITracker {
|
class ITracker {
|
||||||
virtual ~ITracker();
|
NameAndLocation m_nameAndLocation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ITracker(NameAndLocation const& nameAndLoc) :
|
||||||
|
m_nameAndLocation(nameAndLoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
// static queries
|
// static queries
|
||||||
virtual NameAndLocation const& nameAndLocation() const = 0;
|
NameAndLocation const& nameAndLocation() const {
|
||||||
|
return m_nameAndLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ITracker();
|
||||||
|
|
||||||
|
|
||||||
// dynamic queries
|
// dynamic queries
|
||||||
virtual bool isComplete() const = 0; // Successfully completed or failed
|
virtual bool isComplete() const = 0; // Successfully completed or failed
|
||||||
virtual bool isSuccessfullyCompleted() const = 0;
|
virtual bool isSuccessfullyCompleted() const = 0;
|
||||||
virtual bool isOpen() const = 0; // Started but not complete
|
virtual bool isOpen() const = 0; // Started but not complete
|
||||||
virtual bool hasChildren() const = 0;
|
virtual bool hasChildren() const = 0;
|
||||||
|
virtual bool hasStarted() const = 0;
|
||||||
|
|
||||||
virtual ITracker& parent() = 0;
|
virtual ITracker& parent() = 0;
|
||||||
|
|
||||||
@@ -94,7 +110,6 @@ namespace TestCaseTracking {
|
|||||||
};
|
};
|
||||||
|
|
||||||
using Children = std::vector<ITrackerPtr>;
|
using Children = std::vector<ITrackerPtr>;
|
||||||
NameAndLocation m_nameAndLocation;
|
|
||||||
TrackerContext& m_ctx;
|
TrackerContext& m_ctx;
|
||||||
ITracker* m_parent;
|
ITracker* m_parent;
|
||||||
Children m_children;
|
Children m_children;
|
||||||
@@ -103,12 +118,13 @@ namespace TestCaseTracking {
|
|||||||
public:
|
public:
|
||||||
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||||
|
|
||||||
NameAndLocation const& nameAndLocation() const override;
|
|
||||||
bool isComplete() const override;
|
bool isComplete() const override;
|
||||||
bool isSuccessfullyCompleted() const override;
|
bool isSuccessfullyCompleted() const override;
|
||||||
bool isOpen() const override;
|
bool isOpen() const override;
|
||||||
bool hasChildren() const override;
|
bool hasChildren() const override;
|
||||||
|
bool hasStarted() const override {
|
||||||
|
return m_runState != NotStarted;
|
||||||
|
}
|
||||||
|
|
||||||
void addChild( ITrackerPtr const& child ) override;
|
void addChild( ITrackerPtr const& child ) override;
|
||||||
|
|
||||||
|
@@ -160,7 +160,7 @@ struct AutoReg : NonCopyable {
|
|||||||
int index = 0; \
|
int index = 0; \
|
||||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
|
||||||
using expander = int[];\
|
using expander = int[];\
|
||||||
(void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
|
(void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
|
||||||
}\
|
}\
|
||||||
};\
|
};\
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||||
@@ -206,7 +206,7 @@ struct AutoReg : NonCopyable {
|
|||||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||||
@@ -250,7 +250,7 @@ struct AutoReg : NonCopyable {
|
|||||||
void reg_tests() { \
|
void reg_tests() { \
|
||||||
int index = 0; \
|
int index = 0; \
|
||||||
using expander = int[]; \
|
using expander = int[]; \
|
||||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
|
||||||
} \
|
} \
|
||||||
};\
|
};\
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
|
||||||
@@ -285,7 +285,7 @@ struct AutoReg : NonCopyable {
|
|||||||
int index = 0; \
|
int index = 0; \
|
||||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
|
||||||
using expander = int[];\
|
using expander = int[];\
|
||||||
(void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \
|
(void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
|
||||||
}\
|
}\
|
||||||
};\
|
};\
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||||
@@ -334,7 +334,7 @@ struct AutoReg : NonCopyable {
|
|||||||
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
|
||||||
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
|
||||||
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
|
||||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \
|
||||||
}\
|
}\
|
||||||
};\
|
};\
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||||
@@ -381,7 +381,7 @@ struct AutoReg : NonCopyable {
|
|||||||
void reg_tests(){\
|
void reg_tests(){\
|
||||||
int index = 0;\
|
int index = 0;\
|
||||||
using expander = int[];\
|
using expander = int[];\
|
||||||
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \
|
(void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
|
||||||
}\
|
}\
|
||||||
};\
|
};\
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
|
||||||
|
@@ -20,10 +20,10 @@ namespace Catch {
|
|||||||
m_substring.reserve(m_arg.size());
|
m_substring.reserve(m_arg.size());
|
||||||
m_patternName.reserve(m_arg.size());
|
m_patternName.reserve(m_arg.size());
|
||||||
m_realPatternPos = 0;
|
m_realPatternPos = 0;
|
||||||
|
|
||||||
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
|
||||||
//if visitChar fails
|
//if visitChar fails
|
||||||
if( !visitChar( m_arg[m_pos] ) ){
|
if( !visitChar( m_arg[m_pos] ) ){
|
||||||
m_testSpec.m_invalidArgs.push_back(arg);
|
m_testSpec.m_invalidArgs.push_back(arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ namespace Catch {
|
|||||||
switch( m_mode ) {
|
switch( m_mode ) {
|
||||||
case Name:
|
case Name:
|
||||||
case QuotedName:
|
case QuotedName:
|
||||||
return addPattern<TestSpec::NamePattern>();
|
return addNamePattern();
|
||||||
case Tag:
|
case Tag:
|
||||||
return addPattern<TestSpec::TagPattern>();
|
return addTagPattern();
|
||||||
case EscapedName:
|
case EscapedName:
|
||||||
revertBackToLastMode();
|
revertBackToLastMode();
|
||||||
return;
|
return;
|
||||||
@@ -156,25 +156,83 @@ namespace Catch {
|
|||||||
void TestSpecParser::saveLastMode() {
|
void TestSpecParser::saveLastMode() {
|
||||||
lastMode = m_mode;
|
lastMode = m_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestSpecParser::revertBackToLastMode() {
|
void TestSpecParser::revertBackToLastMode() {
|
||||||
m_mode = lastMode;
|
m_mode = lastMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestSpecParser::separate() {
|
bool TestSpecParser::separate() {
|
||||||
if( (m_mode==QuotedName) || (m_mode==Tag) ){
|
if( (m_mode==QuotedName) || (m_mode==Tag) ){
|
||||||
//invalid argument, signal failure to previous scope.
|
//invalid argument, signal failure to previous scope.
|
||||||
m_mode = None;
|
m_mode = None;
|
||||||
m_pos = m_arg.size();
|
m_pos = m_arg.size();
|
||||||
m_substring.clear();
|
m_substring.clear();
|
||||||
m_patternName.clear();
|
m_patternName.clear();
|
||||||
|
m_realPatternPos = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
endMode();
|
endMode();
|
||||||
addFilter();
|
addFilter();
|
||||||
return true; //success
|
return true; //success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TestSpecParser::preprocessPattern() {
|
||||||
|
std::string token = m_patternName;
|
||||||
|
for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
|
||||||
|
token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
|
||||||
|
m_escapeChars.clear();
|
||||||
|
if (startsWith(token, "exclude:")) {
|
||||||
|
m_exclusion = true;
|
||||||
|
token = token.substr(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_patternName.clear();
|
||||||
|
m_realPatternPos = 0;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpecParser::addNamePattern() {
|
||||||
|
auto token = preprocessPattern();
|
||||||
|
|
||||||
|
if (!token.empty()) {
|
||||||
|
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);
|
||||||
|
if (m_exclusion)
|
||||||
|
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||||
|
m_currentFilter.m_patterns.push_back(pattern);
|
||||||
|
}
|
||||||
|
m_substring.clear();
|
||||||
|
m_exclusion = false;
|
||||||
|
m_mode = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSpecParser::addTagPattern() {
|
||||||
|
auto token = preprocessPattern();
|
||||||
|
|
||||||
|
if (!token.empty()) {
|
||||||
|
// If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
|
||||||
|
// we have to create a separate hide tag and shorten the real one
|
||||||
|
if (token.size() > 1 && token[0] == '.') {
|
||||||
|
token.erase(token.begin());
|
||||||
|
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);
|
||||||
|
if (m_exclusion) {
|
||||||
|
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||||
|
}
|
||||||
|
m_currentFilter.m_patterns.push_back(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);
|
||||||
|
|
||||||
|
if (m_exclusion) {
|
||||||
|
pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);
|
||||||
|
}
|
||||||
|
m_currentFilter.m_patterns.push_back(pattern);
|
||||||
|
}
|
||||||
|
m_substring.clear();
|
||||||
|
m_exclusion = false;
|
||||||
|
m_mode = None;
|
||||||
|
}
|
||||||
|
|
||||||
TestSpec parseTestSpec( std::string const& arg ) {
|
TestSpec parseTestSpec( std::string const& arg ) {
|
||||||
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
|
||||||
}
|
}
|
||||||
|
@@ -53,35 +53,20 @@ namespace Catch {
|
|||||||
void revertBackToLastMode();
|
void revertBackToLastMode();
|
||||||
void addFilter();
|
void addFilter();
|
||||||
bool separate();
|
bool separate();
|
||||||
|
|
||||||
template<typename T>
|
// Handles common preprocessing of the pattern for name/tag patterns
|
||||||
void addPattern() {
|
std::string preprocessPattern();
|
||||||
std::string token = m_patternName;
|
// Adds the current pattern as a test name
|
||||||
for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
|
void addNamePattern();
|
||||||
token = token.substr( 0, m_escapeChars[i] - i ) + token.substr( m_escapeChars[i] -i +1 );
|
// Adds the current pattern as a tag
|
||||||
m_escapeChars.clear();
|
void addTagPattern();
|
||||||
if( startsWith( token, "exclude:" ) ) {
|
|
||||||
m_exclusion = true;
|
|
||||||
token = token.substr( 8 );
|
|
||||||
}
|
|
||||||
if( !token.empty() ) {
|
|
||||||
TestSpec::PatternPtr pattern = std::make_shared<T>( token, m_substring );
|
|
||||||
if( m_exclusion )
|
|
||||||
pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
|
|
||||||
m_currentFilter.m_patterns.push_back( pattern );
|
|
||||||
}
|
|
||||||
m_substring.clear();
|
|
||||||
m_patternName.clear();
|
|
||||||
m_exclusion = false;
|
|
||||||
m_mode = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void addCharToPattern(char c) {
|
inline void addCharToPattern(char c) {
|
||||||
m_substring += c;
|
m_substring += c;
|
||||||
m_patternName += c;
|
m_patternName += c;
|
||||||
m_realPatternPos++;
|
m_realPatternPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
TestSpec parseTestSpec( std::string const& arg );
|
TestSpec parseTestSpec( std::string const& arg );
|
||||||
|
|
||||||
|
@@ -309,8 +309,8 @@ namespace Catch {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
template<typename InputIterator>
|
template<typename InputIterator, typename Sentinel = InputIterator>
|
||||||
std::string rangeToString(InputIterator first, InputIterator last) {
|
std::string rangeToString(InputIterator first, Sentinel last) {
|
||||||
ReusableStringStream rss;
|
ReusableStringStream rss;
|
||||||
rss << "{ ";
|
rss << "{ ";
|
||||||
if (first != last) {
|
if (first != last) {
|
||||||
@@ -469,20 +469,27 @@ namespace Catch {
|
|||||||
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
|
// Import begin/ end from std here
|
||||||
|
|
||||||
// Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
|
|
||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
not_this_one begin( ... );
|
namespace detail {
|
||||||
not_this_one end( ... );
|
template <typename...>
|
||||||
|
struct void_type {
|
||||||
|
using type = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct is_range_impl : std::false_type {
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_range {
|
struct is_range : detail::is_range_impl<T> {
|
||||||
static const bool value =
|
|
||||||
!std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
|
|
||||||
!std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(_MANAGED) // Managed types are never ranges
|
#if defined(_MANAGED) // Managed types are never ranges
|
||||||
|
@@ -12,7 +12,9 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
bool uncaught_exceptions() {
|
bool uncaught_exceptions() {
|
||||||
#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
return false;
|
||||||
|
#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
|
||||||
return std::uncaught_exceptions() > 0;
|
return std::uncaught_exceptions() > 0;
|
||||||
#else
|
#else
|
||||||
return std::uncaught_exception();
|
return std::uncaught_exception();
|
||||||
|
@@ -37,7 +37,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 2, 10, 2, "", 0 );
|
static Version version( 2, 13, 1, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,8 +12,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
using uchar = unsigned char;
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -87,7 +85,7 @@ namespace {
|
|||||||
// (see: http://www.w3.org/TR/xml/#syntax)
|
// (see: http://www.w3.org/TR/xml/#syntax)
|
||||||
|
|
||||||
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
|
for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
|
||||||
uchar c = m_str[idx];
|
unsigned char c = m_str[idx];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '<': os << "<"; break;
|
case '<': os << "<"; break;
|
||||||
case '&': os << "&"; break;
|
case '&': os << "&"; break;
|
||||||
@@ -147,7 +145,7 @@ namespace {
|
|||||||
bool valid = true;
|
bool valid = true;
|
||||||
uint32_t value = headerValue(c);
|
uint32_t value = headerValue(c);
|
||||||
for (std::size_t n = 1; n < encBytes; ++n) {
|
for (std::size_t n = 1; n < encBytes; ++n) {
|
||||||
uchar nc = m_str[idx + n];
|
unsigned char nc = m_str[idx + n];
|
||||||
valid &= ((nc & 0xC0) == 0x80);
|
valid &= ((nc & 0xC0) == 0x80);
|
||||||
value = (value << 6) | (nc & 0x3F);
|
value = (value << 6) | (nc & 0x3F);
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,17 @@ namespace Catch {
|
|||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldShowDuration( IConfig const& config, double duration ) {
|
||||||
|
if ( config.showDurations() == ShowDurations::Always ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( config.showDurations() == ShowDurations::Never ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const double min = config.minDuration();
|
||||||
|
return min >= 0 && duration >= min;
|
||||||
|
}
|
||||||
|
|
||||||
std::string serializeFilters( std::vector<std::string> const& container ) {
|
std::string serializeFilters( std::vector<std::string> const& container ) {
|
||||||
ReusableStringStream oss;
|
ReusableStringStream oss;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@@ -25,6 +25,9 @@ namespace Catch {
|
|||||||
// Returns double formatted as %.3f (format expected on output)
|
// Returns double formatted as %.3f (format expected on output)
|
||||||
std::string getFormattedDuration( double duration );
|
std::string getFormattedDuration( double duration );
|
||||||
|
|
||||||
|
//! Should the reporter show
|
||||||
|
bool shouldShowDuration( IConfig const& config, double duration );
|
||||||
|
|
||||||
std::string serializeFilters( std::vector<std::string> const& container );
|
std::string serializeFilters( std::vector<std::string> const& container );
|
||||||
|
|
||||||
template<typename DerivedT>
|
template<typename DerivedT>
|
||||||
@@ -52,7 +55,7 @@ namespace Catch {
|
|||||||
void noMatchingTestCases(std::string const&) override {}
|
void noMatchingTestCases(std::string const&) override {}
|
||||||
|
|
||||||
void reportInvalidArguments(std::string const&) override {}
|
void reportInvalidArguments(std::string const&) override {}
|
||||||
|
|
||||||
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
void testRunStarting(TestRunInfo const& _testRunInfo) override {
|
||||||
currentTestRunInfo = _testRunInfo;
|
currentTestRunInfo = _testRunInfo;
|
||||||
}
|
}
|
||||||
|
@@ -245,10 +245,6 @@ private:
|
|||||||
return "Reports test results on a single line, suitable for IDEs";
|
return "Reports test results on a single line, suitable for IDEs";
|
||||||
}
|
}
|
||||||
|
|
||||||
ReporterPreferences CompactReporter::getPreferences() const {
|
|
||||||
return m_reporterPrefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CompactReporter::noMatchingTestCases( std::string const& spec ) {
|
void CompactReporter::noMatchingTestCases( std::string const& spec ) {
|
||||||
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
stream << "No test cases matched '" << spec << '\'' << std::endl;
|
||||||
}
|
}
|
||||||
@@ -275,8 +271,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
|
void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
|
||||||
if (m_config->showDurations() == ShowDurations::Always) {
|
double dur = _sectionStats.durationInSeconds;
|
||||||
stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
if ( shouldShowDuration( *m_config, dur ) ) {
|
||||||
|
stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,8 +22,6 @@ namespace Catch {
|
|||||||
|
|
||||||
static std::string getDescription();
|
static std::string getDescription();
|
||||||
|
|
||||||
ReporterPreferences getPreferences() const override;
|
|
||||||
|
|
||||||
void noMatchingTestCases(std::string const& spec) override;
|
void noMatchingTestCases(std::string const& spec) override;
|
||||||
|
|
||||||
void assertionStarting(AssertionInfo const&) override;
|
void assertionStarting(AssertionInfo const&) override;
|
||||||
|
@@ -210,15 +210,11 @@ class Duration {
|
|||||||
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
|
static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
|
||||||
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
|
static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
|
||||||
|
|
||||||
uint64_t m_inNanoseconds;
|
double m_inNanoseconds;
|
||||||
Unit m_units;
|
Unit m_units;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
|
explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
|
||||||
: Duration(static_cast<uint64_t>(inNanoseconds), units) {
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
|
|
||||||
: m_inNanoseconds(inNanoseconds),
|
: m_inNanoseconds(inNanoseconds),
|
||||||
m_units(units) {
|
m_units(units) {
|
||||||
if (m_units == Unit::Auto) {
|
if (m_units == Unit::Auto) {
|
||||||
@@ -247,7 +243,7 @@ public:
|
|||||||
case Unit::Minutes:
|
case Unit::Minutes:
|
||||||
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
|
return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
|
||||||
default:
|
default:
|
||||||
return static_cast<double>(m_inNanoseconds);
|
return m_inNanoseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto unitsAsString() const -> std::string {
|
auto unitsAsString() const -> std::string {
|
||||||
@@ -366,7 +362,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
return{
|
return{
|
||||||
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
|
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },
|
||||||
{ "samples mean std dev", 14, ColumnInfo::Right },
|
{ "samples mean std dev", 14, ColumnInfo::Right },
|
||||||
{ "iterations low mean low std dev", 14, ColumnInfo::Right },
|
{ "iterations low mean low std dev", 14, ColumnInfo::Right },
|
||||||
{ "estimated high mean high std dev", 14, ColumnInfo::Right }
|
{ "estimated high mean high std dev", 14, ColumnInfo::Right }
|
||||||
@@ -422,8 +418,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
|
|||||||
stream << "\nNo assertions in test case";
|
stream << "\nNo assertions in test case";
|
||||||
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
|
stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
|
||||||
}
|
}
|
||||||
if (m_config->showDurations() == ShowDurations::Always) {
|
double dur = _sectionStats.durationInSeconds;
|
||||||
stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
if (shouldShowDuration(*m_config, dur)) {
|
||||||
|
stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;
|
||||||
}
|
}
|
||||||
if (m_headerPrinted) {
|
if (m_headerPrinted) {
|
||||||
m_headerPrinted = false;
|
m_headerPrinted = false;
|
||||||
@@ -684,8 +681,10 @@ void ConsoleReporter::printSummaryDivider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleReporter::printTestFilters() {
|
void ConsoleReporter::printTestFilters() {
|
||||||
if (m_config->testSpec().hasFilters())
|
if (m_config->testSpec().hasFilters()) {
|
||||||
stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n';
|
Colour guard(Colour::BrightYellow);
|
||||||
|
stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
||||||
@@ -698,4 +697,4 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
|
|||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
# pragma clang diagnostic pop
|
# pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
@@ -193,6 +193,11 @@ namespace Catch {
|
|||||||
xml.writeAttribute( "name", name );
|
xml.writeAttribute( "name", name );
|
||||||
}
|
}
|
||||||
xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
|
xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
|
||||||
|
// This is not ideal, but it should be enough to mimic gtest's
|
||||||
|
// junit output.
|
||||||
|
// Ideally the JUnit reporter would also handle `skipTest`
|
||||||
|
// events and write those out appropriately.
|
||||||
|
xml.writeAttribute( "status", "run" );
|
||||||
|
|
||||||
writeAssertions( sectionNode );
|
writeAssertions( sectionNode );
|
||||||
|
|
||||||
@@ -223,11 +228,7 @@ namespace Catch {
|
|||||||
elementName = "error";
|
elementName = "error";
|
||||||
break;
|
break;
|
||||||
case ResultWas::ExplicitFailure:
|
case ResultWas::ExplicitFailure:
|
||||||
elementName = "failure";
|
|
||||||
break;
|
|
||||||
case ResultWas::ExpressionFailed:
|
case ResultWas::ExpressionFailed:
|
||||||
elementName = "failure";
|
|
||||||
break;
|
|
||||||
case ResultWas::DidntThrowException:
|
case ResultWas::DidntThrowException:
|
||||||
elementName = "failure";
|
elementName = "failure";
|
||||||
break;
|
break;
|
||||||
|
@@ -23,16 +23,17 @@ namespace Catch {
|
|||||||
|
|
||||||
using StreamingReporterBase::StreamingReporterBase;
|
using StreamingReporterBase::StreamingReporterBase;
|
||||||
|
|
||||||
|
TAPReporter( ReporterConfig const& config ):
|
||||||
|
StreamingReporterBase( config ) {
|
||||||
|
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||||
|
}
|
||||||
|
|
||||||
~TAPReporter() override;
|
~TAPReporter() override;
|
||||||
|
|
||||||
static std::string getDescription() {
|
static std::string getDescription() {
|
||||||
return "Reports test results in TAP format, suitable for test harnesses";
|
return "Reports test results in TAP format, suitable for test harnesses";
|
||||||
}
|
}
|
||||||
|
|
||||||
ReporterPreferences getPreferences() const override {
|
|
||||||
return m_reporterPrefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void noMatchingTestCases( std::string const& spec ) override {
|
void noMatchingTestCases( std::string const& spec ) override {
|
||||||
stream << "# No test cases matched '" << spec << "'" << std::endl;
|
stream << "# No test cases matched '" << spec << "'" << std::endl;
|
||||||
}
|
}
|
||||||
@@ -203,16 +204,15 @@ namespace Catch {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using messages.end() directly (or auto) yields compilation error:
|
const auto itEnd = messages.cend();
|
||||||
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
|
const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
||||||
const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Colour colourGuard( colour );
|
Colour colourGuard( colour );
|
||||||
stream << " with " << pluralise( N, "message" ) << ":";
|
stream << " with " << pluralise( N, "message" ) << ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; itMessage != itEnd; ) {
|
while( itMessage != itEnd ) {
|
||||||
// If this assertion is a warning ignore any INFO messages
|
// If this assertion is a warning ignore any INFO messages
|
||||||
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||||
stream << " '" << itMessage->message << "'";
|
stream << " '" << itMessage->message << "'";
|
||||||
@@ -220,7 +220,9 @@ namespace Catch {
|
|||||||
Colour colourGuard( dimColour() );
|
Colour colourGuard( dimColour() );
|
||||||
stream << " and";
|
stream << " and";
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
++itMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,10 +236,9 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void printTotals( const Totals& totals ) const {
|
void printTotals( const Totals& totals ) const {
|
||||||
|
stream << "1.." << totals.assertions.total();
|
||||||
if( totals.testCases.total() == 0 ) {
|
if( totals.testCases.total() == 0 ) {
|
||||||
stream << "1..0 # Skipped: No tests ran.";
|
stream << " # Skipped: No tests ran.";
|
||||||
} else {
|
|
||||||
stream << "1.." << counter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -207,6 +207,10 @@ namespace Catch {
|
|||||||
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
.writeAttribute( "successes", testGroupStats.totals.assertions.passed )
|
||||||
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
.writeAttribute( "failures", testGroupStats.totals.assertions.failed )
|
||||||
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
|
.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
|
||||||
|
m_xml.scopedElement( "OverallResultsCases")
|
||||||
|
.writeAttribute( "successes", testGroupStats.totals.testCases.passed )
|
||||||
|
.writeAttribute( "failures", testGroupStats.totals.testCases.failed )
|
||||||
|
.writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );
|
||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +220,10 @@ namespace Catch {
|
|||||||
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
|
.writeAttribute( "successes", testRunStats.totals.assertions.passed )
|
||||||
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
|
.writeAttribute( "failures", testRunStats.totals.assertions.failed )
|
||||||
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
|
.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
|
||||||
|
m_xml.scopedElement( "OverallResultsCases")
|
||||||
|
.writeAttribute( "successes", testRunStats.totals.testCases.passed )
|
||||||
|
.writeAttribute( "failures", testRunStats.totals.testCases.failed )
|
||||||
|
.writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );
|
||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,16 +237,16 @@ namespace Catch {
|
|||||||
m_xml.writeAttribute("samples", info.samples)
|
m_xml.writeAttribute("samples", info.samples)
|
||||||
.writeAttribute("resamples", info.resamples)
|
.writeAttribute("resamples", info.resamples)
|
||||||
.writeAttribute("iterations", info.iterations)
|
.writeAttribute("iterations", info.iterations)
|
||||||
.writeAttribute("clockResolution", static_cast<uint64_t>(info.clockResolution))
|
.writeAttribute("clockResolution", info.clockResolution)
|
||||||
.writeAttribute("estimatedDuration", static_cast<uint64_t>(info.estimatedDuration))
|
.writeAttribute("estimatedDuration", info.estimatedDuration)
|
||||||
.writeComment("All values in nano seconds");
|
.writeComment("All values in nano seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
|
void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
|
||||||
m_xml.startElement("mean")
|
m_xml.startElement("mean")
|
||||||
.writeAttribute("value", static_cast<uint64_t>(benchmarkStats.mean.point.count()))
|
.writeAttribute("value", benchmarkStats.mean.point.count())
|
||||||
.writeAttribute("lowerBound", static_cast<uint64_t>(benchmarkStats.mean.lower_bound.count()))
|
.writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())
|
||||||
.writeAttribute("upperBound", static_cast<uint64_t>(benchmarkStats.mean.upper_bound.count()))
|
.writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())
|
||||||
.writeAttribute("ci", benchmarkStats.mean.confidence_interval);
|
.writeAttribute("ci", benchmarkStats.mean.confidence_interval);
|
||||||
m_xml.endElement();
|
m_xml.endElement();
|
||||||
m_xml.startElement("standardDeviation")
|
m_xml.startElement("standardDeviation")
|
||||||
|
@@ -27,6 +27,7 @@ set(TEST_SOURCES
|
|||||||
${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
|
${SELF_TEST_DIR}/IntrospectiveTests/StringManip.tests.cpp
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
|
${SELF_TEST_DIR}/IntrospectiveTests/ToString.tests.cpp
|
||||||
|
${SELF_TEST_DIR}/TimingTests/Sleep.tests.cpp
|
||||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
||||||
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
|
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
|
||||||
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
|
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
|
||||||
@@ -451,6 +452,8 @@ set_tests_properties(TestsInFile::InvalidTestNames-1 PROPERTIES PASS_REGULAR_EXP
|
|||||||
add_test(NAME TestsInFile::InvalidTestNames-2 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
|
add_test(NAME TestsInFile::InvalidTestNames-2 COMMAND $<TARGET_FILE:SelfTest> "-f ${CATCH_DIR}/projects/SelfTest/Misc/invalid-test-names.input")
|
||||||
set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXPRESSION "No tests ran")
|
set_tests_properties(TestsInFile::InvalidTestNames-2 PROPERTIES PASS_REGULAR_EXPRESSION "No tests ran")
|
||||||
|
|
||||||
|
add_test(NAME RandomTestOrdering COMMAND ${PYTHON_EXECUTABLE}
|
||||||
|
${CATCH_DIR}/projects/TestScripts/testRandomOrder.py $<TARGET_FILE:SelfTest>)
|
||||||
|
|
||||||
if (CATCH_USE_VALGRIND)
|
if (CATCH_USE_VALGRIND)
|
||||||
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
||||||
|
@@ -10,6 +10,40 @@ project( Catch2ExtraTests LANGUAGES CXX )
|
|||||||
|
|
||||||
message( STATUS "Extra tests included" )
|
message( STATUS "Extra tests included" )
|
||||||
|
|
||||||
|
# The MinDuration reporting tests do not need separate compilation, but
|
||||||
|
# they have non-trivial execution time, so they are categorized as
|
||||||
|
# extra tests, so that they are run less.
|
||||||
|
add_test(NAME MinDuration::SimpleThreshold COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.22 [min_duration_test])
|
||||||
|
set_tests_properties(
|
||||||
|
MinDuration::SimpleThreshold
|
||||||
|
PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION "s: sleep_for_250ms"
|
||||||
|
FAIL_REGULAR_EXPRESSION "sleep_for_100ms"
|
||||||
|
RUN_SERIAL ON # The test is timing sensitive, so we want to run it
|
||||||
|
# serially to avoid false positives on oversubscribed machines
|
||||||
|
)
|
||||||
|
|
||||||
|
# -d yes overrides the threshold, so we should see the faster test even
|
||||||
|
# with a ridiculous high min duration threshold
|
||||||
|
add_test(NAME MinDuration::DurationOverrideYes COMMAND $<TARGET_FILE:SelfTest> --min-duration 1.0 -d yes [min_duration_test])
|
||||||
|
set_tests_properties(
|
||||||
|
MinDuration::DurationOverrideYes
|
||||||
|
PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION "s: sleep_for_100ms"
|
||||||
|
)
|
||||||
|
|
||||||
|
# -d no overrides the threshold, so we should never see any tests even
|
||||||
|
# with ridiculously low min duration threshold
|
||||||
|
add_test(NAME MinDuration::DurationOverrideNo COMMAND $<TARGET_FILE:SelfTest> --min-duration 0.0001 -d no [min_duration_test])
|
||||||
|
set_tests_properties(
|
||||||
|
MinDuration::DurationOverrideNo
|
||||||
|
PROPERTIES
|
||||||
|
FAIL_REGULAR_EXPRESSION "sleep_for_250ms"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ------------ end of duration reporting tests
|
||||||
|
|
||||||
# define folders used:
|
# define folders used:
|
||||||
|
|
||||||
set( TESTS_DIR ${CATCH_DIR}/projects/ExtraTests )
|
set( TESTS_DIR ${CATCH_DIR}/projects/ExtraTests )
|
||||||
@@ -123,7 +157,7 @@ add_test(NAME BenchmarkingMacros COMMAND BenchmarkingMacros -r console -s)
|
|||||||
set_tests_properties(
|
set_tests_properties(
|
||||||
BenchmarkingMacros
|
BenchmarkingMacros
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
PASS_REGULAR_EXPRESSION "benchmark name samples iterations estimated"
|
PASS_REGULAR_EXPRESSION "benchmark name[\\r\\n\\t ]+samples[\\r\\n\\t ]+iterations[\\r\\n\\t ]+estimated"
|
||||||
)
|
)
|
||||||
|
|
||||||
# This test touches windows.h, so it should only be compiled under msvc
|
# This test touches windows.h, so it should only be compiled under msvc
|
||||||
@@ -137,6 +171,14 @@ if (MSVC)
|
|||||||
add_test(NAME WindowsHeader COMMAND WindowsHeader -r compact)
|
add_test(NAME WindowsHeader COMMAND WindowsHeader -r compact)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable(DebugBreakMacros ${TESTS_DIR}/X12-CustomDebugBreakMacro.cpp)
|
||||||
|
add_test(NAME DebugBreakMacros COMMAND DebugBreakMacros --break)
|
||||||
|
set_tests_properties(
|
||||||
|
DebugBreakMacros
|
||||||
|
PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION "Pretty please, break into debugger"
|
||||||
|
)
|
||||||
|
|
||||||
set( EXTRA_TEST_BINARIES
|
set( EXTRA_TEST_BINARIES
|
||||||
PrefixedMacros
|
PrefixedMacros
|
||||||
DisabledMacros
|
DisabledMacros
|
||||||
@@ -145,6 +187,7 @@ set( EXTRA_TEST_BINARIES
|
|||||||
FallbackStringifier
|
FallbackStringifier
|
||||||
DisableStringification
|
DisableStringification
|
||||||
BenchmarkingMacros
|
BenchmarkingMacros
|
||||||
|
DebugBreakMacros
|
||||||
)
|
)
|
||||||
|
|
||||||
# Shared config
|
# Shared config
|
||||||
|
17
projects/ExtraTests/X12-CustomDebugBreakMacro.cpp
Normal file
17
projects/ExtraTests/X12-CustomDebugBreakMacro.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// X12-CustomDebugBreakMacro.cpp
|
||||||
|
// Test that user-defined `CATCH_BREAK_INTO_DEBUGGER` is respected and used.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void custom_debug_break() {
|
||||||
|
std::cerr << "Pretty please, break into debugger\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CATCH_BREAK_INTO_DEBUGGER() custom_debug_break()
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
TEST_CASE("Failing test that breaks into debugger", "[macros]") {
|
||||||
|
REQUIRE(1 == 2);
|
||||||
|
}
|
@@ -26,14 +26,6 @@ TEST_CASE("Benchmark factorial", "[benchmark]") {
|
|||||||
BENCHMARK("factorial 14") {
|
BENCHMARK("factorial 14") {
|
||||||
return factorial(14);
|
return factorial(14);
|
||||||
};
|
};
|
||||||
//
|
|
||||||
// BENCHMARK("factorial 20") {
|
|
||||||
// return factorial(20);
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// BENCHMARK("factorial 35") {
|
|
||||||
// return factorial(35);
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Benchmark containers", "[.][benchmark]") {
|
TEST_CASE("Benchmark containers", "[.][benchmark]") {
|
||||||
|
@@ -23,6 +23,64 @@ This would not be caught previously
|
|||||||
Nor would this
|
Nor would this
|
||||||
Tricky.tests.cpp:<line number>: failed: explicitly with 1 message: '1514'
|
Tricky.tests.cpp:<line number>: failed: explicitly with 1 message: '1514'
|
||||||
Compilation.tests.cpp:<line number>: passed: std::is_same<TypeList<int>, TypeList<int>>::value for: true
|
Compilation.tests.cpp:<line number>: passed: std::is_same<TypeList<int>, TypeList<int>>::value for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("spec . char")) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("spec , char")) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase(R"(spec \, char)"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec {a} char)")) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec [a] char)")) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("differs but has similar tag", "[a]"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase(R"(spec \ char)")) for: true
|
||||||
|
Generators.tests.cpp:<line number>: passed: counter < 7 for: 3 < 7
|
||||||
|
Generators.tests.cpp:<line number>: passed: counter < 7 for: 6 < 7
|
||||||
|
Generators.tests.cpp:<line number>: passed: i != j for: 1 != 3
|
||||||
|
Generators.tests.cpp:<line number>: passed: i != j for: 1 != 4
|
||||||
|
Generators.tests.cpp:<line number>: passed: i != j for: 2 != 3
|
||||||
|
Generators.tests.cpp:<line number>: passed: i != j for: 2 != 4
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 3' and 'k := 5'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 3' and 'k := 6'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 4' and 'k := 5'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 1' and 'j := 4' and 'k := 6'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'A'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 3' and 'k := 5'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 3' and 'k := 6'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 1 message: 'B'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 4' and 'k := 5'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: with 3 messages: 'i := 2' and 'j := 4' and 'k := 6'
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 1
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 2
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: m for: 3
|
||||||
|
PartTracker.tests.cpp:<line number>: passed: n for: 3
|
||||||
|
Misc.tests.cpp:<line number>: passed:
|
||||||
|
Misc.tests.cpp:<line number>: passed:
|
||||||
|
Misc.tests.cpp:<line number>: passed:
|
||||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
|
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception'
|
||||||
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception'
|
||||||
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
Exception.tests.cpp:<line number>: passed: thisThrows() with 1 message: 'answer := 42'
|
||||||
@@ -237,6 +295,11 @@ Matchers.tests.cpp:<line number>: passed: 1, Predicate<int>(alwaysTrue, "always
|
|||||||
Matchers.tests.cpp:<line number>: passed: 1, !Predicate<int>(alwaysFalse, "always false") for: 1 not matches predicate: "always false"
|
Matchers.tests.cpp:<line number>: passed: 1, !Predicate<int>(alwaysFalse, "always false") for: 1 not matches predicate: "always false"
|
||||||
Matchers.tests.cpp:<line number>: passed: "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal"
|
Matchers.tests.cpp:<line number>: passed: "Hello olleH", Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); }, "First and last character should be equal") for: "Hello olleH" matches predicate: "First and last character should be equal"
|
||||||
Matchers.tests.cpp:<line number>: passed: "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate
|
Matchers.tests.cpp:<line number>: passed: "This wouldn't pass", !Predicate<std::string>( [] (std::string const& str) -> bool { return str.front() == str.back(); } ) for: "This wouldn't pass" not matches undescribed predicate
|
||||||
|
Compilation.tests.cpp:<line number>: passed: lhs | rhs for: Val: 1 | Val: 2
|
||||||
|
Compilation.tests.cpp:<line number>: passed: !(lhs & rhs) for: !(Val: 1 & Val: 2)
|
||||||
|
Compilation.tests.cpp:<line number>: passed: HasBitOperators{ 1 } & HasBitOperators{ 1 } for: Val: 1 & Val: 1
|
||||||
|
Compilation.tests.cpp:<line number>: passed: lhs ^ rhs for: Val: 1 ^ Val: 2
|
||||||
|
Compilation.tests.cpp:<line number>: passed: !(lhs ^ lhs) for: !(Val: 1 ^ Val: 1)
|
||||||
Tricky.tests.cpp:<line number>: passed: true
|
Tricky.tests.cpp:<line number>: passed: true
|
||||||
Tricky.tests.cpp:<line number>: passed: true
|
Tricky.tests.cpp:<line number>: passed: true
|
||||||
Tricky.tests.cpp:<line number>: passed: true
|
Tricky.tests.cpp:<line number>: passed: true
|
||||||
@@ -312,6 +375,14 @@ Condition.tests.cpp:<line number>: passed: 4 == ul for: 4 == 4
|
|||||||
Condition.tests.cpp:<line number>: passed: 5 == c for: 5 == 5
|
Condition.tests.cpp:<line number>: passed: 5 == c for: 5 == 5
|
||||||
Condition.tests.cpp:<line number>: passed: 6 == uc for: 6 == 6
|
Condition.tests.cpp:<line number>: passed: 6 == uc for: 6 == 6
|
||||||
Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4
|
Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4
|
||||||
|
Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), !composed1 for: "some completely different text that contains one common word" not ( contains: "string" or contains: "random" )
|
||||||
|
Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), composed2 for: "some completely different text that contains one common word" ( contains: "string" or contains: "random" or contains: "different" )
|
||||||
|
Matchers.tests.cpp:<line number>: passed: 1, !(first && second) for: 1 not ( CheckedTestingMatcher set to fail and CheckedTestingMatcher set to fail )
|
||||||
|
Matchers.tests.cpp:<line number>: passed: first.matchCalled for: true
|
||||||
|
Matchers.tests.cpp:<line number>: passed: !second.matchCalled for: true
|
||||||
|
Matchers.tests.cpp:<line number>: passed: 1, first || second for: 1 ( CheckedTestingMatcher set to succeed or CheckedTestingMatcher set to fail )
|
||||||
|
Matchers.tests.cpp:<line number>: passed: first.matchCalled for: true
|
||||||
|
Matchers.tests.cpp:<line number>: passed: !second.matchCalled for: true
|
||||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
|
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
|
||||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING"
|
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING"
|
||||||
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
|
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
|
||||||
@@ -762,6 +833,7 @@ Condition.tests.cpp:<line number>: passed: data.str_hello != "goodbye" for: "hel
|
|||||||
Condition.tests.cpp:<line number>: passed: data.str_hello != "hell" for: "hello" != "hell"
|
Condition.tests.cpp:<line number>: passed: data.str_hello != "hell" for: "hello" != "hell"
|
||||||
Condition.tests.cpp:<line number>: passed: data.str_hello != "hello1" for: "hello" != "hello1"
|
Condition.tests.cpp:<line number>: passed: data.str_hello != "hello1" for: "hello" != "hello1"
|
||||||
Condition.tests.cpp:<line number>: passed: data.str_hello.size() != 6 for: 5 != 6
|
Condition.tests.cpp:<line number>: passed: data.str_hello.size() != 6 for: 5 != 6
|
||||||
|
Compilation.tests.cpp:<line number>: passed: []() { return true; }() for: true
|
||||||
Approx.tests.cpp:<line number>: passed: d <= Approx( 1.24 ) for: 1.23 <= Approx( 1.24 )
|
Approx.tests.cpp:<line number>: passed: d <= Approx( 1.24 ) for: 1.23 <= Approx( 1.24 )
|
||||||
Approx.tests.cpp:<line number>: passed: d <= Approx( 1.23 ) for: 1.23 <= Approx( 1.23 )
|
Approx.tests.cpp:<line number>: passed: d <= Approx( 1.23 ) for: 1.23 <= Approx( 1.23 )
|
||||||
Approx.tests.cpp:<line number>: passed: !(d <= Approx( 1.22 )) for: !(1.23 <= Approx( 1.22 ))
|
Approx.tests.cpp:<line number>: passed: !(d <= Approx( 1.22 )) for: !(1.23 <= Approx( 1.22 ))
|
||||||
@@ -1027,6 +1099,12 @@ CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark
|
|||||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
|
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( " aardvark " ) ) for: true
|
||||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true
|
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark " ) ) for: true
|
||||||
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true
|
CmdLine.tests.cpp:<line number>: passed: spec.matches( fakeTestCase( "aardvark" ) ) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("hidden and foo", "[.][foo]")) for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("hidden and foo", "[.][foo]"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only foo", "[foo]"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !(spec.matches(fakeTestCase("only hidden", "[.]"))) for: !false
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: spec.matches(fakeTestCase("neither foo nor hidden", "[bar]")) for: true
|
||||||
Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
|
Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0
|
||||||
Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0
|
Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0
|
||||||
Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0
|
Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 0
|
||||||
@@ -1080,6 +1158,16 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-x", "2"}) for: {?}
|
|||||||
CmdLine.tests.cpp:<line number>: passed: config.abortAfter == 2 for: 2 == 2
|
CmdLine.tests.cpp:<line number>: passed: config.abortAfter == 2 for: 2 == 2
|
||||||
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
||||||
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("convert") && Contains("oops") for: "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" )
|
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("convert") && Contains("oops") for: "Unable to convert 'oops' to destination type" ( contains: "convert" and contains: "oops" )
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 0 == 0
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 1 == 1
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 2 == 2
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--wait-for-keypress", std::get<0>(input)}) for: {?}
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: config.waitForKeypress == std::get<1>(input) for: 3 == 3
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: !result for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), Contains("never") && Contains("both") for: "keypress argument must be one of: never, start, exit or both. 'sometimes' not recognised" ( contains: "never" and contains: "both" )
|
||||||
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-e"}) for: {?}
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-e"}) for: {?}
|
||||||
CmdLine.tests.cpp:<line number>: passed: config.noThrow for: true
|
CmdLine.tests.cpp:<line number>: passed: config.noThrow for: true
|
||||||
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--nothrow"}) for: {?}
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "--nothrow"}) for: {?}
|
||||||
@@ -1110,9 +1198,12 @@ CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-confid
|
|||||||
CmdLine.tests.cpp:<line number>: passed: config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99) for: 0.99 == Approx( 0.99 )
|
CmdLine.tests.cpp:<line number>: passed: config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99) for: 0.99 == Approx( 0.99 )
|
||||||
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-no-analysis" }) for: {?}
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-no-analysis" }) for: {?}
|
||||||
CmdLine.tests.cpp:<line number>: passed: config.benchmarkNoAnalysis for: true
|
CmdLine.tests.cpp:<line number>: passed: config.benchmarkNoAnalysis for: true
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "--benchmark-warmup-time=10" }) for: {?}
|
||||||
|
CmdLine.tests.cpp:<line number>: passed: config.benchmarkWarmupTime == 10 for: 10 == 10
|
||||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
|
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 3 >= 1
|
||||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 2 >= 1
|
||||||
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
Misc.tests.cpp:<line number>: passed: std::tuple_size<TestType>::value >= 1 for: 1 >= 1
|
||||||
|
ToString.tests.cpp:<line number>: passed: Catch::Detail::stringify(UsesSentinel{}) == "{ }" for: "{ }" == "{ }"
|
||||||
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
|
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
|
||||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
|
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("this STRING contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
|
||||||
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
|
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches("contains 'abc' as a substring") for: "this string contains 'abc' as a substring" matches "contains 'abc' as a substring" case sensitively
|
||||||
@@ -1186,7 +1277,7 @@ String.tests.cpp:<line number>: passed: s.data() == s2.data() for: "hello world!
|
|||||||
String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
|
String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
|
||||||
String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
|
String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
|
||||||
String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
|
String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
|
||||||
String.tests.cpp:<line number>: passed: buffer1 != buffer2 for: "Hello" != "Hello"
|
String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
|
||||||
String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
|
String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
|
||||||
String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
|
String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
|
||||||
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
|
String.tests.cpp:<line number>: passed: sr == "a standard string" for: a standard string == "a standard string"
|
||||||
@@ -1498,6 +1589,7 @@ Approx.tests.cpp:<line number>: passed: approx( d ) != 1.25 for: Approx( 1.23 )
|
|||||||
VariadicMacros.tests.cpp:<line number>: passed: with 1 message: 'no assertions'
|
VariadicMacros.tests.cpp:<line number>: passed: with 1 message: 'no assertions'
|
||||||
Matchers.tests.cpp:<line number>: passed: empty, Approx(empty) for: { } is approx: { }
|
Matchers.tests.cpp:<line number>: passed: empty, Approx(empty) for: { } is approx: { }
|
||||||
Matchers.tests.cpp:<line number>: passed: v1, Approx(v1) for: { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
|
Matchers.tests.cpp:<line number>: passed: v1, Approx(v1) for: { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v1, Approx<double>({ 1., 2., 3. }) for: { 1.0, 2.0, 3.0 } is approx: { 1.0, 2.0, 3.0 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v1, !Approx(temp) for: { 1.0, 2.0, 3.0 } not is approx: { 1.0, 2.0, 3.0, 4.0 }
|
Matchers.tests.cpp:<line number>: passed: v1, !Approx(temp) for: { 1.0, 2.0, 3.0 } not is approx: { 1.0, 2.0, 3.0, 4.0 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v1, !Approx(v2) for: { 1.0, 2.0, 3.0 } not is approx: { 1.5, 2.5, 3.5 }
|
Matchers.tests.cpp:<line number>: passed: v1, !Approx(v2) for: { 1.0, 2.0, 3.0 } not is approx: { 1.5, 2.5, 3.5 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v1, Approx(v2).margin(0.5) for: { 1.0, 2.0, 3.0 } is approx: { 1.5, 2.5, 3.5 }
|
Matchers.tests.cpp:<line number>: passed: v1, Approx(v2).margin(0.5) for: { 1.0, 2.0, 3.0 } is approx: { 1.5, 2.5, 3.5 }
|
||||||
@@ -1507,18 +1599,29 @@ Matchers.tests.cpp:<line number>: failed: empty, Approx(t1) for: { } is approx:
|
|||||||
Matchers.tests.cpp:<line number>: failed: v1, Approx(v2) for: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }
|
Matchers.tests.cpp:<line number>: failed: v1, Approx(v2) for: { 2.0, 4.0, 6.0 } is approx: { 1.0, 3.0, 5.0 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) for: { 1, 2, 3 } Contains: 1
|
Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) for: { 1, 2, 3 } Contains: 1
|
||||||
Matchers.tests.cpp:<line number>: passed: v, VectorContains(2) for: { 1, 2, 3 } Contains: 2
|
Matchers.tests.cpp:<line number>: passed: v, VectorContains(2) for: { 1, 2, 3 } Contains: 2
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, (VectorContains<int, CustomAllocator<int>>(2)) for: { 1, 2, 3 } Contains: 2
|
||||||
Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2 }
|
Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v, Contains<int>({ 1, 2 }) for: { 1, 2, 3 } Contains: { 1, 2 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, (Contains<int, std::allocator<int>, CustomAllocator<int>>(v2)) for: { 1, 2, 3 } Contains: { 1, 2 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: v, Contains(v2) for: { 1, 2, 3 } Contains: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, Contains(empty) for: { 1, 2, 3 } Contains: { }
|
Matchers.tests.cpp:<line number>: passed: v, Contains(empty) for: { 1, 2, 3 } Contains: { }
|
||||||
Matchers.tests.cpp:<line number>: passed: empty, Contains(empty) for: { } Contains: { }
|
Matchers.tests.cpp:<line number>: passed: empty, Contains(empty) for: { } Contains: { }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, (Contains<int, std::allocator<int>, CustomAllocator<int>>(v2)) for: { 1, 2, 3 } Contains: { 1, 2, 3 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, Contains(v6) for: { 1, 2, 3 } Contains: { 1, 2 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) && VectorContains(2) for: { 1, 2, 3 } ( Contains: 1 and Contains: 2 )
|
Matchers.tests.cpp:<line number>: passed: v, VectorContains(1) && VectorContains(2) for: { 1, 2, 3 } ( Contains: 1 and Contains: 2 )
|
||||||
Matchers.tests.cpp:<line number>: passed: v, Equals(v) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: v, Equals(v) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: passed: empty, Equals(empty) for: { } Equals: { }
|
Matchers.tests.cpp:<line number>: passed: empty, Equals(empty) for: { } Equals: { }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v, Equals<int>({ 1, 2, 3 }) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, Equals(v2) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: v, Equals(v2) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, (Equals<int, std::allocator<int>, CustomAllocator<int>>(v2)) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, Equals(v6) for: { 1, 2, 3 } Equals: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: passed: v, UnorderedEquals(v) for: { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: v, UnorderedEquals(v) for: { 1, 2, 3 } UnorderedEquals: { 1, 2, 3 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v, UnorderedEquals<int>({ 3, 2, 1 }) for: { 1, 2, 3 } UnorderedEquals: { 3, 2, 1 }
|
||||||
Matchers.tests.cpp:<line number>: passed: empty, UnorderedEquals(empty) for: { } UnorderedEquals: { }
|
Matchers.tests.cpp:<line number>: passed: empty, UnorderedEquals(empty) for: { } UnorderedEquals: { }
|
||||||
Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: passed: permuted, UnorderedEquals(v) for: { 2, 3, 1 } UnorderedEquals: { 1, 2, 3 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5, (UnorderedEquals<int, std::allocator<int>, CustomAllocator<int>>(permuted)) for: { 1, 2, 3 } UnorderedEquals: { 2, 3, 1 }
|
||||||
|
Matchers.tests.cpp:<line number>: passed: v5_permuted, UnorderedEquals(v5) for: { 1, 3, 2 } UnorderedEquals: { 1, 2, 3 }
|
||||||
Matchers.tests.cpp:<line number>: failed: v, VectorContains(-1) for: { 1, 2, 3 } Contains: -1
|
Matchers.tests.cpp:<line number>: failed: v, VectorContains(-1) for: { 1, 2, 3 } Contains: -1
|
||||||
Matchers.tests.cpp:<line number>: failed: empty, VectorContains(1) for: { } Contains: 1
|
Matchers.tests.cpp:<line number>: failed: empty, VectorContains(1) for: { } Contains: 1
|
||||||
Matchers.tests.cpp:<line number>: failed: empty, Contains(v) for: { } Contains: { 1, 2, 3 }
|
Matchers.tests.cpp:<line number>: failed: empty, Contains(v) for: { } Contains: { 1, 2, 3 }
|
||||||
@@ -1561,48 +1664,9 @@ Xml.tests.cpp:<line number>: passed: encode( stringWithQuotes, Catch::XmlEncode:
|
|||||||
"don't "quote" me on that"
|
"don't "quote" me on that"
|
||||||
Xml.tests.cpp:<line number>: passed: encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]"
|
Xml.tests.cpp:<line number>: passed: encode( "[\x01]" ) == "[\\x01]" for: "[\x01]" == "[\x01]"
|
||||||
Xml.tests.cpp:<line number>: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]"
|
Xml.tests.cpp:<line number>: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F]" == "[\x7F]"
|
||||||
Xml.tests.cpp:<line number>: passed: encode(u8"Here be 👾") == u8"Here be 👾" for: "Here be 👾" == "Here be 👾"
|
Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", "." } ( Contains: "." and Contains: "!hide" )
|
||||||
Xml.tests.cpp:<line number>: passed: encode(u8"šš") == u8"šš" for: "šš" == "šš"
|
Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", "." } ( Contains: "." and Contains: "!hide" )
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xDF\xBF") == "\xDF\xBF" for: "߿" == "߿"
|
Tag.tests.cpp:<line number>: passed: testcase.tags, VectorContains(std::string(".")) && VectorContains(std::string("!hide")) for: { "!hide", ".", "foo" } ( Contains: "." and Contains: "!hide" )
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\xA0\x80") == "\xE0\xA0\x80" for: "ࠀ" == "ࠀ"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xED\x9F\xBF") == "\xED\x9F\xBF" for: "" == ""
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xEE\x80\x80") == "\xEE\x80\x80" for: "" == ""
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xEF\xBF\xBF") == "\xEF\xBF\xBF" for: "" == ""
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x90\x80\x80") == "\xF0\x90\x80\x80" for: "𐀀" == "𐀀"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x8F\xBF\xBF") == "\xF4\x8F\xBF\xBF" for: "" == ""
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("Here \xFF be 👾") == u8"Here \\xFF be 👾" for: "Here \xFF be 👾" == "Here \xFF be 👾"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xFF") == "\\xFF" for: "\xFF" == "\xFF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xC5\xC5\xA0") == u8"\\xC5Š" for: "\xC5Š" == "\xC5Š"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x90\x80\x80") == u8"\\xF4\\x90\\x80\\x80" for: "\xF4\x90\x80\x80" == "\xF4\x90\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xC0\x80") == u8"\\xC0\\x80" for: "\xC0\x80" == "\xC0\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80\x80") == u8"\\xF0\\x80\\x80\\x80" for: "\xF0\x80\x80\x80" == "\xF0\x80\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xC1\xBF") == u8"\\xC1\\xBF" for: "\xC1\xBF" == "\xC1\xBF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\x9F\xBF") == u8"\\xE0\\x9F\\xBF" for: "\xE0\x9F\xBF" == "\xE0\x9F\xBF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x8F\xBF\xBF") == u8"\\xF0\\x8F\\xBF\\xBF" for: "\xF0\x8F\xBF\xBF" == "\xF0\x8F\xBF\xBF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xA0\x80") == "\xED\xA0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xAF\xBF") == "\xED\xAF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xB0\x80") == "\xED\xB0\x80" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xED\xBF\xBF") == "\xED\xBF\xBF" for: "<22><><EFBFBD>" == "<22><><EFBFBD>"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\x80") == u8"\\x80" for: "\x80" == "\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\x81") == u8"\\x81" for: "\x81" == "\x81"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xBC") == u8"\\xBC" for: "\xBC" == "\xBC"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xBF") == u8"\\xBF" for: "\xBF" == "\xBF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF5\x80\x80\x80") == u8"\\xF5\\x80\\x80\\x80" for: "\xF5\x80\x80\x80" == "\xF5\x80\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF6\x80\x80\x80") == u8"\\xF6\\x80\\x80\\x80" for: "\xF6\x80\x80\x80" == "\xF6\x80\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF7\x80\x80\x80") == u8"\\xF7\\x80\\x80\\x80" for: "\xF7\x80\x80\x80" == "\xF7\x80\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xDE") == u8"\\xDE" for: "\xDE" == "\xDE"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xDF") == u8"\\xDF" for: "\xDF" == "\xDF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE0") == u8"\\xE0" for: "\xE0" == "\xE0"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xEF") == u8"\\xEF" for: "\xEF" == "\xEF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0") == u8"\\xF0" for: "\xF0" == "\xF0"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF4") == u8"\\xF4" for: "\xF4" == "\xF4"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\x80") == u8"\\xE0\\x80" for: "\xE0\x80" == "\xE0\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE0\xBF") == u8"\\xE0\\xBF" for: "\xE0\xBF" == "\xE0\xBF"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xE1\x80") == u8"\\xE1\\x80" for: "\xE1\x80" == "\xE1\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80") == u8"\\xF0\\x80" for: "\xF0\x80" == "\xF0\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80") == u8"\\xF4\\x80" for: "\xF4\x80" == "\xF4\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF0\x80\x80") == u8"\\xF0\\x80\\x80" for: "\xF0\x80\x80" == "\xF0\x80\x80"
|
|
||||||
Xml.tests.cpp:<line number>: passed: encode("\xF4\x80\x80") == u8"\\xF4\\x80\\x80" for: "\xF4\x80\x80" == "\xF4\x80\x80"
|
|
||||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }"
|
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( empty ) == "{ }" for: "{ }" == "{ }"
|
||||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
|
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( oneValue ) == "{ 42 }" for: "{ 42 }" == "{ 42 }"
|
||||||
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
|
ToStringVector.tests.cpp:<line number>: passed: Catch::Detail::stringify( twoValues ) == "{ 42, 250 }" for: "{ 42, 250 }" == "{ 42, 250 }"
|
||||||
@@ -1704,7 +1768,7 @@ StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "'", "|'")
|
|||||||
StringManip.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
|
StringManip.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
|
||||||
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
|
Misc.tests.cpp:<line number>: failed: false with 1 message: '3'
|
||||||
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
|
Message.tests.cpp:<line number>: failed: false with 2 messages: 'hi' and 'i := 7'
|
||||||
Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
|
Tag.tests.cpp:<line number>: passed: testcase.tags, Catch::VectorContains(std::string("magic-tag")) && Catch::VectorContains(std::string(".")) for: { "!hide", ".", "magic-tag" } ( Contains: "magic-tag" and Contains: "." )
|
||||||
StringManip.tests.cpp:<line number>: passed: splitStringRef("", ','), Equals(std::vector<StringRef>()) for: { } Equals: { }
|
StringManip.tests.cpp:<line number>: passed: splitStringRef("", ','), Equals(std::vector<StringRef>()) for: { } Equals: { }
|
||||||
StringManip.tests.cpp:<line number>: passed: splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}) for: { abc } Equals: { abc }
|
StringManip.tests.cpp:<line number>: passed: splitStringRef("abc", ','), Equals(std::vector<StringRef>{"abc"}) for: { abc } Equals: { abc }
|
||||||
StringManip.tests.cpp:<line number>: passed: splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}) for: { abc, def } Equals: { abc, def }
|
StringManip.tests.cpp:<line number>: passed: splitStringRef("abc,def", ','), Equals(std::vector<StringRef>{"abc", "def"}) for: { abc, def } Equals: { abc, def }
|
||||||
|
@@ -1380,6 +1380,6 @@ due to unexpected exception with message:
|
|||||||
Why would you throw a std::string?
|
Why would you throw a std::string?
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 305 | 231 passed | 70 failed | 4 failed as expected
|
test cases: 322 | 248 passed | 70 failed | 4 failed as expected
|
||||||
assertions: 1695 | 1543 passed | 131 failed | 21 failed as expected
|
assertions: 1759 | 1607 passed | 131 failed | 21 failed as expected
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user