mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 16:35:40 +02:00
Compare commits
154 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9e1bdca466 | ||
![]() |
be49a539e4 | ||
![]() |
558bbe7d24 | ||
![]() |
f4881f172a | ||
![]() |
de06340e7d | ||
![]() |
4dd6e81d0f | ||
![]() |
9e6d7bbf00 | ||
![]() |
dfb025cf08 | ||
![]() |
c638c57209 | ||
![]() |
a575536abe | ||
![]() |
1eb42eed97 | ||
![]() |
46e99e258f | ||
![]() |
a212fb440b | ||
![]() |
1e98c820bb | ||
![]() |
bcfa9b1775 | ||
![]() |
a3876adba6 | ||
![]() |
2a4725b40e | ||
![]() |
a81c01d4f9 | ||
![]() |
60b05b2041 | ||
![]() |
232ea3c456 | ||
![]() |
a5c900d077 | ||
![]() |
8b01883854 | ||
![]() |
86da2846af | ||
![]() |
ef9150fe6f | ||
![]() |
84fa76e985 | ||
![]() |
fcd91c7d6b | ||
![]() |
efbf50fc7d | ||
![]() |
64fd5b8058 | ||
![]() |
ee73989f9b | ||
![]() |
646e1f608d | ||
![]() |
6f75acbfb5 | ||
![]() |
9c3cc4a076 | ||
![]() |
f3972f0695 | ||
![]() |
38e1731f69 | ||
![]() |
0947752a44 | ||
![]() |
0646e0283c | ||
![]() |
90663b2e75 | ||
![]() |
7667a7d89c | ||
![]() |
9773d89ab4 | ||
![]() |
2067c8d3bd | ||
![]() |
1742ab76a2 | ||
![]() |
898d111f72 | ||
![]() |
5202993555 | ||
![]() |
f061dabbad | ||
![]() |
1a501fcb48 | ||
![]() |
94121a5f6d | ||
![]() |
92e25049cf | ||
![]() |
fdcd46420e | ||
![]() |
7c25dae9ea | ||
![]() |
7f18282d17 | ||
![]() |
1cdaa48a0b | ||
![]() |
1a63fad8d6 | ||
![]() |
d6f2fd486c | ||
![]() |
5884ec1e28 | ||
![]() |
eb783fc20e | ||
![]() |
38248f3f2c | ||
![]() |
c9de7dd12d | ||
![]() |
52cbb507ab | ||
![]() |
83bfae1a50 | ||
![]() |
f7f592dfc9 | ||
![]() |
78804ea304 | ||
![]() |
b93284716e | ||
![]() |
15cf3caace | ||
![]() |
12a8dfa2f2 | ||
![]() |
797d3b04df | ||
![]() |
82b8744b8c | ||
![]() |
ce80358306 | ||
![]() |
283e2e6d41 | ||
![]() |
d6c7392b24 | ||
![]() |
9ee4c1db52 | ||
![]() |
76790604f5 | ||
![]() |
e21c6aa94d | ||
![]() |
7a59d5027f | ||
![]() |
c8941cccb5 | ||
![]() |
5eeb6aa361 | ||
![]() |
1c1b447ede | ||
![]() |
e1d81174db | ||
![]() |
4846ad59e1 | ||
![]() |
ff2b3c85a7 | ||
![]() |
b55424d3b2 | ||
![]() |
e69c7ce297 | ||
![]() |
7be8ba36c1 | ||
![]() |
ad120965cf | ||
![]() |
f460a7d8f9 | ||
![]() |
ebf89000f1 | ||
![]() |
7d00cb83f1 | ||
![]() |
e69afb6252 | ||
![]() |
9fb38fcc14 | ||
![]() |
0f49a600b0 | ||
![]() |
5c0efa1cfc | ||
![]() |
1579744ddd | ||
![]() |
9b0e740e31 | ||
![]() |
1af60ef5ab | ||
![]() |
3743295ca8 | ||
![]() |
ed582bde4d | ||
![]() |
6c1145d922 | ||
![]() |
b957eb4172 | ||
![]() |
0eb99fb569 | ||
![]() |
bf221583b1 | ||
![]() |
44722f9ed3 | ||
![]() |
35a57b070f | ||
![]() |
1dce91d78e | ||
![]() |
b8553d62a3 | ||
![]() |
504607701b | ||
![]() |
788f81230f | ||
![]() |
c5301bf8bf | ||
![]() |
d2a130f243 | ||
![]() |
7be8a41adf | ||
![]() |
021fcee636 | ||
![]() |
3a47b8b072 | ||
![]() |
2771a8ee9a | ||
![]() |
7abd7db2c8 | ||
![]() |
88d7b8da25 | ||
![]() |
df0b0e64e1 | ||
![]() |
4c7b7d04fe | ||
![]() |
90988f578c | ||
![]() |
e5fe3e877a | ||
![]() |
6c5c4c43a0 | ||
![]() |
c323658483 | ||
![]() |
db570b7e24 | ||
![]() |
0074926e5c | ||
![]() |
6496c51c95 | ||
![]() |
3dd523bdf5 | ||
![]() |
8d5d49299b | ||
![]() |
d0287e3b56 | ||
![]() |
dd99a66cf4 | ||
![]() |
ae590fe216 | ||
![]() |
7f791fa08f | ||
![]() |
0510d4755f | ||
![]() |
e92b9c07c3 | ||
![]() |
88a6ff0b65 | ||
![]() |
9e7c281e6e | ||
![]() |
64be2ad96c | ||
![]() |
c651f239f0 | ||
![]() |
43769a19f7 | ||
![]() |
200d3ad824 | ||
![]() |
aa7b0c9104 | ||
![]() |
375f2052bd | ||
![]() |
dc6b83bec9 | ||
![]() |
f00257e374 | ||
![]() |
414dcae34a | ||
![]() |
d2d8455b57 | ||
![]() |
ab30621138 | ||
![]() |
1ca8f43b01 | ||
![]() |
dfb83f20e9 | ||
![]() |
319bddd5b8 | ||
![]() |
931441251e | ||
![]() |
ea1f326261 | ||
![]() |
3641706923 | ||
![]() |
3b801c4fda | ||
![]() |
e11508b48a | ||
![]() |
886d799b79 | ||
![]() |
8b78087412 | ||
![]() |
6c99b04c87 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -17,6 +17,6 @@
|
|||||||
|
|
||||||
# Keep the single include header with LFs to make sure it is uploaded,
|
# Keep the single include header with LFs to make sure it is uploaded,
|
||||||
# hashed etc with LF
|
# hashed etc with LF
|
||||||
single_include/*.hpp eol=lf
|
single_include/**/*.hpp eol=lf
|
||||||
# Also keep the LICENCE file with LFs for the same reason
|
# Also keep the LICENCE file with LFs for the same reason
|
||||||
LICENCE.txt eol=lf
|
LICENCE.txt eol=lf
|
||||||
|
92
.travis.yml
92
.travis.yml
@@ -11,6 +11,7 @@ common_sources: &all_sources
|
|||||||
- llvm-toolchain-trusty-3.9
|
- llvm-toolchain-trusty-3.9
|
||||||
- llvm-toolchain-trusty-4.0
|
- llvm-toolchain-trusty-4.0
|
||||||
- llvm-toolchain-trusty-5.0
|
- llvm-toolchain-trusty-5.0
|
||||||
|
- llvm-toolchain-trusty-6.0
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
@@ -67,6 +68,14 @@ matrix:
|
|||||||
packages: ['clang-5.0']
|
packages: ['clang-5.0']
|
||||||
env: COMPILER='clang++-5.0'
|
env: COMPILER='clang++-5.0'
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0']
|
||||||
|
env: COMPILER='clang++-6.0'
|
||||||
|
|
||||||
# 2/ Linux GCC Builds
|
# 2/ Linux GCC Builds
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
@@ -108,6 +117,14 @@ matrix:
|
|||||||
packages: ['g++-7']
|
packages: ['g++-7']
|
||||||
env: COMPILER='g++-7'
|
env: COMPILER='g++-7'
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: &gcc8
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['g++-8']
|
||||||
|
env: COMPILER='g++-8'
|
||||||
|
|
||||||
# 3b/ Linux C++14 Clang builds
|
# 3b/ Linux C++14 Clang builds
|
||||||
# Note that we need newer libstdc++ for C++14 support
|
# Note that we need newer libstdc++ for C++14 support
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -144,6 +161,14 @@ matrix:
|
|||||||
packages: ['clang-5.0', 'libstdc++-6-dev']
|
packages: ['clang-5.0', 'libstdc++-6-dev']
|
||||||
env: COMPILER='clang++-5.0' CPP14=1
|
env: COMPILER='clang++-5.0' CPP14=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-6-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP14=1
|
||||||
|
|
||||||
|
|
||||||
# 4a/ Linux C++14 GCC builds
|
# 4a/ Linux C++14 GCC builds
|
||||||
- os: linux
|
- os: linux
|
||||||
@@ -156,6 +181,11 @@ matrix:
|
|||||||
addons: *gcc7
|
addons: *gcc7
|
||||||
env: COMPILER='g++-7' CPP14=1
|
env: COMPILER='g++-7' CPP14=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc8
|
||||||
|
env: COMPILER='g++-8' CPP14=1
|
||||||
|
|
||||||
# 5/ OSX Clang Builds
|
# 5/ OSX Clang Builds
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode7.3
|
osx_image: xcode7.3
|
||||||
@@ -189,7 +219,7 @@ matrix:
|
|||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['lcov', 'g++-7']
|
packages: ['lcov', 'g++-7']
|
||||||
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1
|
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
@@ -199,7 +229,7 @@ matrix:
|
|||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-trusty
|
- llvm-toolchain-trusty
|
||||||
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1
|
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1 EXTRAS=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
@@ -207,19 +237,46 @@ matrix:
|
|||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-7']
|
packages: ['valgrind', 'lcov', 'g++-7']
|
||||||
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
|
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode9.1
|
osx_image: xcode9.1
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1
|
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
|
||||||
|
|
||||||
|
# 7/ C++17 builds
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc7
|
||||||
|
env: COMPILER='g++-7' CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc7
|
||||||
|
env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-8-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-8-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP17=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||||
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
||||||
- |
|
- |
|
||||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||||
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
|
CMAKE_URL="http://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz"
|
||||||
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||||
@@ -232,27 +289,24 @@ before_script:
|
|||||||
# Regenerate single header file, so it is tested in the examples...
|
# Regenerate single header file, so it is tested in the examples...
|
||||||
- python scripts/generateSingleHeader.py
|
- python scripts/generateSingleHeader.py
|
||||||
|
|
||||||
- |
|
|
||||||
# Use Debug builds for running Valgrind and building examples
|
# Use Debug builds for running Valgrind and building examples
|
||||||
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE}
|
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
|
||||||
# Don't bother with release build for coverage build
|
# Don't bother with release build for coverage build
|
||||||
cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- cd Build-Debug
|
||||||
cd Build-Debug
|
- make -j 2
|
||||||
make -j 2
|
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
|
||||||
# Coverage collection does not work for OS X atm
|
# Coverage collection does not work for OS X atm
|
||||||
echo "${TRAVIS_OS_NAME}";
|
- |
|
||||||
echo "${COVERAGE}";
|
|
||||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
|
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
|
||||||
make gcov
|
make gcov
|
||||||
make lcov
|
make lcov
|
||||||
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
||||||
fi
|
fi
|
||||||
# Go to release build
|
- # Go to release build
|
||||||
cd ../Build-Release
|
- cd ../Build-Release
|
||||||
make -j 2
|
- make -j 2
|
||||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||||
|
10
CMake/Catch2Config.cmake.in
Normal file
10
CMake/Catch2Config.cmake.in
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
|
||||||
|
# Avoid repeatedly including the targets
|
||||||
|
if(NOT TARGET Catch2::Catch2)
|
||||||
|
# Provide path for scripts
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
|
||||||
|
endif()
|
26
CMake/MiscFunctions.cmake
Normal file
26
CMake/MiscFunctions.cmake
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#checks that the given hard-coded list contains all headers + sources in the given folder
|
||||||
|
function(CheckFileList LIST_VAR FOLDER)
|
||||||
|
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||||
|
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||||
|
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||||
|
"${FOLDER}/*.hpp"
|
||||||
|
"${FOLDER}/*.h")
|
||||||
|
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||||
|
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||||
|
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||||
|
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(CheckFileListRec LIST_VAR FOLDER)
|
||||||
|
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||||
|
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||||
|
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||||
|
"${FOLDER}/*.hpp"
|
||||||
|
"${FOLDER}/*.h")
|
||||||
|
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||||
|
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||||
|
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||||
|
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
7
CMake/catch2.pc.in
Normal file
7
CMake/catch2.pc.in
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: Catch2
|
||||||
|
Description: A modern, C++-native, header-only, test framework for C++11
|
||||||
|
URL: https://github.com/catchorg/Catch2
|
||||||
|
Version: @Catch2_VERSION@
|
||||||
|
Cflags: -I${includedir}
|
568
CMakeLists.txt
568
CMakeLists.txt
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.1)
|
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
|
||||||
@@ -6,14 +6,24 @@ if(NOT DEFINED PROJECT_NAME)
|
|||||||
set(NOT_SUBPROJECT ON)
|
set(NOT_SUBPROJECT ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(Catch2 LANGUAGES CXX VERSION 2.2.1)
|
project(Catch2 LANGUAGES CXX VERSION 2.4.1)
|
||||||
|
|
||||||
|
# Provide path for scripts
|
||||||
|
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_EXAMPLES "Build documentation examples" OFF)
|
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
|
||||||
|
option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF)
|
||||||
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
|
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
|
||||||
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
|
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
|
||||||
|
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
|
||||||
|
option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
|
||||||
|
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
@@ -27,428 +37,172 @@ 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()
|
||||||
|
|
||||||
#checks that the given hard-coded list contains all headers + sources in the given folder
|
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||||
function(CheckFileList LIST_VAR FOLDER)
|
find_package(PythonInterp)
|
||||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
if (NOT PYTHONINTERP_FOUND)
|
||||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
message(FATAL_ERROR "Python not found, but required for tests")
|
||||||
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
|
|
||||||
"${FOLDER}/*.hpp"
|
|
||||||
"${FOLDER}/*.h")
|
|
||||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
|
||||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
|
||||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
|
||||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(CheckFileListRec LIST_VAR FOLDER)
|
|
||||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
|
||||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
|
||||||
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
|
|
||||||
"${FOLDER}/*.hpp"
|
|
||||||
"${FOLDER}/*.h")
|
|
||||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
|
||||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
|
||||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
|
||||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# define the sources of the self test
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(TEST_SOURCES
|
|
||||||
${SELF_TEST_DIR}/TestMain.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Class.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Compilation.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Condition.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Decomposition.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/EnumToString.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Exception.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringVector.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
|
|
||||||
)
|
|
||||||
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
|
|
||||||
|
|
||||||
# A set of impl files that just #include a single header
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(SURROGATE_SOURCES
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
|
|
||||||
)
|
|
||||||
CheckFileList(SURROGATE_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
|
|
||||||
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(TOP_LEVEL_HEADERS
|
|
||||||
${HEADER_DIR}/catch.hpp
|
|
||||||
${HEADER_DIR}/catch_with_main.hpp
|
|
||||||
)
|
|
||||||
CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(EXTERNAL_HEADERS
|
|
||||||
${HEADER_DIR}/external/clara.hpp
|
|
||||||
)
|
|
||||||
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
|
|
||||||
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(INTERNAL_HEADERS
|
|
||||||
${HEADER_DIR}/internal/catch_approx.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertionhandler.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertioninfo.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertionresult.h
|
|
||||||
${HEADER_DIR}/internal/catch_capture.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_capture_matchers.h
|
|
||||||
${HEADER_DIR}/internal/catch_clara.h
|
|
||||||
${HEADER_DIR}/internal/catch_commandline.h
|
|
||||||
${HEADER_DIR}/internal/catch_common.h
|
|
||||||
${HEADER_DIR}/internal/catch_compiler_capabilities.h
|
|
||||||
${HEADER_DIR}/internal/catch_config.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_console_colour.h
|
|
||||||
${HEADER_DIR}/internal/catch_context.h
|
|
||||||
${HEADER_DIR}/internal/catch_debug_console.h
|
|
||||||
${HEADER_DIR}/internal/catch_debugger.h
|
|
||||||
${HEADER_DIR}/internal/catch_decomposer.h
|
|
||||||
${HEADER_DIR}/internal/catch_default_main.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_enforce.h
|
|
||||||
${HEADER_DIR}/internal/catch_errno_guard.h
|
|
||||||
${HEADER_DIR}/internal/catch_exception_translator_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_external_interfaces.h
|
|
||||||
${HEADER_DIR}/internal/catch_fatal_condition.h
|
|
||||||
${HEADER_DIR}/internal/catch_impl.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_exception.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_reporter.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_runner.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_testcase.h
|
|
||||||
${HEADER_DIR}/internal/catch_leak_detector.h
|
|
||||||
${HEADER_DIR}/internal/catch_list.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_floating.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
|
||||||
${HEADER_DIR}/internal/catch_message.h
|
|
||||||
${HEADER_DIR}/internal/catch_objc.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_option.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_platform.h
|
|
||||||
${HEADER_DIR}/internal/catch_random_number_generator.h
|
|
||||||
${HEADER_DIR}/internal/catch_reenable_warnings.h
|
|
||||||
${HEADER_DIR}/internal/catch_reporter_registrars.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_reporter_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_result_type.h
|
|
||||||
${HEADER_DIR}/internal/catch_run_context.h
|
|
||||||
${HEADER_DIR}/internal/catch_benchmark.h
|
|
||||||
${HEADER_DIR}/internal/catch_section.h
|
|
||||||
${HEADER_DIR}/internal/catch_section_info.h
|
|
||||||
${HEADER_DIR}/internal/catch_session.h
|
|
||||||
${HEADER_DIR}/internal/catch_startup_exception_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_stream.h
|
|
||||||
${HEADER_DIR}/internal/catch_stringref.h
|
|
||||||
${HEADER_DIR}/internal/catch_string_manip.h
|
|
||||||
${HEADER_DIR}/internal/catch_suppress_warnings.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_info.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_tracker.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec_parser.h
|
|
||||||
${HEADER_DIR}/internal/catch_text.h
|
|
||||||
${HEADER_DIR}/internal/catch_timer.h
|
|
||||||
${HEADER_DIR}/internal/catch_tostring.h
|
|
||||||
${HEADER_DIR}/internal/catch_totals.h
|
|
||||||
${HEADER_DIR}/internal/catch_uncaught_exceptions.h
|
|
||||||
${HEADER_DIR}/internal/catch_user_interfaces.h
|
|
||||||
${HEADER_DIR}/internal/catch_version.h
|
|
||||||
${HEADER_DIR}/internal/catch_wildcard_pattern.h
|
|
||||||
${HEADER_DIR}/internal/catch_windows_h_proxy.h
|
|
||||||
${HEADER_DIR}/internal/catch_xmlwriter.h
|
|
||||||
)
|
|
||||||
set(IMPL_SOURCES
|
|
||||||
${HEADER_DIR}/internal/catch_approx.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_assertionhandler.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_assertionresult.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_benchmark.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_capture_matchers.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_commandline.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_common.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_config.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_console_colour.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_context.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_debug_console.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_debugger.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_decomposer.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_errno_guard.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_exception_translator_registry.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_fatal_condition.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_capture.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_config.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_exception.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_registry_hub.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_runner.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_testcase.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_list.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_leak_detector.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_matchers.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_floating.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_string.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_message.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_registry_hub.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_reporter.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_random_number_generator.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_reporter_registry.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_result_type.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_run_context.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_section.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_section_info.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_session.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_stream.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_stringref.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_string_manip.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_registry.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_info.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_tracker.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_registry.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec_parser.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_timer.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_tostring.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_totals.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_uncaught_exceptions.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_version.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
|
|
||||||
${HEADER_DIR}/internal/catch_xmlwriter.cpp
|
|
||||||
)
|
|
||||||
set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
|
|
||||||
CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(REPORTER_HEADERS
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_compact.h
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_console.h
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_junit.h
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_multi.h
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_xml.h
|
|
||||||
)
|
|
||||||
set(REPORTER_SOURCES
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_bases.cpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_compact.cpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_console.cpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_junit.cpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_multi.cpp
|
|
||||||
${HEADER_DIR}/reporters/catch_reporter_xml.cpp
|
|
||||||
)
|
|
||||||
set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
|
|
||||||
CheckFileList(REPORTER_FILES ${HEADER_DIR}/reporters)
|
|
||||||
|
|
||||||
# Specify the headers, too, so CLion recognises them as project files
|
|
||||||
set(HEADERS
|
|
||||||
${TOP_LEVEL_HEADERS}
|
|
||||||
${EXTERNAL_HEADERS}
|
|
||||||
${INTERNAL_HEADERS}
|
|
||||||
${REPORTER_HEADERS}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Provide some groupings for IDEs
|
|
||||||
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
|
||||||
SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
|
|
||||||
|
|
||||||
|
|
||||||
# Projects consuming Catch via ExternalProject_Add might want to use install step
|
|
||||||
# without building all of our selftests.
|
|
||||||
|
|
||||||
if(DEFINED NO_SELFTEST)
|
|
||||||
message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead")
|
|
||||||
if (NO_SELFTEST)
|
|
||||||
set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
|
|
||||||
else()
|
|
||||||
set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
|
|
||||||
endif()
|
endif()
|
||||||
|
add_subdirectory(projects)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CTest)
|
|
||||||
|
|
||||||
if (BUILD_TESTING AND NOT_SUBPROJECT)
|
|
||||||
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
|
|
||||||
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
|
|
||||||
|
|
||||||
if(USE_CPP14)
|
|
||||||
message(STATUS "Enabling C++14")
|
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 14)
|
|
||||||
else()
|
|
||||||
message(STATUS "Enabling C++11")
|
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 11)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
|
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
|
|
||||||
|
|
||||||
if (CATCH_ENABLE_COVERAGE)
|
|
||||||
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
|
||||||
find_package(codecov)
|
|
||||||
add_coverage(SelfTest)
|
|
||||||
list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'")
|
|
||||||
coverage_evaluate()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add per compiler options
|
|
||||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
|
||||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic)
|
|
||||||
if (CATCH_ENABLE_WERROR)
|
|
||||||
target_compile_options( SelfTest PRIVATE -Werror)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
# Clang specific options go here
|
|
||||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
|
||||||
target_compile_options( SelfTest PRIVATE -Wweak-vtables -Wexit-time-destructors -Wglobal-constructors -Wmissing-noreturn )
|
|
||||||
endif()
|
|
||||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
|
|
||||||
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
|
|
||||||
target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 )
|
|
||||||
if (CATCH_ENABLE_WERROR)
|
|
||||||
target_compile_options( SelfTest PRIVATE /WX)
|
|
||||||
endif()
|
|
||||||
# Force MSVC to consider everything as encoded in utf-8
|
|
||||||
target_compile_options( SelfTest PRIVATE /utf-8 )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# configure unit tests via CTest
|
|
||||||
include(CTest)
|
|
||||||
add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest>)
|
|
||||||
|
|
||||||
add_test(NAME ListTests COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
|
||||||
set_tests_properties(ListTests PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "[0-9]+ test cases"
|
|
||||||
FAIL_REGULAR_EXPRESSION "Hidden Test"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
|
|
||||||
set_tests_properties(ListTags PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
|
|
||||||
FAIL_REGULAR_EXPRESSION "[.]")
|
|
||||||
|
|
||||||
add_test(NAME ListReporters COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
|
|
||||||
set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
|
|
||||||
|
|
||||||
add_test(NAME ListTestNamesOnly COMMAND $<TARGET_FILE:SelfTest> --list-test-names-only)
|
|
||||||
set_tests_properties(ListTestNamesOnly PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "Regex string matcher"
|
|
||||||
FAIL_REGULAR_EXPRESSION "Hidden Test")
|
|
||||||
|
|
||||||
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions)
|
|
||||||
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
|
|
||||||
|
|
||||||
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
|
|
||||||
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
|
|
||||||
|
|
||||||
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
|
|
||||||
add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
|
|
||||||
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
|
|
||||||
|
|
||||||
if (CATCH_USE_VALGRIND)
|
|
||||||
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
|
||||||
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
|
||||||
set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
|
|
||||||
add_test(NAME ValgrindListTags COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tags)
|
|
||||||
set_tests_properties(ValgrindListTags PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif() # !NO_SELFTEST
|
|
||||||
|
|
||||||
|
|
||||||
if(CATCH_BUILD_EXAMPLES)
|
if(CATCH_BUILD_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
|
if(CATCH_BUILD_EXTRA_TESTS)
|
||||||
|
add_subdirectory(projects/ExtraTests)
|
||||||
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
|
||||||
|
|
||||||
## Provide some pkg-config integration
|
|
||||||
# Don't bother on Windows
|
|
||||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
|
||||||
|
|
||||||
set(PKGCONFIG_INSTALL_DIR
|
|
||||||
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
|
||||||
CACHE PATH "Path where catch.pc is installed"
|
|
||||||
)
|
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/catch.pc.in ${CMAKE_CURRENT_BINARY_DIR}/catch.pc @ONLY)
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/catch.pc DESTINATION ${PKGCONFIG_INSTALL_DIR})
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# add catch as a 'linkable' target
|
# add catch as a 'linkable' target
|
||||||
add_library(Catch INTERFACE)
|
add_library(Catch2 INTERFACE)
|
||||||
|
|
||||||
# depend on some obvious c++11 features so the dependency is transitively added dependants
|
|
||||||
target_compile_features(Catch INTERFACE cxx_auto_type cxx_constexpr cxx_noexcept)
|
|
||||||
|
|
||||||
target_include_directories(Catch
|
|
||||||
INTERFACE
|
# depend on some obvious c++11 features so the dependency is transitively added dependents
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/single_include>
|
target_compile_features(Catch2
|
||||||
$<INSTALL_INTERFACE:include/catch>
|
INTERFACE
|
||||||
$<INSTALL_INTERFACE:include>)
|
cxx_alignas
|
||||||
|
cxx_alignof
|
||||||
|
cxx_attributes
|
||||||
|
cxx_auto_type
|
||||||
|
cxx_constexpr
|
||||||
|
cxx_defaulted_functions
|
||||||
|
cxx_deleted_functions
|
||||||
|
cxx_final
|
||||||
|
cxx_lambdas
|
||||||
|
cxx_noexcept
|
||||||
|
cxx_override
|
||||||
|
cxx_range_for
|
||||||
|
cxx_rvalue_references
|
||||||
|
cxx_static_assert
|
||||||
|
cxx_strong_enums
|
||||||
|
cxx_trailing_return_types
|
||||||
|
cxx_unicode_literals
|
||||||
|
cxx_user_literals
|
||||||
|
cxx_variadic_macros
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(Catch2
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/single_include>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
|
)
|
||||||
|
|
||||||
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
|
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
|
||||||
add_library(Catch2::Catch ALIAS Catch)
|
add_library(Catch2::Catch2 ALIAS Catch2)
|
||||||
|
|
||||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
# Only perform the installation steps when Catch is not being used as
|
||||||
|
# a subproject via `add_subdirectory`, or the destinations will break,
|
||||||
|
# see https://github.com/catchorg/Catch2/issues/1373
|
||||||
|
if (NOT_SUBPROJECT)
|
||||||
|
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||||
|
|
||||||
# create and install an export set for catch target as Catch2::Catch
|
configure_package_config_file(
|
||||||
install(TARGETS Catch EXPORT Catch2Config DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
|
||||||
|
INSTALL_DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
install(EXPORT Catch2Config
|
|
||||||
NAMESPACE Catch2::
|
|
||||||
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})
|
|
||||||
|
|
||||||
# install Catch2ConfigVersion.cmake file to handle versions in find_package
|
# create and install an export set for catch target as Catch2::Catch
|
||||||
include(CMakePackageConfigHelpers)
|
install(
|
||||||
|
TARGETS
|
||||||
|
Catch2
|
||||||
|
EXPORT
|
||||||
|
Catch2Targets
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
write_basic_package_version_file(
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
|
||||||
COMPATIBILITY SameMajorVersion)
|
|
||||||
|
|
||||||
install(FILES
|
install(
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
EXPORT
|
||||||
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})
|
Catch2Targets
|
||||||
|
NAMESPACE
|
||||||
|
Catch2::
|
||||||
|
DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# By default, FooConfigVersion is tied to architecture that it was
|
||||||
|
# generated on. Because Catch2 is header-only, it is arch-independent
|
||||||
|
# and thus Catch2ConfigVersion should not be tied to the architecture
|
||||||
|
# it was generated on.
|
||||||
|
#
|
||||||
|
# CMake does not provide a direct customization point for this in
|
||||||
|
# `write_basic_package_version_file`, but it can be accomplished
|
||||||
|
# indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
|
||||||
|
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||||
|
unset(CMAKE_SIZEOF_VOID_P)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||||
|
COMPATIBILITY
|
||||||
|
SameMajorVersion
|
||||||
|
)
|
||||||
|
set(CMAKE_SIZEOF_VOID_P ${CATCH2_CMAKE_SIZEOF_VOID_P})
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY
|
||||||
|
"single_include/"
|
||||||
|
DESTINATION
|
||||||
|
"${CMAKE_INSTALL_INCLUDEDIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||||
|
DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install documentation
|
||||||
|
if(CATCH_INSTALL_DOCS)
|
||||||
|
install(
|
||||||
|
DIRECTORY
|
||||||
|
docs/
|
||||||
|
DESTINATION
|
||||||
|
"${CMAKE_INSTALL_DOCDIR}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CATCH_INSTALL_HELPERS)
|
||||||
|
# Install CMake scripts
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"contrib/ParseAndAddCatchTests.cmake"
|
||||||
|
"contrib/Catch.cmake"
|
||||||
|
"contrib/CatchAddTests.cmake"
|
||||||
|
DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install debugger helpers
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"contrib/gdbinit"
|
||||||
|
"contrib/lldbinit"
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Provide some pkg-config integration
|
||||||
|
set(PKGCONFIG_INSTALL_DIR
|
||||||
|
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||||
|
CACHE PATH "Path where catch2.pc is installed"
|
||||||
|
)
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
|
||||||
|
DESTINATION
|
||||||
|
${PKGCONFIG_INSTALL_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
endif(NOT_SUBPROJECT)
|
||||||
|
@@ -5,9 +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/zDKMK3eGMC9IP2jy)
|
[](https://wandbox.org/permlink/E0msqwbW7U4PVbHn)
|
||||||
|
[](https://discord.gg/4CWS9zD)
|
||||||
|
|
||||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.2.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
|
||||||
|
<a href="https://github.com/catchorg/Catch2/releases/download/v2.4.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||||
|
|
||||||
## Catch2 is released!
|
## Catch2 is released!
|
||||||
|
|
||||||
@@ -32,5 +34,5 @@ This documentation comprises these three parts:
|
|||||||
|
|
||||||
## More
|
## More
|
||||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
||||||
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)
|
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD)
|
||||||
* See [who else is using Catch2](docs/opensource-users.md#top)
|
* See [who else is using Catch2](docs/opensource-users.md#top)
|
||||||
|
@@ -62,7 +62,7 @@ matrix:
|
|||||||
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip install codecov }
|
- 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" ) { .\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.
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
|
||||||
|
|
||||||
Name: Catch
|
|
||||||
Description: Testing library for C++
|
|
||||||
Version: @Catch2_VERSION@
|
|
||||||
Cflags: -I${includedir}
|
|
14
codecov.yml
14
codecov.yml
@@ -9,6 +9,12 @@ coverage:
|
|||||||
patch:
|
patch:
|
||||||
default:
|
default:
|
||||||
target: 80%
|
target: 80%
|
||||||
|
ignore:
|
||||||
|
- "projects/SelfTest"
|
||||||
|
- "**/catch_reporter_tap.hpp"
|
||||||
|
- "**/catch_reporter_automake.hpp"
|
||||||
|
- "**/catch_reporter_teamcity.hpp"
|
||||||
|
- "**/external/clara.hpp"
|
||||||
|
|
||||||
|
|
||||||
codecov:
|
codecov:
|
||||||
@@ -16,11 +22,3 @@ codecov:
|
|||||||
|
|
||||||
comment:
|
comment:
|
||||||
layout: "diff"
|
layout: "diff"
|
||||||
|
|
||||||
coverage:
|
|
||||||
ignore:
|
|
||||||
- "projects/SelfTest"
|
|
||||||
- "**/catch_reporter_tap.hpp"
|
|
||||||
- "**/catch_reporter_automake.hpp"
|
|
||||||
- "**/catch_reporter_teamcity.hpp"
|
|
||||||
- "**/external/clara.hpp"
|
|
||||||
|
24
conanfile.py
24
conanfile.py
@@ -1,19 +1,31 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from conans import ConanFile
|
from conans import ConanFile, CMake
|
||||||
|
|
||||||
|
|
||||||
class CatchConan(ConanFile):
|
class CatchConan(ConanFile):
|
||||||
name = "Catch"
|
name = "Catch"
|
||||||
version = "2.2.1"
|
version = "2.4.1"
|
||||||
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
||||||
author = "philsquared"
|
author = "philsquared"
|
||||||
generators = "cmake"
|
generators = "cmake"
|
||||||
exports_sources = "single_include/*"
|
# Only needed until conan 1.5 is released
|
||||||
url = "https://github.com/philsquared/Catch"
|
settings = "compiler", "arch"
|
||||||
|
exports_sources = "single_include/*", "CMakeLists.txt", "CMake/catch2.pc.in", "LICENSE.txt"
|
||||||
|
url = "https://github.com/catchorg/Catch2"
|
||||||
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
|
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
self.copy(pattern="catch.hpp", src="single_include", dst="include")
|
cmake = CMake(self)
|
||||||
|
cmake.definitions["BUILD_TESTING"] = "OFF"
|
||||||
|
cmake.definitions["CATCH_INSTALL_DOCS"] = "OFF"
|
||||||
|
cmake.definitions["CATCH_INSTALL_HELPERS"] = "ON"
|
||||||
|
cmake.configure()
|
||||||
|
cmake.install()
|
||||||
|
|
||||||
|
self.copy(pattern="LICENSE.txt", dst="licenses")
|
||||||
|
|
||||||
def package_id(self):
|
def package_id(self):
|
||||||
self.info.header_only()
|
self.info.header_only()
|
||||||
|
@@ -50,8 +50,7 @@ string(REPLACE "\n" ";" output "${output}")
|
|||||||
|
|
||||||
# Parse output
|
# Parse output
|
||||||
foreach(line ${output})
|
foreach(line ${output})
|
||||||
# Test name; strip spaces to get just the name...
|
set(test ${line})
|
||||||
string(REGEX REPLACE " +" "" test "${line}")
|
|
||||||
# ...and add to script
|
# ...and add to script
|
||||||
add_command(add_test
|
add_command(add_test
|
||||||
"${prefix}${test}${suffix}"
|
"${prefix}${test}${suffix}"
|
||||||
|
@@ -143,6 +143,9 @@ function(ParseFile SourceFile TestTarget)
|
|||||||
endif()
|
endif()
|
||||||
string(REPLACE "]" ";" Tags "${Tags}")
|
string(REPLACE "]" ";" Tags "${Tags}")
|
||||||
string(REPLACE "[" "" Tags "${Tags}")
|
string(REPLACE "[" "" Tags "${Tags}")
|
||||||
|
else()
|
||||||
|
# unset tags variable from previous loop
|
||||||
|
unset(Tags)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND Labels ${Tags})
|
list(APPEND Labels ${Tags})
|
||||||
|
16
contrib/gdbinit
Normal file
16
contrib/gdbinit
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# This file provides a way to skip stepping into Catch code when debugging with gdb.
|
||||||
|
#
|
||||||
|
# With the gdb "skip" command you can tell gdb to skip files or functions during debugging.
|
||||||
|
# see https://xaizek.github.io/2016-05-26/skipping-standard-library-in-gdb/ for an example
|
||||||
|
#
|
||||||
|
# Basically the following line tells gdb to skip all functions containing the
|
||||||
|
# regexp "Catch", which matches the complete Catch namespace.
|
||||||
|
# If you want to skip just some parts of the Catch code you can modify the
|
||||||
|
# regexp accordingly.
|
||||||
|
#
|
||||||
|
# If you want to permanently skip stepping into Catch code copy the following
|
||||||
|
# line into your ~/.gdbinit file
|
||||||
|
#
|
||||||
|
|
||||||
|
skip -rfu Catch
|
16
contrib/lldbinit
Normal file
16
contrib/lldbinit
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# This file provides a way to skip stepping into Catch code when debugging with lldb.
|
||||||
|
#
|
||||||
|
# With the setting "target.process.thread.step-avoid-regexp" you can tell lldb
|
||||||
|
# to skip functions matching the regexp
|
||||||
|
#
|
||||||
|
# Basically the following line tells lldb to skip all functions containing the
|
||||||
|
# regexp "Catch", which matches the complete Catch namespace.
|
||||||
|
# If you want to skip just some parts of the Catch code you can modify the
|
||||||
|
# regexp accordingly.
|
||||||
|
#
|
||||||
|
# If you want to permanently skip stepping into Catch code copy the following
|
||||||
|
# line into your ~/.lldbinit file
|
||||||
|
#
|
||||||
|
|
||||||
|
settings set target.process.thread.step-avoid-regexp Catch
|
@@ -12,6 +12,7 @@ Writing tests:
|
|||||||
* [Test fixtures](test-fixtures.md#top)
|
* [Test fixtures](test-fixtures.md#top)
|
||||||
* [Reporters](reporters.md#top)
|
* [Reporters](reporters.md#top)
|
||||||
* [Event Listeners](event-listeners.md#top)
|
* [Event Listeners](event-listeners.md#top)
|
||||||
|
* [Data Generators](generators.md#top)
|
||||||
|
|
||||||
Fine tuning:
|
Fine tuning:
|
||||||
* [Supplying your own main()](own-main.md#top)
|
* [Supplying your own main()](own-main.md#top)
|
||||||
@@ -20,7 +21,10 @@ Fine tuning:
|
|||||||
|
|
||||||
Running:
|
Running:
|
||||||
* [Command line](command-line.md#top)
|
* [Command line](command-line.md#top)
|
||||||
* [CI and Build system integration](build-systems.md#top)
|
|
||||||
|
Odds and ends:
|
||||||
|
* [CMake integration](cmake-integration.md#top)
|
||||||
|
* [CI and other miscellaneous pieces](ci-and-misc.md#top)
|
||||||
|
|
||||||
FAQ:
|
FAQ:
|
||||||
* [Why are my tests slow to compile?](slow-compiles.md#top)
|
* [Why are my tests slow to compile?](slow-compiles.md#top)
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
[Exceptions](#exceptions)<br>
|
[Exceptions](#exceptions)<br>
|
||||||
[Matcher expressions](#matcher-expressions)<br>
|
[Matcher expressions](#matcher-expressions)<br>
|
||||||
[Thread Safety](#thread-safety)<br>
|
[Thread Safety](#thread-safety)<br>
|
||||||
|
[Expressions with commas](#expressions-with-commas)<br>
|
||||||
|
|
||||||
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
||||||
|
|
||||||
@@ -54,33 +55,45 @@ This expression is too complex because of the `||` operator. If you want to chec
|
|||||||
|
|
||||||
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
|
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
|
||||||
|
|
||||||
Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called ```Approx```. ```Approx``` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
|
Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called `Approx`. `Approx` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
REQUIRE( performComputation() == Approx( 2.1 ) );
|
REQUIRE( performComputation() == Approx( 2.1 ) );
|
||||||
```
|
```
|
||||||
|
|
||||||
This way `Approx` is constructed with reasonable defaults, covering most simple cases of rounding errors. If these are insufficient, each `Approx` instance has 3 tuning knobs, that can be used to customize it for your computation.
|
Catch also provides a UDL for `Approx`; `_a`. It resides in
|
||||||
|
the `Catch::literals` namespace and can be used like so:
|
||||||
|
```cpp
|
||||||
|
using namespace Catch::literals;
|
||||||
|
REQUIRE( performComputation() == 2.1_a );
|
||||||
|
```
|
||||||
|
|
||||||
* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
|
`Approx` is constructed with defaults that should cover most simple cases.
|
||||||
* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
|
For the more complex cases, `Approx` provides 3 customization points:
|
||||||
* __scale__ - scale serves to adjust the epsilon's multiplicator. By default set to `0.0`.
|
|
||||||
|
* __epsilon__ - epsilon serves to set the coefficient by which a result
|
||||||
|
can differ from `Approx`'s value before it is rejected.
|
||||||
|
_By default set to `std::numeric_limits<float>::epsilon()*100`._
|
||||||
|
* __margin__ - margin serves to set the the absolute value by which
|
||||||
|
a result can differ from `Approx`'s value before it is rejected.
|
||||||
|
_By default set to `0.0`._
|
||||||
|
* __scale__ - scale is used to change the magnitude of `Approx` for relative check.
|
||||||
|
_By default set to `0.0`._
|
||||||
|
|
||||||
#### epsilon example
|
#### epsilon example
|
||||||
```cpp
|
```cpp
|
||||||
Approx target = Approx(100).epsilon(0.01);
|
Approx target = Approx(100).epsilon(0.01);
|
||||||
100.0 == target; // Obviously true
|
100.0 == target; // Obviously true
|
||||||
200.0 == target; // Obviously still false
|
200.0 == target; // Obviously still false
|
||||||
100.5 == target; // True, because we set target to allow up to 1% error
|
100.5 == target; // True, because we set target to allow up to 1% difference
|
||||||
```
|
```
|
||||||
|
|
||||||
#### margin example
|
#### margin example
|
||||||
_Margin check is used only if the relative (epsilon and scale based) check fails._
|
|
||||||
```cpp
|
```cpp
|
||||||
Approx target = Approx(100).margin(5);
|
Approx target = Approx(100).margin(5);
|
||||||
100.0 == target; // Obviously true
|
100.0 == target; // Obviously true
|
||||||
200.0 == target; // Obviously still false
|
200.0 == target; // Obviously still false
|
||||||
104.0 == target; // True, because we set target to allow absolute error up to 5
|
104.0 == target; // True, because we set target to allow absolute difference of at most 5
|
||||||
```
|
```
|
||||||
|
|
||||||
#### scale
|
#### scale
|
||||||
@@ -155,6 +168,34 @@ Matchers can be composed using `&&`, `||` and `!` operators.
|
|||||||
Currently assertions in Catch are not thread safe.
|
Currently assertions in Catch are not thread safe.
|
||||||
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
|
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
|
||||||
|
|
||||||
|
## Expressions with commas
|
||||||
|
|
||||||
|
Because the preprocessor parses code using different rules than the
|
||||||
|
compiler, multiple-argument assertions (e.g. `REQUIRE_THROWS_AS`) have
|
||||||
|
problems with commas inside the provided expressions. As an example
|
||||||
|
`REQUIRE_THROWS_AS(std::pair<int, int>(1, 2), std::invalid_argument);`
|
||||||
|
will fail to compile, because the preprocessor sees 3 arguments provided,
|
||||||
|
but the macro accepts only 2. There are two possible workarounds.
|
||||||
|
|
||||||
|
1) Use typedef:
|
||||||
|
```cpp
|
||||||
|
using int_pair = std::pair<int, int>;
|
||||||
|
REQUIRE_THROWS_AS(int_pair(1, 2), std::invalid_argument);
|
||||||
|
```
|
||||||
|
|
||||||
|
This solution is always applicable, but makes the meaning of the code
|
||||||
|
less clear.
|
||||||
|
|
||||||
|
2) Parenthesize the expression:
|
||||||
|
```cpp
|
||||||
|
TEST_CASE_METHOD((Fixture<int, int>), "foo", "[bar]") {
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This solution is not always applicable, because it might require extra
|
||||||
|
changes on the Catch's side to work.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -1,6 +1,13 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# CI and build system integration
|
# CI and other odd pieces
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[Continuous Integration systems](#continuous-integration-systems)<br>
|
||||||
|
[Other reporters](#other-reporters)<br>
|
||||||
|
[Low-level tools](#low-level-tools)<br>
|
||||||
|
[CMake](#cmake)<br>
|
||||||
|
|
||||||
|
This page talks about how Catch integrates with Continuous Integration
|
||||||
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
|
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
|
||||||
|
|
||||||
## Continuous Integration systems
|
## Continuous Integration systems
|
||||||
@@ -71,105 +78,31 @@ Catch offers prototypal support for being included in precompiled headers, but b
|
|||||||
* include "catch.hpp" again
|
* include "catch.hpp" again
|
||||||
|
|
||||||
|
|
||||||
### CMake
|
|
||||||
|
|
||||||
In general we recommend "vendoring" Catch's single-include releases inside your own repository. If you do this, the following example shows a minimal CMake project:
|
|
||||||
```CMake
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
|
|
||||||
project(cmake_test)
|
|
||||||
|
|
||||||
# Prepare "Catch" library for other executables
|
|
||||||
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/catch)
|
|
||||||
add_library(Catch INTERFACE)
|
|
||||||
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
|
|
||||||
|
|
||||||
# Make test executable
|
|
||||||
set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
|
|
||||||
add_executable(tests ${TEST_SOURCES})
|
|
||||||
target_link_libraries(tests Catch)
|
|
||||||
```
|
|
||||||
Note that it assumes that the path to the Catch's header is `catch/catch.hpp` from the `CMakeLists.txt` file.
|
|
||||||
|
|
||||||
|
|
||||||
You can also use the following CMake snippet to automatically fetch the entire Catch repository from github and configure it as an external project:
|
|
||||||
```CMake
|
|
||||||
cmake_minimum_required(VERSION 2.8.8)
|
|
||||||
project(catch_builder CXX)
|
|
||||||
include(ExternalProject)
|
|
||||||
find_package(Git REQUIRED)
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
catch
|
|
||||||
PREFIX ${CMAKE_BINARY_DIR}/catch
|
|
||||||
GIT_REPOSITORY https://github.com/philsquared/Catch.git
|
|
||||||
TIMEOUT 10
|
|
||||||
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND ""
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
LOG_DOWNLOAD ON
|
|
||||||
)
|
|
||||||
|
|
||||||
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
|
||||||
ExternalProject_Get_Property(catch source_dir)
|
|
||||||
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
|
||||||
```
|
|
||||||
|
|
||||||
If you put it in, e.g., `${PROJECT_SRC_DIR}/${EXT_PROJECTS_DIR}/catch/`, you can use it in your project by adding the following to your root CMake file:
|
|
||||||
|
|
||||||
```CMake
|
|
||||||
# Includes Catch in the project:
|
|
||||||
add_subdirectory(${EXT_PROJECTS_DIR}/catch)
|
|
||||||
include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
|
|
||||||
enable_testing(true) # Enables unit-testing.
|
|
||||||
```
|
|
||||||
|
|
||||||
The advantage of this approach is that you can always automatically update Catch to the latest release. The disadvantage is that it means bringing in lot more than you need.
|
|
||||||
|
|
||||||
|
|
||||||
### Automatic test registration
|
|
||||||
We provide 2 CMake scripts that can automatically register Catch-based
|
|
||||||
tests with CTest,
|
|
||||||
* `contrib/ParseAndAddCatchTests.cmake`
|
|
||||||
* `contrib/CatchAddTests.cmake`
|
|
||||||
|
|
||||||
The first is based on parsing the test implementation files, and attempts
|
|
||||||
to register all `TEST_CASE`s using their tags as labels. This means that
|
|
||||||
these:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
TEST_CASE("Test1", "[unit]") {
|
|
||||||
int a = 1;
|
|
||||||
int b = 2;
|
|
||||||
REQUIRE(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Test2") {
|
|
||||||
int a = 1;
|
|
||||||
int b = 2;
|
|
||||||
REQUIRE(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Test3", "[a][b][c]") {
|
|
||||||
int a = 1;
|
|
||||||
int b = 2;
|
|
||||||
REQUIRE(a == b);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
would be registered as 3 tests, `Test1`, `Test2` and `Test3`,
|
|
||||||
and 4 CTest labels would be created, `a`, `b`, `c` and `unit`.
|
|
||||||
|
|
||||||
|
|
||||||
The second is based on parsing the output of a Catch binary given
|
|
||||||
`--list-test-names-only`. This means that it deals with inactive
|
|
||||||
(e.g. commented-out) tests better, but requires CMake 3.10 for full
|
|
||||||
functionality.
|
|
||||||
|
|
||||||
### CodeCoverage module (GCOV, LCOV...)
|
### CodeCoverage module (GCOV, LCOV...)
|
||||||
|
|
||||||
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
|
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
|
||||||
|
|
||||||
|
|
||||||
|
### pkg-config
|
||||||
|
|
||||||
|
Catch2 provides a rudimentary pkg-config integration, by registering itself
|
||||||
|
under the name `catch2`. This means that after Catch2 is installed, you
|
||||||
|
can use `pkg-config` to get its include path: `pkg-config --cflags catch2`.
|
||||||
|
|
||||||
|
### gdb and lldb scripts
|
||||||
|
|
||||||
|
Catch2's `contrib` folder also contains two simple debugger scripts,
|
||||||
|
`gdbinit` for `gdb` and `lldbinit` for `lldb`. If loaded into their
|
||||||
|
respective debugger, these will tell it to step over Catch2's internals
|
||||||
|
when stepping through code.
|
||||||
|
|
||||||
|
|
||||||
|
## CMake
|
||||||
|
|
||||||
|
[As it has been getting kinda long, the documentation of Catch2's
|
||||||
|
integration with CMake has been moved to its own page.](cmake-integration.md#top)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
216
docs/cmake-integration.md
Normal file
216
docs/cmake-integration.md
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<a id="top"></a>
|
||||||
|
# CMake integration
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[CMake target](#cmake-target)<br>
|
||||||
|
[Automatic test registration](#automatic-test-registration)<br>
|
||||||
|
[CMake project options](#cmake-project-options)<br>
|
||||||
|
[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
|
||||||
|
|
||||||
|
Because we use CMake to build Catch2, we also provide a couple of
|
||||||
|
integration points for our users.
|
||||||
|
|
||||||
|
1) Catch2 exports a (namespaced) CMake target
|
||||||
|
2) Catch2's repository contains CMake scripts for automatic registration
|
||||||
|
of `TEST_CASE`s in CTest
|
||||||
|
|
||||||
|
## CMake target
|
||||||
|
|
||||||
|
Catch2's CMake build exports an interface target `Catch2::Catch2`. Linking
|
||||||
|
against it will add the proper include path and all necessary capabilities
|
||||||
|
to the resulting binary.
|
||||||
|
|
||||||
|
This means that if Catch2 has been installed on the system, it should be
|
||||||
|
enough to do:
|
||||||
|
```cmake
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
target_link_libraries(tests Catch2::Catch2)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
This target is also provided when Catch2 is used as a subdirectory.
|
||||||
|
Assuming that Catch2 has been cloned to `lib/Catch2`:
|
||||||
|
```cmake
|
||||||
|
add_subdirectory(lib/Catch2)
|
||||||
|
target_link_libraries(tests Catch2::Catch2)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic test registration
|
||||||
|
|
||||||
|
Catch2's repository also contains two CMake scripts that help users
|
||||||
|
with automatically registering their `TEST_CASE`s with CTest. They
|
||||||
|
can be found in the `contrib` folder, and are
|
||||||
|
|
||||||
|
1) `Catch.cmake` (and its dependency `CatchAddTests.cmake`)
|
||||||
|
2) `ParseAndAddCatchTests.cmake`
|
||||||
|
|
||||||
|
If Catch2 has been installed in system, both of these can be used after
|
||||||
|
doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
|
||||||
|
to your CMake module path.
|
||||||
|
|
||||||
|
### `Catch.cmake` and `AddCatchTests.cmake`
|
||||||
|
|
||||||
|
`Catch.cmake` provides function `catch_discover_tests` to get tests from
|
||||||
|
a target. This function works by running the resulting executable with
|
||||||
|
`--list-test-names-only` flag, and then parsing the output to find all
|
||||||
|
existing tests.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
```cmake
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(foo test.cpp)
|
||||||
|
target_link_libraries(foo Catch2::Catch2)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(foo)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
`catch_discover_tests` can be given several extra argumets:
|
||||||
|
```cmake
|
||||||
|
catch_discover_tests(target
|
||||||
|
[TEST_SPEC arg1...]
|
||||||
|
[EXTRA_ARGS arg1...]
|
||||||
|
[WORKING_DIRECTORY dir]
|
||||||
|
[TEST_PREFIX prefix]
|
||||||
|
[TEST_SUFFIX suffix]
|
||||||
|
[PROPERTIES name1 value1...]
|
||||||
|
[TEST_LIST var]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `TEST_SPEC arg1...`
|
||||||
|
|
||||||
|
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||||
|
pass to the Catch executable alongside the `--list-test-names-only` flag.
|
||||||
|
|
||||||
|
|
||||||
|
* `EXTRA_ARGS arg1...`
|
||||||
|
|
||||||
|
Any extra arguments to pass on the command line to each test case.
|
||||||
|
|
||||||
|
|
||||||
|
* `WORKING_DIRECTORY dir`
|
||||||
|
|
||||||
|
Specifies the directory in which to run the discovered test cases. If this
|
||||||
|
option is not provided, the current binary directory is used.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_PREFIX prefix`
|
||||||
|
|
||||||
|
Specifies a _prefix_ to be added to the name of each discovered test case.
|
||||||
|
This can be useful when the same test executable is being used in multiple
|
||||||
|
calls to `catch_discover_tests()`, with different `TEST_SPEC` or `EXTRA_ARGS`.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_SUFFIX suffix`
|
||||||
|
|
||||||
|
Same as `TEST_PREFIX`, except it specific the _suffix_ for the test names.
|
||||||
|
Both `TEST_PREFIX` and `TEST_SUFFIX` can be specified at the same time.
|
||||||
|
|
||||||
|
|
||||||
|
* `PROPERTIES name1 value1...`
|
||||||
|
|
||||||
|
Specifies additional properties to be set on all tests discovered by this
|
||||||
|
invocation of `catch_discover_tests`.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_LIST var`
|
||||||
|
|
||||||
|
Make the list of tests available in the variable `var`, rather than the
|
||||||
|
default `<target>_TESTS`. This can be useful when the same test
|
||||||
|
executable is being used in multiple calls to `catch_discover_tests()`.
|
||||||
|
Note that this variable is only available in CTest.
|
||||||
|
|
||||||
|
|
||||||
|
### `ParseAndAddCatchTests.cmake`
|
||||||
|
|
||||||
|
`ParseAndAddCatchTests` works by parsing all implementation files
|
||||||
|
associated with the provided target, and registering them via CTest's
|
||||||
|
`add_test`. This approach has some limitations, such as the fact that
|
||||||
|
commented-out tests will be registered anyway.
|
||||||
|
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(foo test.cpp)
|
||||||
|
target_link_libraries(foo Catch2::Catch2)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(ParseAndAddCatchTests)
|
||||||
|
ParseAndAddCatchTests(foo)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
`ParseAndAddCatchTests` provides some customization points:
|
||||||
|
* `PARSE_CATCH_TESTS_VERBOSE` -- When `ON`, the script prints debug
|
||||||
|
messages. Defaults to `OFF`.
|
||||||
|
* `PARSE_CATCH_TESTS_NO_HIDDEN_TESTS` -- When `ON`, hidden tests (tests
|
||||||
|
tagged with any of `[!hide]`, `[.]` or `[.foo]`) will not be registered.
|
||||||
|
Defaults to `OFF`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME` -- When `ON`, adds fixture
|
||||||
|
class name to the test name in CTest. Defaults to `ON`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME` -- When `ON`, adds target
|
||||||
|
name to the test name in CTest. Defaults to `ON`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS` -- When `ON`, adds test
|
||||||
|
file to `CMAKE_CONFIGURE_DEPENDS`. This means that the CMake configuration
|
||||||
|
step will be re-ran when the test files change, letting new tests be
|
||||||
|
automatically discovered. Defaults to `OFF`.
|
||||||
|
|
||||||
|
|
||||||
|
## CMake project options
|
||||||
|
|
||||||
|
Catch2's CMake project also provides some options for other projects
|
||||||
|
that consume it. These are
|
||||||
|
|
||||||
|
* `CATCH_BUILD_TESTING` -- When `ON`, Catch2's SelfTest project will be
|
||||||
|
built. Defaults to `ON`. Note that Catch2 also obeys `BUILD_TESTING` CMake
|
||||||
|
variable, so _both_ of them need to be `ON` for the SelfTest to be built,
|
||||||
|
and either of them can be set to `OFF` to disable building SelfTest.
|
||||||
|
* `CATCH_BUILD_EXAMPLES` -- When `ON`, Catch2's usage examples will be
|
||||||
|
built. Defaults to `OFF`.
|
||||||
|
* `CATCH_INSTALL_DOCS` -- When `ON`, Catch2's documentation will be
|
||||||
|
included in the installation. Defaults to `ON`.
|
||||||
|
* `CATCH_INSTALL_HELPERS` -- When `ON`, Catch2's contrib folder will be
|
||||||
|
included in the installation. Defaults to `ON`.
|
||||||
|
* `BUILD_TESTING` -- When `ON` and the project is not used as a subproject,
|
||||||
|
Catch2's test binary will be built. Defaults to `ON`.
|
||||||
|
|
||||||
|
|
||||||
|
## Installing Catch2 from git repository
|
||||||
|
|
||||||
|
If you cannot install Catch2 from a package manager (e.g. Ubuntu 16.04
|
||||||
|
provides catch only in version 1.2.0) you might want to install it from
|
||||||
|
the repository instead. Assuming you have enough rights, you can just
|
||||||
|
install it to the default location, like so:
|
||||||
|
```
|
||||||
|
$ git clone https://github.com/catchorg/Catch2.git
|
||||||
|
$ cd Catch2
|
||||||
|
$ cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
$ sudo cmake --build build/ --target install
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not have superuser rights, you will also need to specify
|
||||||
|
[CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
|
||||||
|
when configuring the build, and then modify your calls to
|
||||||
|
[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Home](Readme.md#top)
|
@@ -24,6 +24,7 @@
|
|||||||
[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>
|
||||||
|
[Override output colouring](#override-output-colouring)<br>
|
||||||
|
|
||||||
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
||||||
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
|
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
|
||||||
@@ -57,6 +58,7 @@ Click one of the followings links to take you straight to that option - or scrol
|
|||||||
<a href="#libidentify"> ` --libidentify`</a><br />
|
<a href="#libidentify"> ` --libidentify`</a><br />
|
||||||
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
||||||
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
||||||
|
<a href="#use-colour"> ` --use-colour`</a><br />
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
@@ -122,7 +124,9 @@ The JUnit reporter is an xml format that follows the structure of the JUnit XML
|
|||||||
## Breaking into the debugger
|
## Breaking into the debugger
|
||||||
<pre>-b, --break</pre>
|
<pre>-b, --break</pre>
|
||||||
|
|
||||||
In some IDEs (currently XCode and Visual Studio) it is possible for Catch to break into the debugger on a test failure. This can be very helpful during debug sessions - especially when there is more than one path through a particular test.
|
Under most debuggers Catch2 is capable of automatically breaking on a test
|
||||||
|
failure. This allows the user to see the current state of the test during
|
||||||
|
failure.
|
||||||
|
|
||||||
<a id="showing-results-for-successful-tests"></a>
|
<a id="showing-results-for-successful-tests"></a>
|
||||||
## Showing results for successful tests
|
## Showing results for successful tests
|
||||||
@@ -329,6 +333,16 @@ filename it is found in, with any extension stripped, prefixed with the `#` char
|
|||||||
|
|
||||||
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
||||||
|
|
||||||
|
<a id="use-colour"></a>
|
||||||
|
## Override output colouring
|
||||||
|
<pre>--use-colour <yes|no|auto></pre>
|
||||||
|
|
||||||
|
Catch colours output for terminals, but omits colouring when it detects that
|
||||||
|
output is being sent to a pipe. This is done to avoid interfering with automated
|
||||||
|
processing of output.
|
||||||
|
|
||||||
|
`--use-colour yes` forces coloured output, `--use-colour no` disables coloured
|
||||||
|
output. The default behaviour is `--use-colour auto`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -3,15 +3,19 @@
|
|||||||
|
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
[main()/ implementation](#main-implementation)<br>
|
[main()/ implementation](#main-implementation)<br>
|
||||||
|
[Reporter / Listener interfaces](#reporter--listener-interfaces)<br>
|
||||||
[Prefixing Catch macros](#prefixing-catch-macros)<br>
|
[Prefixing Catch macros](#prefixing-catch-macros)<br>
|
||||||
[Terminal colour](#terminal-colour)<br>
|
[Terminal colour](#terminal-colour)<br>
|
||||||
[Console width](#console-width)<br>
|
[Console width](#console-width)<br>
|
||||||
[stdout](#stdout)<br>
|
[stdout](#stdout)<br>
|
||||||
[Fallback stringifier](#fallback-stringifier)<br>
|
[Fallback stringifier](#fallback-stringifier)<br>
|
||||||
[Default reporter](#default-reporter)<br>
|
[Default reporter](#default-reporter)<br>
|
||||||
|
[C++11 toggles](#c11-toggles)<br>
|
||||||
|
[C++17 toggles](#c17-toggles)<br>
|
||||||
[Other toggles](#other-toggles)<br>
|
[Other toggles](#other-toggles)<br>
|
||||||
[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>
|
||||||
|
|
||||||
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```).
|
||||||
|
|
||||||
@@ -19,12 +23,12 @@ Nonetheless there are still some occasions where finer control is needed. For th
|
|||||||
|
|
||||||
## main()/ implementation
|
## main()/ implementation
|
||||||
|
|
||||||
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
|
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
|
||||||
CATCH_CONFIG_RUNNER // Designates this as implementation file
|
CATCH_CONFIG_RUNNER // Designates this as implementation file
|
||||||
|
|
||||||
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
|
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
|
||||||
|
|
||||||
# Reporter / Listener interfaces
|
## Reporter / Listener interfaces
|
||||||
|
|
||||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
|
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
|
||||||
|
|
||||||
@@ -34,16 +38,16 @@ Implied by both `CATCH_CONFIG_MAIN` and `CATCH_CONFIG_RUNNER`.
|
|||||||
|
|
||||||
## Prefixing Catch macros
|
## Prefixing Catch macros
|
||||||
|
|
||||||
CATCH_CONFIG_PREFIX_ALL
|
CATCH_CONFIG_PREFIX_ALL
|
||||||
|
|
||||||
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
|
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
|
||||||
|
|
||||||
|
|
||||||
## Terminal colour
|
## Terminal colour
|
||||||
|
|
||||||
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
|
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
|
||||||
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
|
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
|
||||||
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
|
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
|
||||||
|
|
||||||
Yes, I am English, so I will continue to spell "colour" with a 'u'.
|
Yes, I am English, so I will continue to spell "colour" with a 'u'.
|
||||||
|
|
||||||
@@ -57,33 +61,41 @@ Typically you should place the ```#define``` before #including "catch.hpp" in yo
|
|||||||
|
|
||||||
## Console width
|
## Console width
|
||||||
|
|
||||||
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
|
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
|
||||||
|
|
||||||
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
|
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
|
||||||
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
|
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
|
||||||
|
|
||||||
## stdout
|
## stdout
|
||||||
|
|
||||||
CATCH_CONFIG_NOSTDOUT
|
CATCH_CONFIG_NOSTDOUT
|
||||||
|
|
||||||
Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly but gets them from ```Catch::cout()```, ```Catch::cerr()``` and ```Catch::clog``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
|
To support platforms that do not provide `std::cout`, `std::cerr` and
|
||||||
|
`std::clog`, Catch does not usem the directly, but rather calls
|
||||||
|
`Catch::cout`, `Catch::cerr` and `Catch::clog`. You can replace their
|
||||||
|
implementation by defining `CATCH_CONFIG_NOSTDOUT` and implementing
|
||||||
|
them yourself, their signatures are:
|
||||||
|
|
||||||
std::ostream& cout();
|
std::ostream& cout();
|
||||||
std::ostream& cerr();
|
std::ostream& cerr();
|
||||||
std::ostream& clog();
|
std::ostream& clog();
|
||||||
|
|
||||||
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
|
[You can see an example of replacing these functions here.](
|
||||||
|
../examples/231-Cfg-OutputStreams.cpp)
|
||||||
|
|
||||||
|
|
||||||
## Fallback stringifier
|
## Fallback stringifier
|
||||||
|
|
||||||
By default Catch's stringification machinery falls back to a "{?}". To
|
By default, when Catch's stringification machinery has to stringify
|
||||||
let projects reuse their own existing stringification machinery, this
|
a type that does not specialize `StringMaker`, does not overload `operator<<`,
|
||||||
fallback can be overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER`
|
is not an enumeration and is not a range, it uses `"{?}"`. This can be
|
||||||
to a name of a function that should perform the stringification instead.
|
overriden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
|
||||||
|
function that should perform the stringification instead.
|
||||||
|
|
||||||
The provided function must return std::string and must accept any type
|
All types that do not provide `StringMaker` specialization or `operator<<`
|
||||||
(e.g. via overloading).
|
overload will be sent to this function (this includes enums and ranges).
|
||||||
|
The provided function must return `std::string` and must accept any type,
|
||||||
|
e.g. via overloading.
|
||||||
|
|
||||||
_Note that if the provided function does not handle a type and this type
|
_Note that if the provided function does not handle a type and this type
|
||||||
requires to be stringified, the compilation will fail._
|
requires to be stringified, the compilation will fail._
|
||||||
@@ -99,9 +111,24 @@ This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
|
|||||||
is equivalent with the out-of-the-box experience.
|
is equivalent with the out-of-the-box experience.
|
||||||
|
|
||||||
|
|
||||||
|
## C++11 toggles
|
||||||
|
|
||||||
|
CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
|
||||||
|
|
||||||
|
Because we support platforms whose standard library does not contain
|
||||||
|
`std::to_string`, it is possible to force Catch to use a workaround
|
||||||
|
based on `std::stringstream`. On platforms other than Android,
|
||||||
|
the default is to use `std::to_string`. On Android, the default is to
|
||||||
|
use the `stringstream` workaround. As always, it is possible to override
|
||||||
|
Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
|
||||||
|
`CATCH_CONFIG_NO_CPP11_TO_STRING`.
|
||||||
|
|
||||||
|
|
||||||
## C++17 toggles
|
## C++17 toggles
|
||||||
|
|
||||||
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
|
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
|
||||||
|
CATCH_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view
|
||||||
|
CATCH_CONFIG_CPP17_VARIANT // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||||
|
|
||||||
Catch contains basic compiler/standard detection and attempts to use
|
Catch contains basic compiler/standard detection and attempts to use
|
||||||
some C++17 features whenever appropriate. This automatic detection
|
some C++17 features whenever appropriate. This automatic detection
|
||||||
@@ -121,6 +148,7 @@ by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
|
|||||||
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
||||||
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
||||||
CATCH_CONFIG_WCHAR // Enables use of wchart_t
|
CATCH_CONFIG_WCHAR // Enables use of wchart_t
|
||||||
|
CATCH_CONFIG_EXPERIMENTAL_REDIRECT // Enables the new (experimental) way of capturing stdout/stderr
|
||||||
|
|
||||||
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
|
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
|
||||||
|
|
||||||
@@ -131,14 +159,19 @@ Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC,
|
|||||||
`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently
|
`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently
|
||||||
it is only used in support for DJGPP cross-compiler.
|
it is only used in support for DJGPP cross-compiler.
|
||||||
|
|
||||||
These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
|
With the exception of `CATCH_CONFIG_EXPERIMENTAL_REDIRECT`,
|
||||||
|
these toggles can be disabled by using `_NO_` form of the toggle,
|
||||||
|
e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
|
||||||
|
|
||||||
### `CATCH_CONFIG_FAST_COMPILE`
|
### `CATCH_CONFIG_FAST_COMPILE`
|
||||||
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
|
This compile-time flag speeds up compilation of assertion macros by ~20%,
|
||||||
* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
|
by disabling the generation of assertion-local try-catch blocks for
|
||||||
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_THAT`}, no longer use local try-catch block. This disables exception translation, but should not lead to false negatives.
|
non-exception family of assertion macros ({`REQUIRE`,`CHECK`}{``,`_FALSE`, `_THAT`}).
|
||||||
|
This disables translation of exceptions thrown under these assertions, but
|
||||||
|
should not lead to false negatives.
|
||||||
|
|
||||||
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
|
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined,
|
||||||
|
in all translation units that are linked into single test binary.
|
||||||
|
|
||||||
### `CATCH_CONFIG_DISABLE_MATCHERS`
|
### `CATCH_CONFIG_DISABLE_MATCHERS`
|
||||||
When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
|
When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
|
||||||
@@ -170,9 +203,44 @@ By default, Catch does not stringify some types from the standard library. This
|
|||||||
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
||||||
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
|
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
|
||||||
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
|
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
|
||||||
|
CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER // Provide StringMaker specialization for std::variant, std::monostate (on C++17)
|
||||||
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
|
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
|
||||||
|
|
||||||
|
|
||||||
|
## Disabling exceptions
|
||||||
|
|
||||||
|
By default, Catch2 uses exceptions to signal errors and to abort tests
|
||||||
|
when an assertion from the `REQUIRE` family of assertions fails. We also
|
||||||
|
provide an experimental support for disabling exceptions. Catch2 should
|
||||||
|
automatically detect when it is compiled with exceptions disabled, but
|
||||||
|
it can be forced to compile without exceptions by defining
|
||||||
|
|
||||||
|
CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||||
|
|
||||||
|
Note that when using Catch2 without exceptions, there are 2 major
|
||||||
|
limitations:
|
||||||
|
|
||||||
|
1) If there is an error that would normally be signalled by an exception,
|
||||||
|
the exception's message will instead be written to `Catch::cerr` and
|
||||||
|
`std::terminate` will be called.
|
||||||
|
2) If an assertion from the `REQUIRE` family of macros fails,
|
||||||
|
`std::terminate` will be called after the active reporter returns.
|
||||||
|
|
||||||
|
|
||||||
|
There is also a customization point for the exact behaviour of what
|
||||||
|
happens instead of exception being thrown. To use it, define
|
||||||
|
|
||||||
|
CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
|
||||||
|
|
||||||
|
and provide a definition for this function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Catch {
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const&);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
50
docs/generators.md
Normal file
50
docs/generators.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<a id="top"></a>
|
||||||
|
# Data Generators
|
||||||
|
|
||||||
|
_Generators are currently considered an experimental feature and their
|
||||||
|
API can change between versions freely._
|
||||||
|
|
||||||
|
Data generators (also known as _data driven/parametrized test cases_)
|
||||||
|
let you reuse the same set of assertions across different input values.
|
||||||
|
In Catch2, this means that they respect the ordering and nesting
|
||||||
|
of the `TEST_CASE` and `SECTION` macros.
|
||||||
|
|
||||||
|
How does combining generators and test cases work might be better
|
||||||
|
explained by an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("Generators") {
|
||||||
|
auto i = GENERATE( range(1, 11) );
|
||||||
|
|
||||||
|
SECTION( "Some section" ) {
|
||||||
|
auto j = GENERATE( range( 11, 21 ) );
|
||||||
|
REQUIRE(i < j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
the assertion will be checked 100 times, because there are 10 possible
|
||||||
|
values for `i` (1, 2, ..., 10) and for each of them, there are 10 possible
|
||||||
|
values for `j` (11, 12, ..., 20).
|
||||||
|
|
||||||
|
You can also combine multiple generators by concatenation:
|
||||||
|
```cpp
|
||||||
|
static int square(int x) { return x * x; }
|
||||||
|
TEST_CASE("Generators 2") {
|
||||||
|
auto i = GENERATE(0, 1, -1, range(-20, -10), range(10, 20));
|
||||||
|
CAPTURE(i);
|
||||||
|
REQUIRE(square(i) >= 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will call `square` with arguments `0`, `1`, `-1`, `-20`, ..., `-11`,
|
||||||
|
`10`, ..., `19`.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
Because of the experimental nature of the current Generator implementation,
|
||||||
|
we won't list all of the first-party generators in Catch2. Instead you
|
||||||
|
should look at our current usage tests in
|
||||||
|
[projects/SelfTest/UsageTests/Generators.tests.cpp](/projects/SelfTest/UsageTests/Generators.tests.cpp).
|
||||||
|
For implementing your own generators, you can look at their implementation in
|
||||||
|
[include/internal/catch_generators.hpp](/include/internal/catch_generators.hpp).
|
@@ -1,12 +1,19 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Known limitations
|
# Known limitations
|
||||||
|
|
||||||
Catch has some known limitations, that we are not planning to change. Some of these are caused by our desire to support C++98 compilers, some of these are caused by our desire to keep Catch crossplatform, some exist because their priority is seen as low compared to the development effort they would need and some other yet are compiler/runtime bugs.
|
Over time, some limitations of Catch2 emerged. Some of these are due
|
||||||
|
to implementation details that cannot be easily changed, some of these
|
||||||
|
are due to lack of development resources on our part, and some of these
|
||||||
|
are due to plain old 3rd party bugs.
|
||||||
|
|
||||||
|
|
||||||
## Implementation limits
|
## Implementation limits
|
||||||
### Sections nested in loops
|
### Sections nested in loops
|
||||||
|
|
||||||
If you are using `SECTION`s inside loops, you have to create them with different name per loop's iteration. The recommended way to do so is to incorporate the loop's counter into section's name, like so
|
If you are using `SECTION`s inside loops, you have to create them with
|
||||||
|
different name per loop's iteration. The recommended way to do so is to
|
||||||
|
incorporate the loop's counter into section's name, like so:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
TEST_CASE( "Looped section" ) {
|
TEST_CASE( "Looped section" ) {
|
||||||
for (char i = '0'; i < '5'; ++i) {
|
for (char i = '0'; i < '5'; ++i) {
|
||||||
@@ -17,11 +24,34 @@ TEST_CASE( "Looped section" ) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or with a `DYNAMIC_SECTION` macro (that was made for exactly this purpose):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE( "Looped section" ) {
|
||||||
|
for (char i = '0'; i < '5'; ++i) {
|
||||||
|
DYNAMIC_SECTION( "Looped section " << i) {
|
||||||
|
SUCCEED( "Everything is OK" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests might be run again if last section fails
|
||||||
|
|
||||||
|
If the last section in a test fails, it might be run again. This is because
|
||||||
|
Catch2 discovers `SECTION`s dynamically, as they are about to run, and
|
||||||
|
if the last section in test case is aborted during execution (e.g. via
|
||||||
|
the `REQUIRE` family of macros), Catch2 does not know that there are no
|
||||||
|
more sections in that test case and must run the test case again.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
This section outlines some missing features, what is their status and their possible workarounds.
|
This section outlines some missing features, what is their status and their possible workarounds.
|
||||||
|
|
||||||
### Thread safe assertions
|
### Thread safe assertions
|
||||||
Because threading support in standard C++98 is limited (well, non-existent), assertion macros in Catch are not thread safe. This does not mean that you cannot use threads inside Catch's test, but that only single thread can interact with Catch's assertions and other macros.
|
Catch2's assertion macros are not thread safe. This does not mean that
|
||||||
|
you cannot use threads inside Catch's test, but that only single thread
|
||||||
|
can interact with Catch's assertions and other macros.
|
||||||
|
|
||||||
This means that this is ok
|
This means that this is ok
|
||||||
```cpp
|
```cpp
|
||||||
@@ -49,8 +79,8 @@ because only one thread passes the `REQUIRE` macro and this is not
|
|||||||
REQUIRE(cnt == 16);
|
REQUIRE(cnt == 16);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Because C++11 provides the necessary tools to do this, we are planning
|
||||||
_This limitation is highly unlikely to be lifted before Catch 2 is released._
|
to remove this limitation in the future.
|
||||||
|
|
||||||
### Process isolation in a test
|
### Process isolation in a test
|
||||||
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
||||||
@@ -135,3 +165,14 @@ If you are seeing a problem like this, i.e. a weird test paths that trigger only
|
|||||||
This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
|
This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
|
||||||
|
|
||||||
Workaround: Use newer version of `libstdc++`.
|
Workaround: Use newer version of `libstdc++`.
|
||||||
|
|
||||||
|
|
||||||
|
### libstdc++, `_GLIBCXX_DEBUG` macro and random ordering of tests
|
||||||
|
|
||||||
|
Running a Catch2 binary compiled against libstdc++ with `_GLIBCXX_DEBUG`
|
||||||
|
macro defined with `--order rand` will cause a debug check to trigger and
|
||||||
|
abort the run due to self-assignment.
|
||||||
|
[This is a known bug inside libstdc++](https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle/23691322)
|
||||||
|
|
||||||
|
Workaround: Don't use `--order rand` when compiling against debug-enabled
|
||||||
|
libstdc++.
|
||||||
|
@@ -1,18 +1,28 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# List of examples
|
# List of examples
|
||||||
|
|
||||||
|
## Already available
|
||||||
|
|
||||||
|
- Catch main: [Catch-provided main](../examples/000-CatchMain.cpp)
|
||||||
- Test Case: [Single-file](../examples/010-TestCase.cpp)
|
- Test Case: [Single-file](../examples/010-TestCase.cpp)
|
||||||
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-1.cpp)
|
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-2.cpp)
|
||||||
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
|
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
|
||||||
|
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
|
||||||
|
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
|
||||||
|
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
|
||||||
|
- Report: [Catch-provided main](../examples/200-Rpt-CatchMain.cpp)
|
||||||
|
- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
|
||||||
|
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||||
|
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
||||||
|
|
||||||
|
## Planned
|
||||||
|
|
||||||
- Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
|
- Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
|
||||||
- Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
- Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
|
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
|
- Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
|
||||||
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
|
|
||||||
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
|
|
||||||
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
|
|
||||||
- Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
|
- Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
|
||||||
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
||||||
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
||||||
@@ -20,8 +30,10 @@
|
|||||||
- Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
|
- Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
|
||||||
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
|
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
|
||||||
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
||||||
- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
|
- Report: [User-defined reporter](../examples/202-Rpt-UserDefinedReporter.cpp)
|
||||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
- Report: [Automake reporter](../examples/205-Rpt-AutomakeReporter.cpp)
|
||||||
|
- Report: [TAP reporter](../examples/206-Rpt-TapReporter.cpp)
|
||||||
|
- Report: [Multiple reporter](../examples/208-Rpt-MultipleReporters.cpp)
|
||||||
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
||||||
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
||||||
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
||||||
|
@@ -72,12 +72,6 @@ This would log something like:
|
|||||||
|
|
||||||
<pre>"theAnswer := 42"</pre>
|
<pre>"theAnswer := 42"</pre>
|
||||||
|
|
||||||
## Deprecated macros
|
|
||||||
|
|
||||||
**SCOPED_INFO and SCOPED_CAPTURE**
|
|
||||||
|
|
||||||
These macros are now deprecated and are just aliases for INFO and CAPTURE (which were not previously scoped).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -53,6 +53,25 @@ The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts
|
|||||||
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
|
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
|
||||||
|
|
||||||
|
|
||||||
|
### Generic matchers
|
||||||
|
Catch also aims to provide a set of generic matchers. Currently this set
|
||||||
|
contains only a matcher that takes arbitrary callable predicate and applies
|
||||||
|
it onto the provided object.
|
||||||
|
|
||||||
|
Because of type inference limitations, the argument type of the predicate
|
||||||
|
has to be provided explicitly. Example:
|
||||||
|
```cpp
|
||||||
|
REQUIRE_THAT("Hello olleH",
|
||||||
|
Predicate<std::string>(
|
||||||
|
[] (std::string const& str) -> bool { return str.front() == str.back(); },
|
||||||
|
"First and last character should be equal")
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The second argument is an optional description of the predicate, and is
|
||||||
|
used only during reporting of the result.
|
||||||
|
|
||||||
|
|
||||||
## Custom matchers
|
## Custom matchers
|
||||||
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ The next-generation core storage and query engine for Couchbase Lite
|
|||||||
A High-performance Cluster Computing Engine
|
A High-performance Cluster Computing Engine
|
||||||
|
|
||||||
### [forest](https://github.com/xorz57/forest)
|
### [forest](https://github.com/xorz57/forest)
|
||||||
Forest is an open-source, template library of tree data structures written in C++11.
|
Template Library of Tree Data Structures
|
||||||
|
|
||||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||||
@@ -47,6 +47,9 @@ A header-only template engine for modern C++.
|
|||||||
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||||
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
||||||
|
|
||||||
|
### [libcluon](https://github.com/chrberger/libcluon)
|
||||||
|
A single-header-only library written in C++14 to glue distributed software components (UDP, TCP, shared memory) supporting natively Protobuf, LCM/ZCM, MsgPack, and JSON for dynamic message transformations in-between.
|
||||||
|
|
||||||
### [MNMLSTC Core](https://github.com/mnmlstc/core)
|
### [MNMLSTC Core](https://github.com/mnmlstc/core)
|
||||||
A small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions.
|
A small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions.
|
||||||
|
|
||||||
@@ -68,6 +71,9 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
|
|||||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||||
A library of algorithms for values-distributed-in-time
|
A library of algorithms for values-distributed-in-time
|
||||||
|
|
||||||
|
### [thor](https://github.com/xorz57/thor)
|
||||||
|
Wrapper Library for CUDA
|
||||||
|
|
||||||
### [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
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Supplying main() yourself
|
# Supplying main() yourself
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[Let Catch take full control of args and config](#let-catch-take-full-control-of-args-and-config)<br>
|
||||||
|
[Amending the config](#amending-the-config)<br>
|
||||||
|
[Adding your own command line options](#adding-your-own-command-line-options)<br>
|
||||||
|
[Version detection](#version-detection)<br>
|
||||||
|
|
||||||
The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
|
The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
|
||||||
|
|
||||||
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.
|
||||||
@@ -45,7 +51,7 @@ int main( int argc, char* argv[] )
|
|||||||
|
|
||||||
int returnCode = session.applyCommandLine( argc, argv );
|
int returnCode = session.applyCommandLine( argc, argv );
|
||||||
if( returnCode != 0 ) // Indicates a command line error
|
if( returnCode != 0 ) // Indicates a command line error
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
// writing to session.configData() or session.Config() here
|
// writing to session.configData() or session.Config() here
|
||||||
// overrides command line args
|
// overrides command line args
|
||||||
@@ -94,7 +100,7 @@ int main( int argc, char* argv[] )
|
|||||||
// Let Catch (using Clara) parse the command line
|
// Let Catch (using Clara) parse the command line
|
||||||
int returnCode = session.applyCommandLine( argc, argv );
|
int returnCode = session.applyCommandLine( argc, argv );
|
||||||
if( returnCode != 0 ) // Indicates a command line error
|
if( returnCode != 0 ) // Indicates a command line error
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
// if set on the command line then 'height' is now set at this point
|
// if set on the command line then 'height' is now set at this point
|
||||||
if( height > 0 )
|
if( height > 0 )
|
||||||
|
@@ -1,23 +1,178 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
|
|
||||||
# 2.2.1
|
# Release notes
|
||||||
|
**Contents**<br>
|
||||||
|
[2.4.1](#241)<br>
|
||||||
|
[2.4.0](#240)<br>
|
||||||
|
[2.3.0](#230)<br>
|
||||||
|
[2.2.3](#223)<br>
|
||||||
|
[2.2.2](#222)<br>
|
||||||
|
[2.2.1](#221)<br>
|
||||||
|
[2.2.0](#220)<br>
|
||||||
|
[2.1.2](#212)<br>
|
||||||
|
[2.1.1](#211)<br>
|
||||||
|
[2.1.0](#210)<br>
|
||||||
|
[2.0.1](#201)<br>
|
||||||
|
[Older versions](#older-versions)<br>
|
||||||
|
[Even Older versions](#even-older-versions)<br>
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added a StringMaker for `std::(w)string_view` (#1375, #1376)
|
||||||
|
* Added a StringMaker for `std::variant` (#1380)
|
||||||
|
* This one is disabled by default to avoid increased compile-time drag
|
||||||
|
* Added detection for cygwin environment without `std::to_string` (#1396, #1397)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* `UnorderedEqualsMatcher` will no longer accept erroneously accept
|
||||||
|
vectors that share suffix, but are not permutation of the desired vector
|
||||||
|
* Abort after (`-x N`) can no longer be overshot by nested `REQUIRES` and
|
||||||
|
subsequently ignored (#1391, #1392)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
|
||||||
|
**This release brings two new experimental features, generator support
|
||||||
|
and a `-fno-exceptions` support. Being experimental means that they
|
||||||
|
will not be subject to the usual stability guarantees provided by semver.**
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Various small runtime performance improvements
|
||||||
|
* `CAPTURE` macro is now variadic
|
||||||
|
* Added `AND_GIVEN` macro (#1360)
|
||||||
|
* Added experimental support for data generators
|
||||||
|
* See [their documentation](generators.md) for details
|
||||||
|
* Added support for compiling and running Catch without exceptions
|
||||||
|
* Doing so limits the functionality somewhat
|
||||||
|
* Look [into the documentation](configuration.md#disablingexceptions) for details
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Suppressed `-Wnon-virtual-dtor` warnings in Matchers (#1357)
|
||||||
|
* Suppressed `-Wunreachable-code` warnings in floating point matchers (#1350)
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
* It is now possible to override which Python is used to run Catch's tests (#1365)
|
||||||
|
* Catch now provides infrastructure for adding tests that check compile-time configuration
|
||||||
|
* Catch no longer tries to install itself when used as a subproject (#1373)
|
||||||
|
* Catch2ConfigVersion.cmake is now generated as arch-independent (#1368)
|
||||||
|
* This means that installing Catch from 32-bit machine and copying it to 64-bit one works
|
||||||
|
* This fixes conan installation of Catch
|
||||||
|
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
|
||||||
|
**This release changes the include paths provided by our CMake and
|
||||||
|
pkg-config integration. The proper include path for the single-header
|
||||||
|
when using one of the above is now `<catch2/catch.hpp>`. This change
|
||||||
|
also necessitated changes to paths inside the repository, so that the
|
||||||
|
single-header version is now at `single_include/catch2/catch.hpp`, rather
|
||||||
|
than `single_include/catch.hpp`.**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed Objective-C++ build
|
||||||
|
* `-Wunused-variable` suppression no longer leaks from Catch's header under Clang
|
||||||
|
* Implementation of the experimental new output capture can now be disabled (#1335)
|
||||||
|
* This allows building Catch2 on platforms that do not provide things like `dup` or `tmpfile`.
|
||||||
|
* The JUnit and XML reporters will no longer skip over successful tests when running without `-s` (#1264, #1267, #1310)
|
||||||
|
* See improvements for more details
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* pkg-config and CMake integration has been rewritten
|
||||||
|
* If you use them, the new include path is `#include <catch2/catch.hpp>`
|
||||||
|
* CMake installation now also installs scripts from `contrib/`
|
||||||
|
* For details see the [new documentation](cmake-integration.md#top)
|
||||||
|
* Reporters now have a new customization point, `ReporterPreferences::shouldReportAllAssertions`
|
||||||
|
* When this is set to `false` and the tests are run without `-s`, passing assertions are not sent to the reporter.
|
||||||
|
* Defaults to `false`.
|
||||||
|
* Added `DYNAMIC_SECTION`, a section variant that constructs its name using stream
|
||||||
|
* This means that you can do `DYNAMIC_SECTION("For X := " << x)`.
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.3
|
||||||
|
|
||||||
|
**To fix some of the bugs, some behavior had to change in potentially breaking manner.**
|
||||||
|
**This means that even though this is a patch release, it might not be a drop-in replacement.**
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Listeners are now called before reporter
|
||||||
|
* This was always documented to be the case, now it actually works that way
|
||||||
|
* Catch's commandline will no longer accept multiple reporters
|
||||||
|
* This was done because multiple reporters never worked properly and broke things in non-obvious ways
|
||||||
|
* **This has potential to be a breaking change**
|
||||||
|
* MinGW is now detected as Windows platform w/o SEH support (#1257)
|
||||||
|
* This means that Catch2 no longer tries to use POSIX signal handling when compiled with MinGW
|
||||||
|
* Fixed potential UB in parsing tags using non-ASCII characters (#1266)
|
||||||
|
* Note that Catch2 still supports only ASCII test names/tags/etc
|
||||||
|
* `TEST_CASE_METHOD` can now be used on classnames containing commas (#1245)
|
||||||
|
* You have to enclose the classname in extra set of parentheses
|
||||||
|
* Fixed insufficient alt stack size for POSIX signal handling (#1225)
|
||||||
|
* Fixed compilation error on Android due to missing `std::to_string` in C++11 mode (#1280)
|
||||||
|
* Fixed the order of user-provided `FALLBACK_STRINGIFIER` in stringification machinery (#1024)
|
||||||
|
* It was intended to be replacement for built-in fallbacks, but it was used _after_ them.
|
||||||
|
* **This has potential to be a breaking change**
|
||||||
|
* Fixed compilation error when a type has an `operator<<` with templated lhs (#1285, #1306)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added a new, experimental, output capture (#1243)
|
||||||
|
* This capture can also redirect output written via C apis, e.g. `printf`
|
||||||
|
* To opt-in, define `CATCH_CONFIG_EXPERIMENTAL_REDIRECT` in the implementation file
|
||||||
|
* Added a new fallback stringifier for classes derived from `std::exception`
|
||||||
|
* Both `StringMaker` specialization and `operator<<` overload are given priority
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* `contrib/` now contains dbg scripts that skip over Catch's internals (#904, #1283)
|
||||||
|
* `gdbinit` for gdb `lldbinit` for lldb
|
||||||
|
* `CatchAddTests.cmake` no longer strips whitespace from tests (#1265, #1281)
|
||||||
|
* Online documentation now describes `--use-colour` option (#1263)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed bug in `WithinAbs::match()` failing spuriously (#1228)
|
||||||
|
* Fixed clang-tidy diagnostic about virtual call in destructor (#1226)
|
||||||
|
* Reduced the number of GCC warnings suppression leaking out of the header (#1090, #1091)
|
||||||
|
* Only `-Wparentheses` should be leaking now
|
||||||
|
* Added upper bound on the time benchmark timer calibration is allowed to take (#1237)
|
||||||
|
* On platforms where `std::chrono::high_resolution_clock`'s resolution is low, the calibration would appear stuck
|
||||||
|
* Fixed compilation error when stringifying static arrays of `unsigned char`s (#1238)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* XML encoder now hex-encodes invalid UTF-8 sequences (#1207)
|
||||||
|
* This affects xml and junit reporters
|
||||||
|
* Some invalid UTF-8 parts are left as is, e.g. surrogate pairs. This is because certain extensions of UTF-8 allow them, such as WTF-8.
|
||||||
|
* CLR objects (`T^`) can now be stringified (#1216)
|
||||||
|
* This affects code compiled as C++/CLI
|
||||||
|
* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236)
|
||||||
|
* See [documentation for details](https://github.com/catchorg/Catch2/blob/master/docs/matchers.md)
|
||||||
|
|
||||||
|
### Others
|
||||||
|
* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
|
||||||
|
* The plans to standardize on `#include <catch2/catch.hpp>` are still in effect
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
|
* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
|
||||||
* Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
|
* Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
|
||||||
* Fixed Catch2 return code always being 0 (#1215)
|
* Fixed Catch2 return code always being 0 (#1215)
|
||||||
* In the words of STL, "We feel superbad about letting this in"
|
* In the words of STL, "We feel superbad about letting this in"
|
||||||
|
|
||||||
|
|
||||||
# 2.2.0
|
## 2.2.0
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Hidden tests are not listed by default when listing tests (#1175)
|
* Hidden tests are not listed by default when listing tests (#1175)
|
||||||
* This makes `catch_discover_tests` CMake script work better
|
* This makes `catch_discover_tests` CMake script work better
|
||||||
* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
|
* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
|
||||||
* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
|
* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
|
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
|
||||||
* Use as `-w NoTests`
|
* Use as `-w NoTests`
|
||||||
* Added provisional support for Emscripten (#1114)
|
* Added provisional support for Emscripten (#1114)
|
||||||
@@ -29,38 +184,38 @@
|
|||||||
* Added support for DJGPP DOS crosscompiler (#1206)
|
* Added support for DJGPP DOS crosscompiler (#1206)
|
||||||
|
|
||||||
|
|
||||||
# 2.1.2
|
## 2.1.2
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Fixed compilation error with `-fno-rtti` (#1165)
|
* Fixed compilation error with `-fno-rtti` (#1165)
|
||||||
* Fixed NoAssertion warnings
|
* Fixed NoAssertion warnings
|
||||||
* `operator<<` is used before range-based stringification (#1172)
|
* `operator<<` is used before range-based stringification (#1172)
|
||||||
* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
|
* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
|
||||||
|
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
|
* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
|
||||||
* Added `BrightYellow` colour for use in reporters (#979)
|
* Added `BrightYellow` colour for use in reporters (#979)
|
||||||
* It is also used by ConsoleReporter for reconstructed expressions
|
* It is also used by ConsoleReporter for reconstructed expressions
|
||||||
|
|
||||||
## Other changes
|
### Other changes
|
||||||
* Catch is now exported as a CMake package and linkable target (#1170)
|
* Catch is now exported as a CMake package and linkable target (#1170)
|
||||||
|
|
||||||
# 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
|
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
|
||||||
* Embedded newer version of Clara -- v1.1.1
|
* Embedded newer version of Clara -- v1.1.1
|
||||||
* This should fix some warnings dragged in from Clara
|
* This should fix some warnings dragged in from Clara
|
||||||
* MSVC's CLR exceptions are supported
|
* MSVC's CLR exceptions are supported
|
||||||
|
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Fixed compilation when comparison operators do not return bool (#1147)
|
* Fixed compilation when comparison operators do not return bool (#1147)
|
||||||
* Fixed CLR exceptions blowing up the executable during translation (#1138)
|
* Fixed CLR exceptions blowing up the executable during translation (#1138)
|
||||||
|
|
||||||
|
|
||||||
## Other changes
|
### Other changes
|
||||||
* Many CMake changes
|
* Many CMake changes
|
||||||
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
|
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
|
||||||
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
|
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
|
||||||
@@ -68,9 +223,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 2.1.0
|
## 2.1.0
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Various performance improvements
|
* Various performance improvements
|
||||||
* On top of the performance regression fixes
|
* On top of the performance regression fixes
|
||||||
* Experimental support for PCH was added (#1061)
|
* Experimental support for PCH was added (#1061)
|
||||||
@@ -80,7 +235,7 @@
|
|||||||
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
|
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
|
||||||
|
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Fixed performance regression from Catch classic
|
* Fixed performance regression from Catch classic
|
||||||
* One of the performance improvement patches for Catch classic was not applied to Catch2
|
* One of the performance improvement patches for Catch classic was not applied to Catch2
|
||||||
* Fixed platform detection for iOS (#1084)
|
* Fixed platform detection for iOS (#1084)
|
||||||
@@ -93,7 +248,7 @@
|
|||||||
* Fixed `std::uncaught_exception` deprecation warning (#1124)
|
* Fixed `std::uncaught_exception` deprecation warning (#1124)
|
||||||
|
|
||||||
|
|
||||||
## New features
|
### New features
|
||||||
* New Matchers
|
* New Matchers
|
||||||
* Regex matcher for strings, `Matches`.
|
* Regex matcher for strings, `Matches`.
|
||||||
* Set-equal matcher for vectors, `UnorderedEquals`
|
* Set-equal matcher for vectors, `UnorderedEquals`
|
||||||
@@ -102,15 +257,15 @@
|
|||||||
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
|
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
|
||||||
|
|
||||||
|
|
||||||
## Other changes
|
### Other changes
|
||||||
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
|
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
## Breaking changes
|
### Breaking changes
|
||||||
* Removed C++98 support
|
* Removed C++98 support
|
||||||
* Removed legacy reporter support
|
* Removed legacy reporter support
|
||||||
* Removed legacy generator support
|
* Removed legacy generator support
|
||||||
@@ -140,7 +295,7 @@
|
|||||||
* `INFINITY == Approx(INFINITY)` returns true
|
* `INFINITY == Approx(INFINITY)` returns true
|
||||||
|
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Reporters and Listeners can be defined in files different from the main file
|
* Reporters and Listeners can be defined in files different from the main file
|
||||||
* The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
|
* The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
|
||||||
* Errors that happen during set up before main are now caught and properly reported once main is entered
|
* Errors that happen during set up before main are now caught and properly reported once main is entered
|
||||||
@@ -174,7 +329,7 @@
|
|||||||
* Add `pkg-config` support to CMake install command
|
* Add `pkg-config` support to CMake install command
|
||||||
|
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Don't use console colour if running in XCode
|
* Don't use console colour if running in XCode
|
||||||
* Explicit constructor in reporter base class
|
* Explicit constructor in reporter base class
|
||||||
* Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
|
* Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
|
||||||
@@ -186,7 +341,7 @@
|
|||||||
* Suppressed C4061 warning under MSVC
|
* Suppressed C4061 warning under MSVC
|
||||||
|
|
||||||
|
|
||||||
## Internal changes
|
### Internal changes
|
||||||
* The development version now uses .cpp files instead of header files containing implementation.
|
* The development version now uses .cpp files instead of header files containing implementation.
|
||||||
* This makes partial rebuilds much faster during development
|
* This makes partial rebuilds much faster during development
|
||||||
* The expression decomposition layer has been rewritten
|
* The expression decomposition layer has been rewritten
|
||||||
@@ -194,13 +349,33 @@
|
|||||||
* New library (TextFlow) is used for formatting text to output
|
* New library (TextFlow) is used for formatting text to output
|
||||||
|
|
||||||
|
|
||||||
# Older versions
|
## Older versions
|
||||||
|
|
||||||
## 1.11.x
|
### 1.12.x
|
||||||
|
|
||||||
### 1.11.0
|
#### 1.12.2
|
||||||
|
##### Fixes
|
||||||
|
* Fixed missing <cassert> include
|
||||||
|
|
||||||
#### Fixes
|
#### 1.12.1
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
|
* Fixed deprecation warning in `ScopedMessage::~ScopedMessage`
|
||||||
|
* All uses of `min` or `max` identifiers are now wrapped in parentheses
|
||||||
|
* This avoids problems when Windows headers define `min` and `max` macros
|
||||||
|
|
||||||
|
#### 1.12.0
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
|
* Fixed compilation for strict C++98 mode (ie not gnu++98) and older compilers (#1103)
|
||||||
|
* `INFO` messages are included in the `xml` reporter output even without `-s` specified.
|
||||||
|
|
||||||
|
|
||||||
|
### 1.11.x
|
||||||
|
|
||||||
|
#### 1.11.0
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
|
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
|
||||||
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
|
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
|
||||||
* `Approx::Margin` is now inclusive (#952)
|
* `Approx::Margin` is now inclusive (#952)
|
||||||
@@ -208,7 +383,7 @@
|
|||||||
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
|
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
|
||||||
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
|
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
|
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
|
||||||
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
|
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
|
||||||
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
|
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
|
||||||
@@ -216,35 +391,35 @@
|
|||||||
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
|
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
|
||||||
* This means you do not have to manually rerun CMake configuration step to detect new tests
|
* This means you do not have to manually rerun CMake configuration step to detect new tests
|
||||||
|
|
||||||
## 1.10.x
|
### 1.10.x
|
||||||
|
|
||||||
### 1.10.0
|
#### 1.10.0
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Evaluation layer has been rewritten (backported from Catch 2)
|
* Evaluation layer has been rewritten (backported from Catch 2)
|
||||||
* The new layer is much simpler and fixes some issues (#981)
|
* The new layer is much simpler and fixes some issues (#981)
|
||||||
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
|
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
|
||||||
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
|
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
|
||||||
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
|
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
|
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
|
||||||
* Added "wait-for-keypress" option
|
* Added "wait-for-keypress" option
|
||||||
|
|
||||||
## 1.9.x
|
### 1.9.x
|
||||||
|
|
||||||
### 1.9.6
|
#### 1.9.6
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* Catch's runtime overhead has been significantly decreased (#937, #939)
|
* Catch's runtime overhead has been significantly decreased (#937, #939)
|
||||||
* Added `--list-extra-info` cli option (#934).
|
* Added `--list-extra-info` cli option (#934).
|
||||||
* It lists all tests together with extra information, ie filename, line number and description.
|
* It lists all tests together with extra information, ie filename, line number and description.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.9.5
|
#### 1.9.5
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Truthy expressions are now reconstructed properly, not as booleans (#914)
|
* Truthy expressions are now reconstructed properly, not as booleans (#914)
|
||||||
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
|
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
|
||||||
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
|
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
|
||||||
@@ -252,35 +427,35 @@
|
|||||||
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
|
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
|
||||||
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
|
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
|
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
|
||||||
* Various documentation improvements
|
* Various documentation improvements
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.9.4
|
#### 1.9.4
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
|
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
|
||||||
* `INFO` messages are no longer cleared after being reported once
|
* `INFO` messages are no longer cleared after being reported once
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
|
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
|
||||||
* Note that Catch still officially supports only ASCII
|
* Note that Catch still officially supports only ASCII
|
||||||
|
|
||||||
### 1.9.3
|
#### 1.9.3
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
|
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
|
||||||
|
|
||||||
### 1.9.2
|
#### 1.9.2
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
|
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
|
||||||
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
|
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
|
||||||
|
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* POSIX signals are now disabled by default under QNX (#889)
|
* POSIX signals are now disabled by default under QNX (#889)
|
||||||
* QNX does not support current enough (2001) POSIX specification
|
* QNX does not support current enough (2001) POSIX specification
|
||||||
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
|
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
|
||||||
@@ -288,22 +463,22 @@
|
|||||||
* Catch no longer attempts to define `uint64_t` on windows (#862)
|
* Catch no longer attempts to define `uint64_t` on windows (#862)
|
||||||
* This was causing trouble when compiled under Cygwin
|
* This was causing trouble when compiled under Cygwin
|
||||||
|
|
||||||
#### Other
|
##### Other
|
||||||
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
|
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
|
||||||
* We now provide cmake script that autoregisters Catch tests into ctest.
|
* We now provide cmake script that autoregisters Catch tests into ctest.
|
||||||
* See `contrib` folder.
|
* See `contrib` folder.
|
||||||
|
|
||||||
|
|
||||||
### 1.9.1
|
#### 1.9.1
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Unexpected exceptions are no longer ignored by default (#885, #887)
|
* Unexpected exceptions are no longer ignored by default (#885, #887)
|
||||||
|
|
||||||
|
|
||||||
### 1.9.0
|
#### 1.9.0
|
||||||
|
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
|
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
|
||||||
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
|
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
|
||||||
* This actually reverts changes made in v1.7.2
|
* This actually reverts changes made in v1.7.2
|
||||||
@@ -317,7 +492,7 @@
|
|||||||
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
|
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
|
||||||
* Captured messages are now printed on unexpected exceptions
|
* Captured messages are now printed on unexpected exceptions
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
|
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
|
||||||
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
|
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
|
||||||
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
|
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
|
||||||
@@ -326,18 +501,18 @@
|
|||||||
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
|
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
|
||||||
|
|
||||||
|
|
||||||
#### Other notes:
|
##### Other notes:
|
||||||
* We have added VS 2017 to our CI
|
* We have added VS 2017 to our CI
|
||||||
* Work on Catch 2 should start soon
|
* Work on Catch 2 should start soon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 1.8.x
|
### 1.8.x
|
||||||
|
|
||||||
### 1.8.2
|
#### 1.8.2
|
||||||
|
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* TAP reporter now behaves as if `-s` was always set
|
* TAP reporter now behaves as if `-s` was always set
|
||||||
* This should be more consistent with the protocol desired behaviour.
|
* This should be more consistent with the protocol desired behaviour.
|
||||||
* Compact reporter now obeys `-d yes` argument (#780)
|
* Compact reporter now obeys `-d yes` argument (#780)
|
||||||
@@ -351,7 +526,7 @@
|
|||||||
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
|
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
|
||||||
|
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
|
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
|
||||||
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
|
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
|
||||||
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
|
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
|
||||||
@@ -368,21 +543,21 @@
|
|||||||
* Regression in Objective-C bindings (Matchers) fixed (#854)
|
* Regression in Objective-C bindings (Matchers) fixed (#854)
|
||||||
|
|
||||||
|
|
||||||
#### Other notes:
|
##### Other notes:
|
||||||
* We have added VS 2013 and 2015 to our CI
|
* We have added VS 2013 and 2015 to our CI
|
||||||
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
|
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.8.1
|
#### 1.8.1
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
|
|
||||||
Cygwin issue with `gettimeofday` - `#define` was not early enough
|
Cygwin issue with `gettimeofday` - `#define` was not early enough
|
||||||
|
|
||||||
### 1.8.0
|
#### 1.8.0
|
||||||
|
|
||||||
#### New features/ minor changes
|
##### New features/ minor changes
|
||||||
|
|
||||||
* Matchers have new, simpler (and documented) interface.
|
* Matchers have new, simpler (and documented) interface.
|
||||||
* Catch provides string and vector matchers.
|
* Catch provides string and vector matchers.
|
||||||
@@ -402,7 +577,7 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
|
|||||||
* `Approx` now supports an optional margin of absolute error
|
* `Approx` now supports an optional margin of absolute error
|
||||||
* It has also received [new documentation](assertions.md#top).
|
* It has also received [new documentation](assertions.md#top).
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
|
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
|
||||||
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
|
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
|
||||||
* Cygwin compatibility fixes
|
* Cygwin compatibility fixes
|
||||||
@@ -413,15 +588,15 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
|
|||||||
* Otherwise it is supressed for the whole TU
|
* Otherwise it is supressed for the whole TU
|
||||||
* Fixed test spec parser issue (with escapes in multiple names)
|
* Fixed test spec parser issue (with escapes in multiple names)
|
||||||
|
|
||||||
#### Other
|
##### Other
|
||||||
* Various documentation fixes and improvements
|
* Various documentation fixes and improvements
|
||||||
|
|
||||||
|
|
||||||
## 1.7.x
|
### 1.7.x
|
||||||
|
|
||||||
### 1.7.2
|
#### 1.7.2
|
||||||
|
|
||||||
#### Fixes and minor improvements
|
##### Fixes and minor improvements
|
||||||
Xml:
|
Xml:
|
||||||
|
|
||||||
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
|
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
|
||||||
@@ -440,9 +615,9 @@ Other:
|
|||||||
* Silenced a few more warnings in different circumstances
|
* Silenced a few more warnings in different circumstances
|
||||||
* Travis improvements
|
* Travis improvements
|
||||||
|
|
||||||
### 1.7.1
|
#### 1.7.1
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
|
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
|
||||||
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
|
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
|
||||||
* For specifics, look into the [documentation](configuration.md#top).
|
* For specifics, look into the [documentation](configuration.md#top).
|
||||||
@@ -452,9 +627,9 @@ Other:
|
|||||||
* Fixed possible infinite recursion in Windows SEH.
|
* Fixed possible infinite recursion in Windows SEH.
|
||||||
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
|
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
|
||||||
|
|
||||||
### 1.7.0
|
#### 1.7.0
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Catch now runs significantly faster for passing tests
|
* Catch now runs significantly faster for passing tests
|
||||||
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
||||||
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
||||||
@@ -468,30 +643,30 @@ Other:
|
|||||||
* Certain characters (space, tab, etc) are now pretty printed.
|
* Certain characters (space, tab, etc) are now pretty printed.
|
||||||
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
||||||
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
||||||
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
||||||
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Catch's CMakeLists now defines install command.
|
* Catch's CMakeLists now defines install command.
|
||||||
* Catch's CMakeLists now generates projects with warnings enabled.
|
* Catch's CMakeLists now generates projects with warnings enabled.
|
||||||
|
|
||||||
|
|
||||||
## 1.6.x
|
### 1.6.x
|
||||||
|
|
||||||
### 1.6.1
|
#### 1.6.1
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Catch now supports breaking into debugger on Linux
|
* Catch now supports breaking into debugger on Linux
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Generators no longer leak memory (generators are still unsupported in general)
|
* Generators no longer leak memory (generators are still unsupported in general)
|
||||||
* JUnit reporter now reports UTC timestamps, instead of "tbd"
|
* JUnit reporter now reports UTC timestamps, instead of "tbd"
|
||||||
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
|
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
|
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
|
||||||
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
|
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
|
||||||
* This change is not active when compiling a binary
|
* This change is not active when compiling a binary
|
||||||
@@ -501,28 +676,28 @@ Other:
|
|||||||
* This can be disabled if needed, see [documentation](configuration.md#top) for details.
|
* This can be disabled if needed, see [documentation](configuration.md#top) for details.
|
||||||
|
|
||||||
|
|
||||||
### 1.6.0
|
#### 1.6.0
|
||||||
|
|
||||||
#### Cmake/ projects:
|
##### Cmake/ projects:
|
||||||
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
|
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Approx now supports `>=` and `<=`
|
* Approx now supports `>=` and `<=`
|
||||||
* Can now use `\` to escape chars in test names on command line
|
* Can now use `\` to escape chars in test names on command line
|
||||||
* Standardize C++11 feature toggles
|
* Standardize C++11 feature toggles
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Blue shell colour
|
* Blue shell colour
|
||||||
* Missing argument to `CATCH_CHECK_THROWS`
|
* Missing argument to `CATCH_CHECK_THROWS`
|
||||||
* Don't encode extended ASCII in XML
|
* Don't encode extended ASCII in XML
|
||||||
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
|
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
|
||||||
* Use `__COUNTER__` more consistently (where available)
|
* Use `__COUNTER__` more consistently (where available)
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
|
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
|
||||||
|
|
||||||
|
|
||||||
# Even Older versions
|
## Even Older versions
|
||||||
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@@ -49,17 +49,5 @@ on a specific version of the single-include header.
|
|||||||
|
|
||||||
## Optional steps
|
## Optional steps
|
||||||
|
|
||||||
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
|
Because Catch's [vcpkg](https://github.com/Microsoft/vcpkg) port updates
|
||||||
|
itself automagically, there are no optional steps at this time.
|
||||||
|
|
||||||
### vcpkg update
|
|
||||||
|
|
||||||
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of necessary work for you, it creates a branch and commits necessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
|
|
||||||
|
|
||||||
Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
|
|
||||||
```
|
|
||||||
GitHub
|
|
||||||
Catch
|
|
||||||
vcpkg
|
|
||||||
```
|
|
||||||
|
|
||||||
|
@@ -25,8 +25,8 @@ Because of the way the junit format is structured the run must complete before a
|
|||||||
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
|
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
|
||||||
Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
|
Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
|
||||||
|
|
||||||
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
|
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
|
||||||
Use this when building as part of a TeamCity build to see results as they happen.
|
Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
|
||||||
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
||||||
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
||||||
|
|
||||||
|
@@ -20,10 +20,10 @@ Tags allow an arbitrary number of additional strings to be associated with a tes
|
|||||||
|
|
||||||
As an example - given the following test cases:
|
As an example - given the following test cases:
|
||||||
|
|
||||||
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
||||||
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
||||||
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
||||||
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
||||||
|
|
||||||
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
|
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
|||||||
|
|
||||||
* `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
* `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
||||||
|
|
||||||
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
|
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
|
||||||
|
|
||||||
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
||||||
|
|
||||||
@@ -55,11 +55,11 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
|||||||
|
|
||||||
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
|
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
|
||||||
|
|
||||||
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
|
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
|
||||||
|
|
||||||
Aliases must begin with the `@` character. An example of a tag alias is:
|
Aliases must begin with the `@` character. An example of a tag alias is:
|
||||||
|
|
||||||
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
|
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
|
||||||
|
|
||||||
Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.
|
Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# String conversions
|
# String conversions
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[operator << overload for std::ostream](#operator--overload-for-stdostream)<br>
|
||||||
|
[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
|
||||||
|
[Catch::is_range specialisation](#catchis_range-specialisation)<br>
|
||||||
|
[Exceptions](#exceptions)<br>
|
||||||
|
|
||||||
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
|
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
|
||||||
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
||||||
|
|
||||||
@@ -10,8 +16,8 @@ This is the standard way of providing string conversions in C++ - and the chance
|
|||||||
|
|
||||||
```
|
```
|
||||||
std::ostream& operator << ( std::ostream& os, T const& value ) {
|
std::ostream& operator << ( std::ostream& os, T const& value ) {
|
||||||
os << convertMyTypeToString( value );
|
os << convertMyTypeToString( value );
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -19,21 +25,21 @@ std::ostream& operator << ( std::ostream& os, T const& value ) {
|
|||||||
|
|
||||||
You should put this function in the same namespace as your type and have it declared before including Catch's header.
|
You should put this function in the same namespace as your type and have it declared before including Catch's header.
|
||||||
|
|
||||||
## Catch::StringMaker<T> specialisation
|
## Catch::StringMaker specialisation
|
||||||
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
|
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
|
||||||
|
|
||||||
```
|
```
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<T> {
|
struct StringMaker<T> {
|
||||||
static std::string convert( T const& value ) {
|
static std::string convert( T const& value ) {
|
||||||
return convertMyTypeToString( value );
|
return convertMyTypeToString( value );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Catch::is_range<T> specialisation
|
## Catch::is_range specialisation
|
||||||
As a fallback, Catch attempts to detect if the type can be iterated
|
As a fallback, Catch attempts to detect if the type can be iterated
|
||||||
(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
|
(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
|
||||||
as a range. For certain types this can lead to infinite recursion, so
|
as a range. For certain types this can lead to infinite recursion, so
|
||||||
@@ -56,7 +62,7 @@ By default all exceptions deriving from `std::exception` will be translated to s
|
|||||||
|
|
||||||
```
|
```
|
||||||
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
|
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
|
||||||
return ex.message();
|
return ex.message();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
## Getting Catch2
|
## Getting Catch2
|
||||||
|
|
||||||
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/CatchOrg/Catch2/master/single_include/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
|
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
|
||||||
|
|
||||||
|
Alternative ways of getting Catch2 include using your system package
|
||||||
|
manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).
|
||||||
|
|
||||||
The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
|
The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
|
||||||
|
|
||||||
@@ -23,6 +26,9 @@ Catch2 is header only. All you need to do is drop the file somewhere reachable f
|
|||||||
|
|
||||||
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
||||||
|
|
||||||
|
_If you have installed Catch2 from system package manager, or CMake
|
||||||
|
package, you need to include the header as `#include <catch2/catch.hpp>`_
|
||||||
|
|
||||||
## Writing tests
|
## Writing tests
|
||||||
|
|
||||||
Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
|
Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
// That's it
|
// That's it
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
int Factorial( int number ) {
|
int Factorial( int number ) {
|
||||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
|
TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// main() provided by Catch in file 020-TestCase-1.cpp.
|
// main() provided by Catch in file 020-TestCase-1.cpp.
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
int Factorial( int number ) {
|
int Factorial( int number ) {
|
||||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
std::string one() {
|
std::string one() {
|
||||||
return "1";
|
return "1";
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
class DBConnection
|
class DBConnection
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
||||||
|
|
||||||
|
27
examples/200-Rpt-CatchMain.cpp
Normal file
27
examples/200-Rpt-CatchMain.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 200-Rpt-CatchMain.cpp
|
||||||
|
|
||||||
|
// In a Catch project with multiple files, dedicate one file to compile the
|
||||||
|
// source code of Catch itself and reuse the resulting object file for linking.
|
||||||
|
|
||||||
|
// Let Catch provide main():
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_1
|
||||||
|
#include CATCH_EXAMPLE_RPT_1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_2
|
||||||
|
#include CATCH_EXAMPLE_RPT_2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_3
|
||||||
|
#include CATCH_EXAMPLE_RPT_3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// That's it
|
||||||
|
|
||||||
|
// Compile implementation of Catch for use with files that do contain tests:
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
|
||||||
|
// cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
|
171
examples/207-Rpt-TeamCityReporter.cpp
Normal file
171
examples/207-Rpt-TeamCityReporter.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
// 207-Rpt-TeamCityReporter.cpp
|
||||||
|
|
||||||
|
// Catch has built-in and external reporters:
|
||||||
|
// Built-in:
|
||||||
|
// - compact
|
||||||
|
// - console
|
||||||
|
// - junit
|
||||||
|
// - xml
|
||||||
|
// External:
|
||||||
|
// - automake
|
||||||
|
// - tap
|
||||||
|
// - teamcity (this example)
|
||||||
|
|
||||||
|
// main() and reporter code provided in 200-Rpt-CatchMain.cpp
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning (disable : 4702) // Disable warning: unreachable code
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity passes unconditionally succeeding assertion", "[teamcity]" ) {
|
||||||
|
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unconditionally failing assertion", "[teamcity]" ) {
|
||||||
|
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE( 3 == 7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check-false", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_FALSE( 3 == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check-that", "[teamcity]" ) {
|
||||||
|
|
||||||
|
using namespace Catch;
|
||||||
|
|
||||||
|
REQUIRE_THAT( "hello", Contains( "world" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unexpected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE( (throw std::runtime_error("surprise!"), true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports undesired exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW( (throw std::runtime_error("surprise!"), true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports missing expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports missing specific expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS_AS( throw std::bad_alloc(), std::runtime_error );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unexpected message in expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
using namespace Catch;
|
||||||
|
|
||||||
|
CHECK_THROWS_WITH( throw std::runtime_error("hello"), "world" );
|
||||||
|
CHECK_THROWS_WITH( throw std::runtime_error("hello"), Contains("world") );
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyException: public std::runtime_error
|
||||||
|
{
|
||||||
|
MyException( char const * text )
|
||||||
|
: std::runtime_error( text ) {}
|
||||||
|
|
||||||
|
~MyException() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// prevent -Wweak-vtables:
|
||||||
|
MyException::~MyException() = default;
|
||||||
|
|
||||||
|
struct MyExceptionMatcher : Catch::MatcherBase< std::runtime_error >
|
||||||
|
{
|
||||||
|
std::string m_text;
|
||||||
|
|
||||||
|
MyExceptionMatcher( char const * text )
|
||||||
|
: m_text( text )
|
||||||
|
{}
|
||||||
|
|
||||||
|
~MyExceptionMatcher() override;
|
||||||
|
|
||||||
|
bool match( std::runtime_error const & arg ) const override
|
||||||
|
{
|
||||||
|
return m_text == arg.what() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string describe() const override
|
||||||
|
{
|
||||||
|
return "it's me";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// prevent -Wweak-vtables:
|
||||||
|
MyExceptionMatcher::~MyExceptionMatcher() = default;
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity failing check-throws-matches", "[teamcity]" ) {
|
||||||
|
|
||||||
|
CHECK_THROWS_MATCHES( throw MyException("hello"), MyException, MyExceptionMatcher("world") );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!throws] - lets Catch know that this test is likely to throw an exception even if successful.
|
||||||
|
// This causes the test to be excluded when running with -e or --nothrow.
|
||||||
|
|
||||||
|
// No special effects for the reporter.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity throwing exception with tag [!throws]", "[teamcity][!throws]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS( throw std::runtime_error("unsurprisingly") );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!mayfail] - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity failing assertion with tag [!mayfail]", "[teamcity][!mayfail] " ) {
|
||||||
|
|
||||||
|
REQUIRE( 3 == 7 ); // doesn't fail test case this time, reports: testIgnored
|
||||||
|
REQUIRE( 3 == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!shouldfail] - like [!mayfail] but fails the test if it passes.
|
||||||
|
// This can be useful if you want to be notified of accidental, or third-party, fixes.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity succeeding assertion with tag [!shouldfail]", "[teamcity][!shouldfail]" ) {
|
||||||
|
|
||||||
|
SUCCEED( "Marked [!shouldfail]" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile & run:
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -o 207-Rpt-TeamCityReporter 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
|
||||||
|
//
|
||||||
|
// - cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
|
||||||
|
// - cl -EHsc -I%CATCH_ROOT% 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
|
||||||
|
|
||||||
|
// Compilation output (--list-reporters):
|
||||||
|
// Available reporters:
|
||||||
|
// compact: Reports test results on a single line, suitable for IDEs
|
||||||
|
// console: Reports test results as plain lines of text
|
||||||
|
// junit: Reports test results in an XML format that looks like Ant's
|
||||||
|
// junitreport target
|
||||||
|
// teamcity: Reports test results as TeamCity service messages
|
||||||
|
// xml: Reports test results as an XML document
|
||||||
|
|
||||||
|
// Expected output (abbreviated and broken into shorter lines):
|
||||||
|
//
|
||||||
|
// prompt> 207-Rpt-TeamCityReporter.exe --reporter teamcity
|
||||||
|
// ##teamcity[testSuiteStarted name='207-Rpt-TeamCityReporter.exe']
|
||||||
|
// ##teamcity[testStarted name='TeamCity passes unconditionally succeeding assertion']
|
||||||
|
// ##teamcity[testFinished name='TeamCity passes unconditionally succeeding assertion' duration='1']
|
||||||
|
// ##teamcity[testStarted name='TeamCity reports unconditionally failing assertion']
|
||||||
|
// ##teamcity[testFailed name='TeamCity reports unconditionally failing assertion' /
|
||||||
|
// message='.../examples/207-Rpt-TeamCityReporter.cpp:23|n/
|
||||||
|
// ...............................................................................|n|n/
|
||||||
|
// .../examples/207-Rpt-TeamCityReporter.cpp:25|nexplicit failure']
|
||||||
|
// ##teamcity[testFinished name='TeamCity reports unconditionally failing assertion' duration='3']
|
||||||
|
// ...
|
@@ -10,7 +10,7 @@
|
|||||||
// Let Catch provide the required interfaces:
|
// Let Catch provide the required interfaces:
|
||||||
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@@ -187,8 +187,7 @@ void print( std::ostream& os, int const level, std::string const& title, Catch::
|
|||||||
|
|
||||||
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
|
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
|
||||||
os << ws(level ) << title << ":\n"
|
os << ws(level ) << title << ":\n"
|
||||||
<< ws(level+1) << "- name: " << info.name << "\n"
|
<< ws(level+1) << "- name: " << info.name << "\n";
|
||||||
<< ws(level+1) << "- description: '" << info.description << "'\n";
|
|
||||||
print( os, level+1 , "- lineInfo", info.lineInfo );
|
print( os, level+1 , "- lineInfo", info.lineInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
examples/231-Cfg-OutputStreams.cpp
Normal file
49
examples/231-Cfg-OutputStreams.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// 231-Cfg-OutputStreams.cpp
|
||||||
|
// Show how to replace the streams with a simple custom made streambuf.
|
||||||
|
|
||||||
|
// Note that this reimplementation _does not_ follow `std::cerr`
|
||||||
|
// semantic, because it buffers the output. For most uses however,
|
||||||
|
// there is no important difference between having `std::cerr` buffered
|
||||||
|
// or unbuffered.
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_NOSTDOUT
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
class out_buff : public std::stringbuf {
|
||||||
|
std::FILE* m_stream;
|
||||||
|
public:
|
||||||
|
out_buff(std::FILE* stream) :m_stream(stream) {}
|
||||||
|
~out_buff() { pubsync(); }
|
||||||
|
int sync() {
|
||||||
|
int ret = 0;
|
||||||
|
for (unsigned char c : str()) {
|
||||||
|
if (putc(c, m_stream) == EOF) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reset the buffer to avoid printing it multiple times
|
||||||
|
str("");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
std::ostream& cout() {
|
||||||
|
static std::ostream ret(new out_buff(stdout));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::ostream& clog() {
|
||||||
|
static std::ostream ret(new out_buff(stderr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::ostream& cerr() {
|
||||||
|
return clog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("This binary uses putc to write out output", "[compilation-only]") {
|
||||||
|
SUCCEED("Nothing to test.");
|
||||||
|
}
|
@@ -8,15 +8,19 @@ cmake_minimum_required( VERSION 3.0 )
|
|||||||
|
|
||||||
project( CatchExamples CXX )
|
project( CatchExamples CXX )
|
||||||
|
|
||||||
|
message( STATUS "Examples included" )
|
||||||
|
|
||||||
# define folders used:
|
# define folders used:
|
||||||
|
|
||||||
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
|
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
|
||||||
set( HEADER_DIR ${CATCH_DIR}/single_include )
|
set( HEADER_DIR ${CATCH_DIR}/single_include )
|
||||||
|
set( REPORTER_HEADER_DIR ${CATCH_DIR}/include/reporters )
|
||||||
|
|
||||||
# single-file sources:
|
# single-file sources:
|
||||||
|
|
||||||
set( SOURCES_SINGLE_FILE
|
set( SOURCES_SINGLE_FILE
|
||||||
010-TestCase.cpp
|
010-TestCase.cpp
|
||||||
|
231-Cfg-OutputStreams.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# multiple-file modules:
|
# multiple-file modules:
|
||||||
@@ -42,6 +46,26 @@ set( SOURCES_IDIOMATIC_TESTS
|
|||||||
210-Evt-EventListeners.cpp
|
210-Evt-EventListeners.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# main-s for reporter-specific test sources:
|
||||||
|
|
||||||
|
set( SOURCES_REPORTERS_MAIN
|
||||||
|
200-Rpt-CatchMain.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN 200-Rpt-CatchMain.cpp )
|
||||||
|
|
||||||
|
set( NAMES_REPORTERS TeamCity )
|
||||||
|
|
||||||
|
foreach( reporter ${NAMES_REPORTERS} )
|
||||||
|
list( APPEND SOURCES_SPECIFIC_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN}${reporter}.cpp )
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# sources to combine with 200-Rpt-CatchMain{Reporter}.cpp:
|
||||||
|
|
||||||
|
set( SOURCES_REPORTERS_TESTS
|
||||||
|
207-Rpt-TeamCityReporter.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# check if all sources are listed, warn if not:
|
# check if all sources are listed, warn if not:
|
||||||
|
|
||||||
set( SOURCES_ALL
|
set( SOURCES_ALL
|
||||||
@@ -49,6 +73,8 @@ set( SOURCES_ALL
|
|||||||
${SOURCES_SINGLE_FILE}
|
${SOURCES_SINGLE_FILE}
|
||||||
${SOURCES_IDIOMATIC_MAIN}
|
${SOURCES_IDIOMATIC_MAIN}
|
||||||
${SOURCES_IDIOMATIC_TESTS}
|
${SOURCES_IDIOMATIC_TESTS}
|
||||||
|
${SOURCES_REPORTERS_MAIN}
|
||||||
|
${SOURCES_REPORTERS_TESTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach( name ${SOURCES_ALL} )
|
foreach( name ${SOURCES_ALL} )
|
||||||
@@ -61,29 +87,55 @@ CheckFileList( SOURCES_ALL_PATH ${EXAMPLES_DIR} )
|
|||||||
|
|
||||||
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
|
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
|
||||||
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
|
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_TESTS "${SOURCES_REPORTERS_TESTS}" )
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN "${SOURCES_REPORTERS_MAIN}" )
|
||||||
|
|
||||||
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
|
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
|
||||||
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
|
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
|
||||||
set( TARGETS_ALL ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 020-TestCase CatchMain )
|
set( TARGETS_REPORTERS_TESTS ${BASENAMES_REPORTERS_TESTS} )
|
||||||
|
set( TARGETS_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN} )
|
||||||
|
|
||||||
|
set( TARGETS_ALL
|
||||||
|
${TARGETS_SINGLE_FILE}
|
||||||
|
020-TestCase
|
||||||
|
${TARGETS_IDIOMATIC_TESTS} CatchMain
|
||||||
|
${TARGETS_REPORTERS_TESTS} CatchMainTeamCity
|
||||||
|
)
|
||||||
|
|
||||||
# define program targets:
|
# define program targets:
|
||||||
|
|
||||||
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch.hpp )
|
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_library( CatchMainAutomake OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_library( CatchMainTap OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
add_library( CatchMainTeamCity OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch.hpp )
|
#target_compile_definitions( CatchMainAutomake PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_automake.hpp\" )
|
||||||
|
#target_compile_definitions( CatchMainTap PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_tap.hpp\" )
|
||||||
|
target_compile_definitions( CatchMainTeamCity PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" )
|
||||||
|
|
||||||
foreach( name ${TARGETS_SINGLE_FILE} )
|
foreach( name ${TARGETS_SINGLE_FILE} )
|
||||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch.hpp )
|
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
foreach( name ${TARGETS_IDIOMATIC_TESTS} )
|
foreach( name ${TARGETS_IDIOMATIC_TESTS} )
|
||||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch.hpp )
|
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
|
#add_executable( 207-Rpt-AutomakeReporter ${EXAMPLES_DIR}/207-Rpt-AutomakeReporter.cpp $<TARGET_OBJECTS:CatchMainAutomake> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_executable( 207-Rpt-TapReporter ${EXAMPLES_DIR}/207-Rpt-TapReporter.cpp $<TARGET_OBJECTS:CatchMainTap> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
add_executable( 207-Rpt-TeamCityReporter ${EXAMPLES_DIR}/207-Rpt-TeamCityReporter.cpp $<TARGET_OBJECTS:CatchMainTeamCity> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
|
#foreach( name ${TARGETS_REPORTERS_TESTS} )
|
||||||
|
# add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#endforeach()
|
||||||
|
|
||||||
foreach( name ${TARGETS_ALL} )
|
foreach( name ${TARGETS_ALL} )
|
||||||
target_include_directories( ${name} PRIVATE ${HEADER_DIR} )
|
target_include_directories( ${name} PRIVATE ${HEADER_DIR} ${CATCH_DIR} )
|
||||||
|
|
||||||
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
|
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
|
||||||
|
set_property(TARGET ${name} PROPERTY CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
# Add desired warnings
|
# Add desired warnings
|
||||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||||
@@ -98,3 +150,4 @@ foreach( name ${TARGETS_ALL} )
|
|||||||
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
|
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 2
|
#define CATCH_VERSION_MAJOR 2
|
||||||
#define CATCH_VERSION_MINOR 2
|
#define CATCH_VERSION_MINOR 4
|
||||||
#define CATCH_VERSION_PATCH 1
|
#define CATCH_VERSION_PATCH 1
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@@ -33,7 +33,9 @@
|
|||||||
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||||
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
||||||
# endif
|
# endif
|
||||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
|
||||||
|
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||||
@@ -60,6 +62,7 @@
|
|||||||
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
||||||
#include "internal/catch_capture_matchers.h"
|
#include "internal/catch_capture_matchers.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "internal/catch_generators.hpp"
|
||||||
|
|
||||||
// These files are included here so the single_include script doesn't put them
|
// These files are included here so the single_include script doesn't put them
|
||||||
// in the conditionally compiled sections
|
// in the conditionally compiled sections
|
||||||
@@ -128,13 +131,14 @@
|
|||||||
|
|
||||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
|
||||||
|
|
||||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
@@ -144,11 +148,12 @@
|
|||||||
// "BDD-style" convenience wrappers
|
// "BDD-style" convenience wrappers
|
||||||
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc )
|
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc )
|
#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc )
|
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
||||||
#else
|
#else
|
||||||
@@ -187,13 +192,14 @@
|
|||||||
|
|
||||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
|
||||||
|
|
||||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
@@ -207,15 +213,17 @@
|
|||||||
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
|
|
||||||
#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc )
|
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
#define WHEN( desc ) SECTION( std::string(" When: ") + desc )
|
#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc )
|
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
#define THEN( desc ) SECTION( std::string(" Then: ") + desc )
|
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc )
|
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
using Catch::Detail::Approx;
|
using Catch::Detail::Approx;
|
||||||
|
|
||||||
#else
|
#else // CATCH_CONFIG_DISABLE
|
||||||
|
|
||||||
//////
|
//////
|
||||||
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
||||||
#ifdef CATCH_CONFIG_PREFIX_ALL
|
#ifdef CATCH_CONFIG_PREFIX_ALL
|
||||||
@@ -260,6 +268,7 @@ using Catch::Detail::Approx;
|
|||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define CATCH_SECTION( ... )
|
#define CATCH_SECTION( ... )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... )
|
||||||
#define CATCH_FAIL( ... ) (void)(0)
|
#define CATCH_FAIL( ... ) (void)(0)
|
||||||
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||||
#define CATCH_SUCCEED( ... ) (void)(0)
|
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||||
@@ -270,6 +279,7 @@ using Catch::Detail::Approx;
|
|||||||
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
||||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
||||||
#define CATCH_GIVEN( desc )
|
#define CATCH_GIVEN( desc )
|
||||||
|
#define CATCH_AND_GIVEN( desc )
|
||||||
#define CATCH_WHEN( desc )
|
#define CATCH_WHEN( desc )
|
||||||
#define CATCH_AND_WHEN( desc )
|
#define CATCH_AND_WHEN( desc )
|
||||||
#define CATCH_THEN( desc )
|
#define CATCH_THEN( desc )
|
||||||
@@ -319,6 +329,7 @@ using Catch::Detail::Approx;
|
|||||||
#define METHOD_AS_TEST_CASE( method, ... )
|
#define METHOD_AS_TEST_CASE( method, ... )
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define SECTION( ... )
|
#define SECTION( ... )
|
||||||
|
#define DYNAMIC_SECTION( ... )
|
||||||
#define FAIL( ... ) (void)(0)
|
#define FAIL( ... ) (void)(0)
|
||||||
#define FAIL_CHECK( ... ) (void)(0)
|
#define FAIL_CHECK( ... ) (void)(0)
|
||||||
#define SUCCEED( ... ) (void)(0)
|
#define SUCCEED( ... ) (void)(0)
|
||||||
@@ -333,6 +344,7 @@ using Catch::Detail::Approx;
|
|||||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
||||||
|
|
||||||
#define GIVEN( desc )
|
#define GIVEN( desc )
|
||||||
|
#define AND_GIVEN( desc )
|
||||||
#define WHEN( desc )
|
#define WHEN( desc )
|
||||||
#define AND_WHEN( desc )
|
#define AND_WHEN( desc )
|
||||||
#define THEN( desc )
|
#define THEN( desc )
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_approx.h"
|
#include "catch_approx.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@@ -35,6 +36,13 @@ namespace Detail {
|
|||||||
return Approx( 0 );
|
return Approx( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Approx Approx::operator-() const {
|
||||||
|
auto temp(*this);
|
||||||
|
temp.m_value = -temp.m_value;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Approx::toString() const {
|
std::string Approx::toString() const {
|
||||||
ReusableStringStream rss;
|
ReusableStringStream rss;
|
||||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||||
@@ -47,8 +55,31 @@ namespace Detail {
|
|||||||
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Approx::setMargin(double margin) {
|
||||||
|
CATCH_ENFORCE(margin >= 0,
|
||||||
|
"Invalid Approx::margin: " << margin << '.'
|
||||||
|
<< " Approx::Margin has to be non-negative.");
|
||||||
|
m_margin = margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Approx::setEpsilon(double epsilon) {
|
||||||
|
CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
|
||||||
|
"Invalid Approx::epsilon: " << epsilon << '.'
|
||||||
|
<< " Approx::epsilon has to be in [0, 1]");
|
||||||
|
m_epsilon = epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace Detail
|
} // end namespace Detail
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Detail::Approx operator "" _a(long double val) {
|
||||||
|
return Detail::Approx(val);
|
||||||
|
}
|
||||||
|
Detail::Approx operator "" _a(unsigned long long val) {
|
||||||
|
return Detail::Approx(val);
|
||||||
|
}
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
#include "catch_tostring.h"
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
@@ -19,18 +18,26 @@ namespace Detail {
|
|||||||
class Approx {
|
class Approx {
|
||||||
private:
|
private:
|
||||||
bool equalityComparisonImpl(double other) const;
|
bool equalityComparisonImpl(double other) const;
|
||||||
|
// Validates the new margin (margin >= 0)
|
||||||
|
// out-of-line to avoid including stdexcept in the header
|
||||||
|
void setMargin(double margin);
|
||||||
|
// Validates the new epsilon (0 < epsilon < 1)
|
||||||
|
// out-of-line to avoid including stdexcept in the header
|
||||||
|
void setEpsilon(double epsilon);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Approx ( double value );
|
explicit Approx ( double value );
|
||||||
|
|
||||||
static Approx custom();
|
static Approx custom();
|
||||||
|
|
||||||
|
Approx operator-() const;
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx operator()( T const& value ) {
|
Approx operator()( T const& value ) {
|
||||||
Approx approx( static_cast<double>(value) );
|
Approx approx( static_cast<double>(value) );
|
||||||
approx.epsilon( m_epsilon );
|
approx.m_epsilon = m_epsilon;
|
||||||
approx.margin( m_margin );
|
approx.m_margin = m_margin;
|
||||||
approx.scale( m_scale );
|
approx.m_scale = m_scale;
|
||||||
return approx;
|
return approx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,27 +90,14 @@ namespace Detail {
|
|||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx& epsilon( T const& newEpsilon ) {
|
Approx& epsilon( T const& newEpsilon ) {
|
||||||
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||||
if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
|
setEpsilon(epsilonAsDouble);
|
||||||
throw std::domain_error
|
|
||||||
( "Invalid Approx::epsilon: " +
|
|
||||||
Catch::Detail::stringify( epsilonAsDouble ) +
|
|
||||||
", Approx::epsilon has to be between 0 and 1" );
|
|
||||||
}
|
|
||||||
m_epsilon = epsilonAsDouble;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx& margin( T const& newMargin ) {
|
Approx& margin( T const& newMargin ) {
|
||||||
double marginAsDouble = static_cast<double>(newMargin);
|
double marginAsDouble = static_cast<double>(newMargin);
|
||||||
if( marginAsDouble < 0 ) {
|
setMargin(marginAsDouble);
|
||||||
throw std::domain_error
|
|
||||||
( "Invalid Approx::margin: " +
|
|
||||||
Catch::Detail::stringify( marginAsDouble ) +
|
|
||||||
", Approx::Margin has to be non-negative." );
|
|
||||||
|
|
||||||
}
|
|
||||||
m_margin = marginAsDouble;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +115,12 @@ namespace Detail {
|
|||||||
double m_scale;
|
double m_scale;
|
||||||
double m_value;
|
double m_value;
|
||||||
};
|
};
|
||||||
}
|
} // end namespace Detail
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Detail::Approx operator "" _a(long double val);
|
||||||
|
Detail::Approx operator "" _a(unsigned long long val);
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<Catch::Detail::Approx> {
|
struct StringMaker<Catch::Detail::Approx> {
|
||||||
|
@@ -18,9 +18,11 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
namespace {
|
||||||
expr.streamReconstructedExpression( os );
|
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
||||||
return os;
|
expr.streamReconstructedExpression( os );
|
||||||
|
return os;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyExpression::LazyExpression( bool isNegated )
|
LazyExpression::LazyExpression( bool isNegated )
|
||||||
@@ -50,7 +52,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AssertionHandler::AssertionHandler
|
AssertionHandler::AssertionHandler
|
||||||
( StringRef macroName,
|
( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
StringRef capturedExpression,
|
StringRef capturedExpression,
|
||||||
ResultDisposition::Flags resultDisposition )
|
ResultDisposition::Flags resultDisposition )
|
||||||
@@ -79,8 +81,13 @@ namespace Catch {
|
|||||||
// (To go back to the test and change execution, jump over the throw, next)
|
// (To go back to the test and change execution, jump over the throw, next)
|
||||||
CATCH_BREAK_INTO_DEBUGGER();
|
CATCH_BREAK_INTO_DEBUGGER();
|
||||||
}
|
}
|
||||||
if( m_reaction.shouldThrow )
|
if (m_reaction.shouldThrow) {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
throw Catch::TestFailureException();
|
throw Catch::TestFailureException();
|
||||||
|
#else
|
||||||
|
CATCH_ERROR( "Test failure requires aborting test!" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void AssertionHandler::setCompleted() {
|
void AssertionHandler::setCompleted() {
|
||||||
m_completed = true;
|
m_completed = true;
|
||||||
@@ -107,7 +114,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// This is the overload that takes a string and infers the Equals matcher from it
|
// This is the overload that takes a string and infers the Equals matcher from it
|
||||||
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
|
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {
|
||||||
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
|
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@ namespace Catch {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AssertionHandler
|
AssertionHandler
|
||||||
( StringRef macroName,
|
( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
StringRef capturedExpression,
|
StringRef capturedExpression,
|
||||||
ResultDisposition::Flags resultDisposition );
|
ResultDisposition::Flags resultDisposition );
|
||||||
@@ -81,7 +81,7 @@ namespace Catch {
|
|||||||
auto allowThrows() const -> bool;
|
auto allowThrows() const -> bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
|
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
|
@@ -9,8 +9,9 @@
|
|||||||
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||||
|
|
||||||
#include "catch_assertionhandler.h"
|
#include "catch_assertionhandler.h"
|
||||||
#include "catch_message.h"
|
|
||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
|
#include "catch_message.h"
|
||||||
|
#include "catch_stringref.h"
|
||||||
|
|
||||||
#if !defined(CATCH_CONFIG_DISABLE)
|
#if !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
|
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, 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_SUPPRESS_PARENTHESES_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||||
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
|
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
|
||||||
@@ -77,7 +78,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
@@ -94,7 +95,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(expr); \
|
static_cast<void>(expr); \
|
||||||
@@ -115,27 +116,32 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||||
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
} while( false )
|
} while( false )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||||
|
auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
|
||||||
|
varName.captureValues( 0, __VA_ARGS__ )
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Although this is matcher-based, it can be used with just a string
|
// Although this is matcher-based, it can be used with just a string
|
||||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||||
} \
|
} \
|
||||||
catch( ... ) { \
|
catch( ... ) { \
|
||||||
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
|
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||||
|
@@ -15,7 +15,7 @@ namespace Catch {
|
|||||||
// This is the general overload that takes a any string matcher
|
// This is the general overload that takes a any string matcher
|
||||||
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
|
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
|
||||||
// the Equals matcher (so the header does not mention matchers)
|
// the Equals matcher (so the header does not mention matchers)
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
|
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
|
||||||
std::string exceptionMessage = Catch::translateActiveException();
|
std::string exceptionMessage = Catch::translateActiveException();
|
||||||
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
||||||
handler.handleExpr( expr );
|
handler.handleExpr( expr );
|
||||||
|
@@ -11,8 +11,10 @@
|
|||||||
#include "catch_capture.hpp"
|
#include "catch_capture.hpp"
|
||||||
#include "catch_matchers.h"
|
#include "catch_matchers.h"
|
||||||
#include "catch_matchers_floating.h"
|
#include "catch_matchers_floating.h"
|
||||||
|
#include "catch_matchers_generic.hpp"
|
||||||
#include "catch_matchers_string.h"
|
#include "catch_matchers_string.h"
|
||||||
#include "catch_matchers_vector.h"
|
#include "catch_matchers_vector.h"
|
||||||
|
#include "catch_stringref.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ namespace Catch {
|
|||||||
MatcherT m_matcher;
|
MatcherT m_matcher;
|
||||||
StringRef m_matcherString;
|
StringRef m_matcherString;
|
||||||
public:
|
public:
|
||||||
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
|
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
|
||||||
: ITransientExpression{ true, matcher.match( arg ) },
|
: ITransientExpression{ true, matcher.match( arg ) },
|
||||||
m_arg( arg ),
|
m_arg( arg ),
|
||||||
m_matcher( matcher ),
|
m_matcher( matcher ),
|
||||||
@@ -41,10 +43,10 @@ namespace Catch {
|
|||||||
|
|
||||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||||
|
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
|
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
|
||||||
|
|
||||||
template<typename ArgT, typename MatcherT>
|
template<typename ArgT, typename MatcherT>
|
||||||
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
||||||
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +56,9 @@ namespace Catch {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
|
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
|
||||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
} while( false )
|
} while( false )
|
||||||
@@ -65,14 +67,14 @@ namespace Catch {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
|
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__ ); \
|
static_cast<void>(__VA_ARGS__ ); \
|
||||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||||
} \
|
} \
|
||||||
catch( exceptionType const& ex ) { \
|
catch( exceptionType const& ex ) { \
|
||||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
|
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
|
||||||
} \
|
} \
|
||||||
catch( ... ) { \
|
catch( ... ) { \
|
||||||
catchAssertionHandler.handleUnexpectedInflightException(); \
|
catchAssertionHandler.handleUnexpectedInflightException(); \
|
||||||
|
@@ -130,7 +130,7 @@ namespace Catch {
|
|||||||
| Opt( config.outputFilename, "filename" )
|
| Opt( config.outputFilename, "filename" )
|
||||||
["-o"]["--out"]
|
["-o"]["--out"]
|
||||||
( "output filename" )
|
( "output filename" )
|
||||||
| Opt( config.reporterNames, "name" )
|
| Opt( config.reporterName, "name" )
|
||||||
["-r"]["--reporter"]
|
["-r"]["--reporter"]
|
||||||
( "reporter to use (defaults to console)" )
|
( "reporter to use (defaults to console)" )
|
||||||
| Opt( config.name, "name" )
|
| Opt( config.name, "name" )
|
||||||
|
@@ -22,7 +22,9 @@ namespace Catch {
|
|||||||
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
||||||
}
|
}
|
||||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
|
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
|
||||||
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
|
// We can assume that the same file will usually have the same pointer.
|
||||||
|
// Thus, if the pointers are the same, there is no point in calling the strcmp
|
||||||
|
return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
||||||
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
|
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
|
||||||
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
|
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
|
||||||
|
// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
|
||||||
// ****************
|
// ****************
|
||||||
// Note to maintainers: if new toggles are added please document them
|
// Note to maintainers: if new toggles are added please document them
|
||||||
// in configuration.md, too
|
// in configuration.md, too
|
||||||
@@ -24,14 +25,15 @@
|
|||||||
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
||||||
// can be combined, en-mass, with the _NO_ forms later.
|
// can be combined, en-mass, with the _NO_ forms later.
|
||||||
|
|
||||||
|
#include "catch_platform.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
# if __cplusplus >= 201402L
|
# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
|
||||||
# define CATCH_CPP14_OR_GREATER
|
# define CATCH_CPP14_OR_GREATER
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if __cplusplus >= 201703L
|
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
# define CATCH_CPP17_OR_GREATER
|
# define CATCH_CPP17_OR_GREATER
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@@ -56,6 +58,12 @@
|
|||||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||||
_Pragma( "clang diagnostic pop" )
|
_Pragma( "clang diagnostic pop" )
|
||||||
|
|
||||||
|
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||||
|
_Pragma( "clang diagnostic push" ) \
|
||||||
|
_Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
|
||||||
|
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
|
||||||
|
_Pragma( "clang diagnostic pop" )
|
||||||
|
|
||||||
#endif // __clang__
|
#endif // __clang__
|
||||||
|
|
||||||
|
|
||||||
@@ -76,6 +84,24 @@
|
|||||||
# define CATCH_CONFIG_COLOUR_NONE
|
# define CATCH_CONFIG_COLOUR_NONE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Android somehow still does not support std::to_string
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Not all Windows environments support SEH properly
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PS4
|
||||||
|
#if defined(__ORBIS__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Cygwin
|
// Cygwin
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
@@ -83,7 +109,14 @@
|
|||||||
// Required for some versions of Cygwin to declare gettimeofday
|
// Required for some versions of Cygwin to declare gettimeofday
|
||||||
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
|
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
|
||||||
# define _BSD_SOURCE
|
# define _BSD_SOURCE
|
||||||
|
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
|
||||||
|
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
|
||||||
|
&& !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
|
||||||
|
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
|
||||||
|
|
||||||
|
# endif
|
||||||
#endif // __CYGWIN__
|
#endif // __CYGWIN__
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -106,7 +139,12 @@
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if we are compiled with -fno-exceptions or equivalent
|
||||||
|
#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// DJGPP
|
// DJGPP
|
||||||
#ifdef __DJGPP__
|
#ifdef __DJGPP__
|
||||||
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
|
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
|
||||||
@@ -123,10 +161,37 @@
|
|||||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if string_view is available and usable
|
||||||
|
// The check is split apart to work around v140 (VS2015) preprocessor issue...
|
||||||
|
#if defined(__has_include)
|
||||||
|
#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if variant is available and usable
|
||||||
|
#if defined(__has_include)
|
||||||
|
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
# if defined(__clang__) && (__clang_major__ < 8)
|
||||||
|
// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
|
||||||
|
// fix should be in clang 8, workaround in libstdc++ 8.2
|
||||||
|
# include <ciso646>
|
||||||
|
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||||
|
# define CATCH_CONFIG_NO_CPP17_VARIANT
|
||||||
|
# else
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
|
||||||
|
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||||
|
# endif // defined(__clang__) && (__clang_major__ < 8)
|
||||||
|
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
#endif // __has_include
|
||||||
|
|
||||||
|
|
||||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||||
# define CATCH_CONFIG_COUNTER
|
# define CATCH_CONFIG_COUNTER
|
||||||
#endif
|
#endif
|
||||||
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
|
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
|
||||||
# define CATCH_CONFIG_WINDOWS_SEH
|
# define CATCH_CONFIG_WINDOWS_SEH
|
||||||
#endif
|
#endif
|
||||||
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
||||||
@@ -138,10 +203,33 @@
|
|||||||
# define CATCH_CONFIG_WCHAR
|
# define CATCH_CONFIG_WCHAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
|
||||||
|
# define CATCH_CONFIG_CPP11_TO_STRING
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
|
#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
|
||||||
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
|
||||||
|
# define CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||||
|
# define CATCH_CONFIG_CPP17_VARIANT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
# define CATCH_CONFIG_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
# define CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||||
@@ -151,6 +239,20 @@
|
|||||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||||
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
|
||||||
|
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
|
||||||
|
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
#define CATCH_TRY if ((true))
|
||||||
|
#define CATCH_CATCH_ALL if ((false))
|
||||||
|
#define CATCH_CATCH_ANON(type) if ((false))
|
||||||
|
#else
|
||||||
|
#define CATCH_TRY try
|
||||||
|
#define CATCH_CATCH_ALL catch (...)
|
||||||
|
#define CATCH_CATCH_ANON(type) catch (type)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||||
|
@@ -37,8 +37,8 @@ namespace Catch {
|
|||||||
bool Config::listReporters() const { return m_data.listReporters; }
|
bool Config::listReporters() const { return m_data.listReporters; }
|
||||||
|
|
||||||
std::string Config::getProcessName() const { return m_data.processName; }
|
std::string Config::getProcessName() const { return m_data.processName; }
|
||||||
|
std::string const& Config::getReporterName() const { return m_data.reporterName; }
|
||||||
|
|
||||||
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
|
|
||||||
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||||
|
|
||||||
|
@@ -54,8 +54,12 @@ namespace Catch {
|
|||||||
std::string outputFilename;
|
std::string outputFilename;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string processName;
|
std::string processName;
|
||||||
|
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
||||||
|
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
||||||
|
#endif
|
||||||
|
std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
|
||||||
|
#undef CATCH_CONFIG_DEFAULT_REPORTER
|
||||||
|
|
||||||
std::vector<std::string> reporterNames;
|
|
||||||
std::vector<std::string> testsOrTags;
|
std::vector<std::string> testsOrTags;
|
||||||
std::vector<std::string> sectionsToRun;
|
std::vector<std::string> sectionsToRun;
|
||||||
};
|
};
|
||||||
@@ -76,8 +80,8 @@ namespace Catch {
|
|||||||
bool listReporters() const;
|
bool listReporters() const;
|
||||||
|
|
||||||
std::string getProcessName() const;
|
std::string getProcessName() const;
|
||||||
|
std::string const& getReporterName() const;
|
||||||
|
|
||||||
std::vector<std::string> const& getReporterNames() const;
|
|
||||||
std::vector<std::string> const& getTestsOrTags() const;
|
std::vector<std::string> const& getTestsOrTags() const;
|
||||||
std::vector<std::string> const& getSectionsToRun() const override;
|
std::vector<std::string> const& getSectionsToRun() const override;
|
||||||
|
|
||||||
|
19
include/internal/catch_enforce.cpp
Normal file
19
include/internal/catch_enforce.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 03/09/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const& e) {
|
||||||
|
Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
|
||||||
|
<< "The message was: " << e.what() << '\n';
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Catch;
|
@@ -8,17 +8,35 @@
|
|||||||
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||||
|
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
template <typename Ex>
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(Ex const& e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const& e);
|
||||||
|
#endif
|
||||||
|
} // namespace Catch;
|
||||||
|
|
||||||
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
||||||
type( ( Catch::ReusableStringStream() << msg ).str() )
|
type( ( Catch::ReusableStringStream() << msg ).str() )
|
||||||
#define CATCH_INTERNAL_ERROR( msg ) \
|
#define CATCH_INTERNAL_ERROR( msg ) \
|
||||||
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
|
||||||
#define CATCH_ERROR( msg ) \
|
#define CATCH_ERROR( msg ) \
|
||||||
throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
|
||||||
|
#define CATCH_RUNTIME_ERROR( msg ) \
|
||||||
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
|
||||||
#define CATCH_ENFORCE( condition, msg ) \
|
#define CATCH_ENFORCE( condition, msg ) \
|
||||||
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
|
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
|
||||||
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||||
|
@@ -6,8 +6,10 @@
|
|||||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_assertionhandler.h"
|
|
||||||
#include "catch_exception_translator_registry.h"
|
#include "catch_exception_translator_registry.h"
|
||||||
|
#include "catch_assertionhandler.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
#import "Foundation/Foundation.h"
|
#import "Foundation/Foundation.h"
|
||||||
@@ -22,6 +24,7 @@ namespace Catch {
|
|||||||
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
|
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||||
try {
|
try {
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
@@ -64,6 +67,13 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||||
|
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||||
|
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||||
if( m_translators.empty() )
|
if( m_translators.empty() )
|
||||||
std::rethrow_exception(std::current_exception());
|
std::rethrow_exception(std::current_exception());
|
||||||
|
@@ -94,6 +94,11 @@ namespace Catch {
|
|||||||
int id;
|
int id;
|
||||||
const char* name;
|
const char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 32kb for the alternate stack seems to be sufficient. However, this value
|
||||||
|
// is experimentally determined, so that's not guaranteed.
|
||||||
|
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
|
||||||
|
|
||||||
static SignalDefs signalDefs[] = {
|
static SignalDefs signalDefs[] = {
|
||||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||||
@@ -121,7 +126,7 @@ namespace Catch {
|
|||||||
isSet = true;
|
isSet = true;
|
||||||
stack_t sigStack;
|
stack_t sigStack;
|
||||||
sigStack.ss_sp = altStackMem;
|
sigStack.ss_sp = altStackMem;
|
||||||
sigStack.ss_size = SIGSTKSZ;
|
sigStack.ss_size = sigStackSize;
|
||||||
sigStack.ss_flags = 0;
|
sigStack.ss_flags = 0;
|
||||||
sigaltstack(&sigStack, &oldSigStack);
|
sigaltstack(&sigStack, &oldSigStack);
|
||||||
struct sigaction sa = { };
|
struct sigaction sa = { };
|
||||||
@@ -153,7 +158,7 @@ namespace Catch {
|
|||||||
bool FatalConditionHandler::isSet = false;
|
bool FatalConditionHandler::isSet = false;
|
||||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||||
stack_t FatalConditionHandler::oldSigStack = {};
|
stack_t FatalConditionHandler::oldSigStack = {};
|
||||||
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
|
char FatalConditionHandler::altStackMem[sigStackSize] = {};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
50
include/internal/catch_generators.cpp
Normal file
50
include/internal/catch_generators.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_generators.hpp"
|
||||||
|
#include "catch_random_number_generator.h"
|
||||||
|
#include "catch_interfaces_capture.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
IGeneratorTracker::~IGeneratorTracker() {}
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
GeneratorBase::~GeneratorBase() {}
|
||||||
|
|
||||||
|
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
|
||||||
|
|
||||||
|
assert( selectionSize <= sourceSize );
|
||||||
|
std::vector<size_t> indices;
|
||||||
|
indices.reserve( selectionSize );
|
||||||
|
std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
|
||||||
|
|
||||||
|
std::set<size_t> seen;
|
||||||
|
// !TBD: improve this algorithm
|
||||||
|
while( indices.size() < selectionSize ) {
|
||||||
|
auto index = uid( rng() );
|
||||||
|
if( seen.insert( index ).second )
|
||||||
|
indices.push_back( index );
|
||||||
|
}
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||||
|
return getResultCapture().acquireGeneratorTracker( lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
auto all<int>() -> Generator<int> {
|
||||||
|
return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
253
include/internal/catch_generators.hpp
Normal file
253
include/internal/catch_generators.hpp
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_interfaces_generatortracker.h"
|
||||||
|
#include "catch_common.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
// !TBD move this into its own location?
|
||||||
|
namespace pf{
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique( Args&&... args ) {
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct IGenerator {
|
||||||
|
virtual ~IGenerator() {}
|
||||||
|
virtual auto get( size_t index ) const -> T = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class SingleValueGenerator : public IGenerator<T> {
|
||||||
|
T m_value;
|
||||||
|
public:
|
||||||
|
SingleValueGenerator( T const& value ) : m_value( value ) {}
|
||||||
|
|
||||||
|
auto get( size_t ) const -> T override {
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class FixedValuesGenerator : public IGenerator<T> {
|
||||||
|
std::vector<T> m_values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
return m_values[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class RangeGenerator : public IGenerator<T> {
|
||||||
|
T const m_first;
|
||||||
|
T const m_last;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
|
||||||
|
assert( m_last > m_first );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
// ToDo:: introduce a safe cast to catch potential overflows
|
||||||
|
return static_cast<T>(m_first+index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct NullGenerator : IGenerator<T> {
|
||||||
|
auto get( size_t ) const -> T override {
|
||||||
|
CATCH_INTERNAL_ERROR("A Null Generator is always empty");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Generator {
|
||||||
|
std::unique_ptr<IGenerator<T>> m_generator;
|
||||||
|
size_t m_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
|
||||||
|
: m_generator( std::move( generator ) ),
|
||||||
|
m_size( size )
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto size() const -> size_t { return m_size; }
|
||||||
|
auto operator[]( size_t index ) const -> T {
|
||||||
|
assert( index < m_size );
|
||||||
|
return m_generator->get( index );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class GeneratorRandomiser : public IGenerator<T> {
|
||||||
|
Generator<T> m_baseGenerator;
|
||||||
|
|
||||||
|
std::vector<size_t> m_indices;
|
||||||
|
public:
|
||||||
|
GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
|
||||||
|
: m_baseGenerator( std::move( baseGenerator ) ),
|
||||||
|
m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
return m_baseGenerator[m_indices[index]];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RequiresASpecialisationFor;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
auto all<int>() -> Generator<int>;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto range( T const& first, T const& last ) -> Generator<T> {
|
||||||
|
return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto random( T const& first, T const& last ) -> Generator<T> {
|
||||||
|
auto gen = range( first, last );
|
||||||
|
auto size = gen.size();
|
||||||
|
|
||||||
|
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto random( size_t size ) -> Generator<T> {
|
||||||
|
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto values( std::initializer_list<T> values ) -> Generator<T> {
|
||||||
|
return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto value( T const& val ) -> Generator<T> {
|
||||||
|
return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto as() -> Generator<T> {
|
||||||
|
return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
|
||||||
|
return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Generators : GeneratorBase {
|
||||||
|
std::vector<Generator<T>> m_generators;
|
||||||
|
|
||||||
|
using type = T;
|
||||||
|
|
||||||
|
Generators() : GeneratorBase( 0 ) {}
|
||||||
|
|
||||||
|
void populate( T&& val ) {
|
||||||
|
m_size += 1;
|
||||||
|
m_generators.emplace_back( value( std::move( val ) ) );
|
||||||
|
}
|
||||||
|
template<typename U>
|
||||||
|
void populate( U&& val ) {
|
||||||
|
populate( T( std::move( val ) ) );
|
||||||
|
}
|
||||||
|
void populate( Generator<T>&& generator ) {
|
||||||
|
m_size += generator.size();
|
||||||
|
m_generators.emplace_back( std::move( generator ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U, typename... Gs>
|
||||||
|
void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
|
||||||
|
populate( std::forward<U>( valueOrGenerator ) );
|
||||||
|
populate( std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator[]( size_t index ) const -> T {
|
||||||
|
size_t sizes = 0;
|
||||||
|
for( auto const& gen : m_generators ) {
|
||||||
|
auto localIndex = index-sizes;
|
||||||
|
sizes += gen.size();
|
||||||
|
if( index < sizes )
|
||||||
|
return gen[localIndex];
|
||||||
|
}
|
||||||
|
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
Generators<T> generators;
|
||||||
|
generators.m_generators.reserve( 1+sizeof...(Gs) );
|
||||||
|
generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
|
||||||
|
Generators<T> generators;
|
||||||
|
generators.populate( std::move( generator ) );
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
template<typename T, typename U, typename... Gs>
|
||||||
|
auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||||
|
// the expression used in the typedef inside, when it is in
|
||||||
|
// return type. Yeah, ¯\_(ツ)_/¯
|
||||||
|
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
|
||||||
|
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||||
|
|
||||||
|
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
||||||
|
if( !tracker.hasGenerator() )
|
||||||
|
tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
|
||||||
|
|
||||||
|
auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
|
||||||
|
return generator[tracker.getIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#define GENERATE( ... ) \
|
||||||
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
@@ -24,8 +24,10 @@ namespace Catch {
|
|||||||
struct BenchmarkInfo;
|
struct BenchmarkInfo;
|
||||||
struct BenchmarkStats;
|
struct BenchmarkStats;
|
||||||
struct AssertionReaction;
|
struct AssertionReaction;
|
||||||
|
struct SourceLineInfo;
|
||||||
|
|
||||||
struct ITransientExpression;
|
struct ITransientExpression;
|
||||||
|
struct IGeneratorTracker;
|
||||||
|
|
||||||
struct IResultCapture {
|
struct IResultCapture {
|
||||||
|
|
||||||
@@ -36,6 +38,8 @@ 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 void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||||
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
|
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
|
||||||
|
|
||||||
|
39
include/internal/catch_interfaces_generatortracker.h
Normal file
39
include/internal/catch_interfaces_generatortracker.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 26/6/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
class GeneratorBase {
|
||||||
|
protected:
|
||||||
|
size_t m_size = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneratorBase( size_t size ) : m_size( size ) {}
|
||||||
|
virtual ~GeneratorBase();
|
||||||
|
auto size() const -> size_t { return m_size; }
|
||||||
|
};
|
||||||
|
using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
|
||||||
|
struct IGeneratorTracker {
|
||||||
|
virtual ~IGeneratorTracker();
|
||||||
|
virtual auto hasGenerator() const -> bool = 0;
|
||||||
|
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||||
|
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||||
|
virtual auto getIndex() const -> std::size_t = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif //TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
@@ -33,7 +33,7 @@ namespace Catch {
|
|||||||
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
||||||
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
||||||
|
|
||||||
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
|
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
||||||
@@ -49,7 +49,7 @@ namespace Catch {
|
|||||||
virtual void registerStartupException() noexcept = 0;
|
virtual void registerStartupException() noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
IRegistryHub& getRegistryHub();
|
IRegistryHub const& getRegistryHub();
|
||||||
IMutableRegistryHub& getMutableRegistryHub();
|
IMutableRegistryHub& getMutableRegistryHub();
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
std::string translateActiveException();
|
std::string translateActiveException();
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_interfaces_reporter.h"
|
#include "catch_interfaces_reporter.h"
|
||||||
#include "../reporters/catch_reporter_multi.h"
|
#include "../reporters/catch_reporter_listening.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -111,25 +111,4 @@ namespace Catch {
|
|||||||
IReporterFactory::~IReporterFactory() = default;
|
IReporterFactory::~IReporterFactory() = default;
|
||||||
IReporterRegistry::~IReporterRegistry() = default;
|
IReporterRegistry::~IReporterRegistry() = default;
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
|
|
||||||
|
|
||||||
if( !existingReporter ) {
|
|
||||||
existingReporter = std::move( additionalReporter );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultipleReporters* multi = nullptr;
|
|
||||||
|
|
||||||
if( existingReporter->isMulti() ) {
|
|
||||||
multi = static_cast<MultipleReporters*>( existingReporter.get() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
|
|
||||||
newMulti->add( std::move( existingReporter ) );
|
|
||||||
multi = newMulti.get();
|
|
||||||
existingReporter = std::move( newMulti );
|
|
||||||
}
|
|
||||||
multi->add( std::move( additionalReporter ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -42,6 +42,7 @@ namespace Catch {
|
|||||||
|
|
||||||
struct ReporterPreferences {
|
struct ReporterPreferences {
|
||||||
bool shouldRedirectStdOut = false;
|
bool shouldRedirectStdOut = false;
|
||||||
|
bool shouldReportAllAssertions = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -226,8 +227,6 @@ namespace Catch {
|
|||||||
virtual Listeners const& getListeners() const = 0;
|
virtual Listeners const& getListeners() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||||
|
@@ -13,16 +13,16 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
LeakDetector::LeakDetector() {
|
LeakDetector::LeakDetector() {
|
||||||
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||||
flag |= _CRTDBG_LEAK_CHECK_DF;
|
flag |= _CRTDBG_LEAK_CHECK_DF;
|
||||||
flag |= _CRTDBG_ALLOC_MEM_DF;
|
flag |= _CRTDBG_ALLOC_MEM_DF;
|
||||||
_CrtSetDbgFlag(flag);
|
_CrtSetDbgFlag(flag);
|
||||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
||||||
// Change this to leaking allocation's number to break there
|
// Change this to leaking allocation's number to break there
|
||||||
_CrtSetBreakAlloc(-1);
|
_CrtSetBreakAlloc(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@@ -34,6 +34,11 @@ namespace Matchers {
|
|||||||
mutable std::string m_cachedToString;
|
mutable std::string m_cachedToString;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename ObjectT>
|
template<typename ObjectT>
|
||||||
struct MatcherMethod {
|
struct MatcherMethod {
|
||||||
virtual bool match( ObjectT const& arg ) const = 0;
|
virtual bool match( ObjectT const& arg ) const = 0;
|
||||||
@@ -43,6 +48,10 @@ namespace Matchers {
|
|||||||
virtual bool match( PtrT* arg ) const = 0;
|
virtual bool match( PtrT* arg ) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
|
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
|
||||||
|
|
||||||
|
@@ -6,12 +6,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_matchers_floating.h"
|
#include "catch_matchers_floating.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
#include "catch_to_string.hpp"
|
||||||
#include "catch_tostring.h"
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Matchers {
|
namespace Matchers {
|
||||||
@@ -80,15 +81,14 @@ namespace Matchers {
|
|||||||
namespace Floating {
|
namespace Floating {
|
||||||
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
|
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
|
||||||
:m_target{ target }, m_margin{ margin } {
|
:m_target{ target }, m_margin{ margin } {
|
||||||
if (m_margin < 0) {
|
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
|
||||||
throw std::domain_error("Allowed margin difference has to be >= 0");
|
<< " Margin has to be non-negative.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||||
// But without the subtraction to allow for INFINITY in comparison
|
// But without the subtraction to allow for INFINITY in comparison
|
||||||
bool WithinAbsMatcher::match(double const& matchee) const {
|
bool WithinAbsMatcher::match(double const& matchee) const {
|
||||||
return (matchee + m_margin >= m_target) && (m_target + m_margin >= m_margin);
|
return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WithinAbsMatcher::describe() const {
|
std::string WithinAbsMatcher::describe() const {
|
||||||
@@ -98,11 +98,16 @@ namespace Floating {
|
|||||||
|
|
||||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
||||||
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||||
if (m_ulps < 0) {
|
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
|
||||||
throw std::domain_error("Allowed ulp difference has to be >= 0");
|
<< " ULPs have to be non-negative.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
// Clang <3.5 reports on the default branch in the switch below
|
||||||
|
#pragma clang diagnostic ignored "-Wunreachable-code"
|
||||||
|
#endif
|
||||||
|
|
||||||
bool WithinUlpsMatcher::match(double const& matchee) const {
|
bool WithinUlpsMatcher::match(double const& matchee) const {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case FloatingPointKind::Float:
|
case FloatingPointKind::Float:
|
||||||
@@ -110,12 +115,16 @@ namespace Floating {
|
|||||||
case FloatingPointKind::Double:
|
case FloatingPointKind::Double:
|
||||||
return almostEqualUlps<double>(matchee, m_target, m_ulps);
|
return almostEqualUlps<double>(matchee, m_target, m_ulps);
|
||||||
default:
|
default:
|
||||||
throw std::domain_error("Unknown FloatingPointKind value");
|
CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string WithinUlpsMatcher::describe() const {
|
std::string WithinUlpsMatcher::describe() const {
|
||||||
return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
|
return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace Floating
|
}// namespace Floating
|
||||||
|
9
include/internal/catch_matchers_generic.cpp
Normal file
9
include/internal/catch_matchers_generic.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "catch_matchers_generic.hpp"
|
||||||
|
|
||||||
|
std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
|
||||||
|
if (desc.empty()) {
|
||||||
|
return "matches undescribed predicate";
|
||||||
|
} else {
|
||||||
|
return "matches predicate: \"" + desc + '"';
|
||||||
|
}
|
||||||
|
}
|
58
include/internal/catch_matchers_generic.hpp
Normal file
58
include/internal/catch_matchers_generic.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin Hořeňovský on 03/04/2017.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_common.h"
|
||||||
|
#include "catch_matchers.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Matchers {
|
||||||
|
namespace Generic {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
std::string finalizeDescription(const std::string& desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class PredicateMatcher : public MatcherBase<T> {
|
||||||
|
std::function<bool(T const&)> m_predicate;
|
||||||
|
std::string m_description;
|
||||||
|
public:
|
||||||
|
|
||||||
|
PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
|
||||||
|
:m_predicate(std::move(elem)),
|
||||||
|
m_description(Detail::finalizeDescription(descr))
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool match( T const& item ) const override {
|
||||||
|
return m_predicate(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string describe() const override {
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Generic
|
||||||
|
|
||||||
|
// The following functions create the actual matcher objects.
|
||||||
|
// The user has to explicitly specify type to the function, because
|
||||||
|
// infering std::function<bool(T const&)> is hard (but possible) and
|
||||||
|
// requires a lot of TMP.
|
||||||
|
template<typename T>
|
||||||
|
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
|
||||||
|
return Generic::PredicateMatcher<T>(predicate, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Matchers
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
@@ -124,7 +124,7 @@ namespace Matchers {
|
|||||||
auto lfirst = m_target.begin(), llast = m_target.end();
|
auto lfirst = m_target.begin(), llast = m_target.end();
|
||||||
auto rfirst = vec.begin(), rlast = vec.end();
|
auto rfirst = vec.begin(), rlast = vec.end();
|
||||||
// Cut common prefix to optimize checking of permuted parts
|
// Cut common prefix to optimize checking of permuted parts
|
||||||
while (lfirst != llast && *lfirst != *rfirst) {
|
while (lfirst != llast && *lfirst == *rfirst) {
|
||||||
++lfirst; ++rfirst;
|
++lfirst; ++rfirst;
|
||||||
}
|
}
|
||||||
if (lfirst == llast) {
|
if (lfirst == llast) {
|
||||||
|
@@ -10,9 +10,11 @@
|
|||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
#include "catch_uncaught_exceptions.h"
|
#include "catch_uncaught_exceptions.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
MessageInfo::MessageInfo( std::string const& _macroName,
|
MessageInfo::MessageInfo( StringRef const& _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
ResultWas::OfType _type )
|
ResultWas::OfType _type )
|
||||||
: macroName( _macroName ),
|
: macroName( _macroName ),
|
||||||
@@ -35,7 +37,7 @@ namespace Catch {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Catch::MessageBuilder::MessageBuilder( std::string const& macroName,
|
Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
ResultWas::OfType type )
|
ResultWas::OfType type )
|
||||||
:m_info(macroName, lineInfo, type) {}
|
:m_info(macroName, lineInfo, type) {}
|
||||||
@@ -55,4 +57,36 @@ namespace Catch {
|
|||||||
getResultCapture().popScopedMessage(m_info);
|
getResultCapture().popScopedMessage(m_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
|
||||||
|
auto start = std::string::npos;
|
||||||
|
for( size_t pos = 0; pos <= names.size(); ++pos ) {
|
||||||
|
char c = names[pos];
|
||||||
|
if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) {
|
||||||
|
if( start != std::string::npos ) {
|
||||||
|
m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) );
|
||||||
|
m_messages.back().message = names.substr( start, pos-start) + " := ";
|
||||||
|
start = std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( c != '[' && c != ']' && start == std::string::npos )
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Capturer::~Capturer() {
|
||||||
|
if ( !uncaught_exceptions() ){
|
||||||
|
assert( m_captured == m_messages.size() );
|
||||||
|
for( size_t i = 0; i < m_captured; ++i )
|
||||||
|
m_resultCapture.popScopedMessage( m_messages[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Capturer::captureValue( size_t index, StringRef value ) {
|
||||||
|
assert( index < m_messages.size() );
|
||||||
|
m_messages[index].message += value;
|
||||||
|
m_resultCapture.pushScopedMessage( m_messages[index] );
|
||||||
|
m_captured++;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -8,19 +8,23 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "catch_result_type.h"
|
#include "catch_result_type.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
|
#include "catch_interfaces_capture.h"
|
||||||
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct MessageInfo {
|
struct MessageInfo {
|
||||||
MessageInfo( std::string const& _macroName,
|
MessageInfo( StringRef const& _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
ResultWas::OfType _type );
|
ResultWas::OfType _type );
|
||||||
|
|
||||||
std::string macroName;
|
StringRef macroName;
|
||||||
std::string message;
|
std::string message;
|
||||||
SourceLineInfo lineInfo;
|
SourceLineInfo lineInfo;
|
||||||
ResultWas::OfType type;
|
ResultWas::OfType type;
|
||||||
@@ -44,7 +48,7 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MessageBuilder : MessageStream {
|
struct MessageBuilder : MessageStream {
|
||||||
MessageBuilder( std::string const& macroName,
|
MessageBuilder( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
ResultWas::OfType type );
|
ResultWas::OfType type );
|
||||||
|
|
||||||
@@ -65,6 +69,28 @@ namespace Catch {
|
|||||||
MessageInfo m_info;
|
MessageInfo m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Capturer {
|
||||||
|
std::vector<MessageInfo> m_messages;
|
||||||
|
IResultCapture& m_resultCapture = getResultCapture();
|
||||||
|
size_t m_captured = 0;
|
||||||
|
public:
|
||||||
|
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||||
|
~Capturer();
|
||||||
|
|
||||||
|
void captureValue( size_t index, StringRef value );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void captureValues( size_t index, T&& value ) {
|
||||||
|
captureValue( index, Catch::Detail::stringify( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Ts>
|
||||||
|
void captureValues( size_t index, T&& value, Ts&&... values ) {
|
||||||
|
captureValues( index, value );
|
||||||
|
captureValues( index+1, values... );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
|
@@ -93,7 +93,7 @@ namespace Catch {
|
|||||||
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
||||||
const char* className = class_getName( cls );
|
const char* className = class_getName( cls );
|
||||||
|
|
||||||
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) );
|
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
|
||||||
noTestMethods++;
|
noTestMethods++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
138
include/internal/catch_output_redirect.cpp
Normal file
138
include/internal/catch_output_redirect.cpp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 28/04/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_output_redirect.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <io.h> //_dup and _dup2
|
||||||
|
#define dup _dup
|
||||||
|
#define dup2 _dup2
|
||||||
|
#define fileno _fileno
|
||||||
|
#else
|
||||||
|
#include <unistd.h> // dup and dup2
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
|
||||||
|
: m_originalStream( originalStream ),
|
||||||
|
m_redirectionStream( redirectionStream ),
|
||||||
|
m_prevBuf( m_originalStream.rdbuf() )
|
||||||
|
{
|
||||||
|
m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectedStream::~RedirectedStream() {
|
||||||
|
m_originalStream.rdbuf( m_prevBuf );
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
|
||||||
|
auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
|
||||||
|
|
||||||
|
RedirectedStdErr::RedirectedStdErr()
|
||||||
|
: m_cerr( Catch::cerr(), m_rss.get() ),
|
||||||
|
m_clog( Catch::clog(), m_rss.get() )
|
||||||
|
{}
|
||||||
|
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
TempFile::TempFile() {
|
||||||
|
if (tmpnam_s(m_buffer)) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not get a temp filename");
|
||||||
|
}
|
||||||
|
if (fopen_s(&m_file, m_buffer, "w")) {
|
||||||
|
char buffer[100];
|
||||||
|
if (strerror_s(buffer, errno)) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
|
||||||
|
}
|
||||||
|
CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
TempFile::TempFile() {
|
||||||
|
m_file = std::tmpfile();
|
||||||
|
if (!m_file) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not create a temp file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TempFile::~TempFile() {
|
||||||
|
// TBD: What to do about errors here?
|
||||||
|
std::fclose(m_file);
|
||||||
|
// We manually create the file on Windows only, on Linux
|
||||||
|
// it will be autodeleted
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
std::remove(m_buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FILE* TempFile::getFile() {
|
||||||
|
return m_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TempFile::getContents() {
|
||||||
|
std::stringstream sstr;
|
||||||
|
char buffer[100] = {};
|
||||||
|
std::rewind(m_file);
|
||||||
|
while (std::fgets(buffer, sizeof(buffer), m_file)) {
|
||||||
|
sstr << buffer;
|
||||||
|
}
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
|
||||||
|
m_originalStdout(dup(1)),
|
||||||
|
m_originalStderr(dup(2)),
|
||||||
|
m_stdoutDest(stdout_dest),
|
||||||
|
m_stderrDest(stderr_dest) {
|
||||||
|
dup2(fileno(m_stdoutFile.getFile()), 1);
|
||||||
|
dup2(fileno(m_stderrFile.getFile()), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputRedirect::~OutputRedirect() {
|
||||||
|
Catch::cout() << std::flush;
|
||||||
|
fflush(stdout);
|
||||||
|
// Since we support overriding these streams, we flush cerr
|
||||||
|
// even though std::cerr is unbuffered
|
||||||
|
Catch::cerr() << std::flush;
|
||||||
|
Catch::clog() << std::flush;
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
dup2(m_originalStdout, 1);
|
||||||
|
dup2(m_originalStderr, 2);
|
||||||
|
|
||||||
|
m_stdoutDest += m_stdoutFile.getContents();
|
||||||
|
m_stderrDest += m_stderrFile.getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_CONFIG_NEW_CAPTURE
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#undef dup
|
||||||
|
#undef dup2
|
||||||
|
#undef fileno
|
||||||
|
#endif
|
||||||
|
#endif
|
101
include/internal/catch_output_redirect.h
Normal file
101
include/internal/catch_output_redirect.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 28/04/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
||||||
|
#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
||||||
|
|
||||||
|
#include "catch_platform.h"
|
||||||
|
#include "catch_stream.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class RedirectedStream {
|
||||||
|
std::ostream& m_originalStream;
|
||||||
|
std::ostream& m_redirectionStream;
|
||||||
|
std::streambuf* m_prevBuf;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
|
||||||
|
~RedirectedStream();
|
||||||
|
};
|
||||||
|
|
||||||
|
class RedirectedStdOut {
|
||||||
|
ReusableStringStream m_rss;
|
||||||
|
RedirectedStream m_cout;
|
||||||
|
public:
|
||||||
|
RedirectedStdOut();
|
||||||
|
auto str() const -> std::string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// StdErr has two constituent streams in C++, std::cerr and std::clog
|
||||||
|
// This means that we need to redirect 2 streams into 1 to keep proper
|
||||||
|
// order of writes
|
||||||
|
class RedirectedStdErr {
|
||||||
|
ReusableStringStream m_rss;
|
||||||
|
RedirectedStream m_cerr;
|
||||||
|
RedirectedStream m_clog;
|
||||||
|
public:
|
||||||
|
RedirectedStdErr();
|
||||||
|
auto str() const -> std::string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
|
||||||
|
// Windows's implementation of std::tmpfile is terrible (it tries
|
||||||
|
// to create a file inside system folder, thus requiring elevated
|
||||||
|
// privileges for the binary), so we have to use tmpnam(_s) and
|
||||||
|
// create the file ourselves there.
|
||||||
|
class TempFile {
|
||||||
|
public:
|
||||||
|
TempFile(TempFile const&) = delete;
|
||||||
|
TempFile& operator=(TempFile const&) = delete;
|
||||||
|
TempFile(TempFile&&) = delete;
|
||||||
|
TempFile& operator=(TempFile&&) = delete;
|
||||||
|
|
||||||
|
TempFile();
|
||||||
|
~TempFile();
|
||||||
|
|
||||||
|
std::FILE* getFile();
|
||||||
|
std::string getContents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::FILE* m_file = nullptr;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
char m_buffer[L_tmpnam] = { 0 };
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OutputRedirect {
|
||||||
|
public:
|
||||||
|
OutputRedirect(OutputRedirect const&) = delete;
|
||||||
|
OutputRedirect& operator=(OutputRedirect const&) = delete;
|
||||||
|
OutputRedirect(OutputRedirect&&) = delete;
|
||||||
|
OutputRedirect& operator=(OutputRedirect&&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
|
||||||
|
~OutputRedirect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_originalStdout = -1;
|
||||||
|
int m_originalStderr = -1;
|
||||||
|
TempFile m_stdoutFile;
|
||||||
|
TempFile m_stderrFile;
|
||||||
|
std::string& m_stdoutDest;
|
||||||
|
std::string& m_stderrDest;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
@@ -20,7 +20,7 @@
|
|||||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
# define CATCH_PLATFORM_LINUX
|
# define CATCH_PLATFORM_LINUX
|
||||||
|
|
||||||
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
# define CATCH_PLATFORM_WINDOWS
|
# define CATCH_PLATFORM_WINDOWS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -9,23 +9,21 @@
|
|||||||
#include "catch_context.h"
|
#include "catch_context.h"
|
||||||
#include "catch_interfaces_config.h"
|
#include "catch_interfaces_config.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
void seedRng( IConfig const& config ) {
|
std::mt19937& rng() {
|
||||||
if( config.rngSeed() != 0 )
|
static std::mt19937 s_rng;
|
||||||
std::srand( config.rngSeed() );
|
return s_rng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void seedRng( IConfig const& config ) {
|
||||||
|
if( config.rngSeed() != 0 ) {
|
||||||
|
std::srand( config.rngSeed() );
|
||||||
|
rng().seed( config.rngSeed() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int rngSeed() {
|
unsigned int rngSeed() {
|
||||||
return getCurrentContext().getConfig()->rngSeed();
|
return getCurrentContext().getConfig()->rngSeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const {
|
|
||||||
return std::rand() % n;
|
|
||||||
}
|
|
||||||
RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const {
|
|
||||||
return std::rand() % (max)();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,31 +8,16 @@
|
|||||||
#define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct IConfig;
|
struct IConfig;
|
||||||
|
|
||||||
|
std::mt19937& rng();
|
||||||
void seedRng( IConfig const& config );
|
void seedRng( IConfig const& config );
|
||||||
|
|
||||||
unsigned int rngSeed();
|
unsigned int rngSeed();
|
||||||
|
|
||||||
struct RandomNumberGenerator {
|
|
||||||
using result_type = unsigned int;
|
|
||||||
|
|
||||||
static constexpr result_type (min)() { return 0; }
|
|
||||||
static constexpr result_type (max)() { return 1000000; }
|
|
||||||
|
|
||||||
result_type operator()( result_type n ) const;
|
|
||||||
result_type operator()() const;
|
|
||||||
|
|
||||||
template<typename V>
|
|
||||||
static void shuffle( V& vector ) {
|
|
||||||
RandomNumberGenerator rng;
|
|
||||||
std::shuffle( vector.begin(), vector.end(), rng );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "catch_exception_translator_registry.h"
|
#include "catch_exception_translator_registry.h"
|
||||||
#include "catch_tag_alias_registry.h"
|
#include "catch_tag_alias_registry.h"
|
||||||
#include "catch_startup_exception_registry.h"
|
#include "catch_startup_exception_registry.h"
|
||||||
|
#include "catch_singletons.hpp"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ namespace Catch {
|
|||||||
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
ITestCaseRegistry const& getTestCaseRegistry() const override {
|
||||||
return m_testCaseRegistry;
|
return m_testCaseRegistry;
|
||||||
}
|
}
|
||||||
IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override {
|
IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
|
||||||
return m_exceptionTranslatorRegistry;
|
return m_exceptionTranslatorRegistry;
|
||||||
}
|
}
|
||||||
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
ITagAliasRegistry const& getTagAliasRegistry() const override {
|
||||||
@@ -67,27 +68,19 @@ namespace Catch {
|
|||||||
TagAliasRegistry m_tagAliasRegistry;
|
TagAliasRegistry m_tagAliasRegistry;
|
||||||
StartupExceptionRegistry m_exceptionRegistry;
|
StartupExceptionRegistry m_exceptionRegistry;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single, global, instance
|
|
||||||
RegistryHub*& getTheRegistryHub() {
|
|
||||||
static RegistryHub* theRegistryHub = nullptr;
|
|
||||||
if( !theRegistryHub )
|
|
||||||
theRegistryHub = new RegistryHub();
|
|
||||||
return theRegistryHub;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IRegistryHub& getRegistryHub() {
|
using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
|
||||||
return *getTheRegistryHub();
|
|
||||||
|
IRegistryHub const& getRegistryHub() {
|
||||||
|
return RegistryHubSingleton::get();
|
||||||
}
|
}
|
||||||
IMutableRegistryHub& getMutableRegistryHub() {
|
IMutableRegistryHub& getMutableRegistryHub() {
|
||||||
return *getTheRegistryHub();
|
return RegistryHubSingleton::getMutable();
|
||||||
}
|
}
|
||||||
void cleanUp() {
|
void cleanUp() {
|
||||||
delete getTheRegistryHub();
|
cleanupSingletons();
|
||||||
getTheRegistryHub() = nullptr;
|
|
||||||
cleanUpContext();
|
cleanUpContext();
|
||||||
ReusableStringStream::cleanup();
|
|
||||||
}
|
}
|
||||||
std::string translateActiveException() {
|
std::string translateActiveException() {
|
||||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
#include "catch_run_context.h"
|
#include "catch_run_context.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
#include "catch_context.h"
|
#include "catch_context.h"
|
||||||
#include "catch_enforce.h"
|
#include "catch_enforce.h"
|
||||||
#include "catch_random_number_generator.h"
|
#include "catch_random_number_generator.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
|
#include "catch_output_redirect.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -10,46 +12,68 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
class RedirectedStream {
|
namespace Generators {
|
||||||
std::ostream& m_originalStream;
|
struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
|
||||||
std::ostream& m_redirectionStream;
|
size_t m_index = static_cast<size_t>( -1 );
|
||||||
std::streambuf* m_prevBuf;
|
GeneratorBasePtr m_generator;
|
||||||
|
|
||||||
public:
|
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||||
RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
|
: TrackerBase( nameAndLocation, ctx, parent )
|
||||||
: m_originalStream( originalStream ),
|
{}
|
||||||
m_redirectionStream( redirectionStream ),
|
~GeneratorTracker();
|
||||||
m_prevBuf( m_originalStream.rdbuf() )
|
|
||||||
{
|
|
||||||
m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
|
|
||||||
}
|
|
||||||
~RedirectedStream() {
|
|
||||||
m_originalStream.rdbuf( m_prevBuf );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RedirectedStdOut {
|
static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
|
||||||
ReusableStringStream m_rss;
|
std::shared_ptr<GeneratorTracker> tracker;
|
||||||
RedirectedStream m_cout;
|
|
||||||
public:
|
|
||||||
RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
|
|
||||||
auto str() const -> std::string { return m_rss.str(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// StdErr has two constituent streams in C++, std::cerr and std::clog
|
ITracker& currentTracker = ctx.currentTracker();
|
||||||
// This means that we need to redirect 2 streams into 1 to keep proper
|
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||||
// order of writes
|
assert( childTracker );
|
||||||
class RedirectedStdErr {
|
assert( childTracker->isIndexTracker() );
|
||||||
ReusableStringStream m_rss;
|
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
||||||
RedirectedStream m_cerr;
|
}
|
||||||
RedirectedStream m_clog;
|
else {
|
||||||
public:
|
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );
|
||||||
RedirectedStdErr()
|
currentTracker.addChild( tracker );
|
||||||
: m_cerr( Catch::cerr(), m_rss.get() ),
|
}
|
||||||
m_clog( Catch::clog(), m_rss.get() )
|
|
||||||
{}
|
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||||
auto str() const -> std::string { return m_rss.str(); }
|
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||||
};
|
tracker->moveNext();
|
||||||
|
tracker->open();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *tracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveNext() {
|
||||||
|
m_index++;
|
||||||
|
m_children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackerBase interface
|
||||||
|
bool isIndexTracker() const override { return true; }
|
||||||
|
auto hasGenerator() const -> bool override {
|
||||||
|
return !!m_generator;
|
||||||
|
}
|
||||||
|
void close() override {
|
||||||
|
TrackerBase::close();
|
||||||
|
if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 )
|
||||||
|
m_runState = Executing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IGeneratorTracker interface
|
||||||
|
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||||
|
return m_generator;
|
||||||
|
}
|
||||||
|
void setGenerator( GeneratorBasePtr&& generator ) override {
|
||||||
|
m_generator = std::move( generator );
|
||||||
|
}
|
||||||
|
auto getIndex() const -> size_t override {
|
||||||
|
return m_index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GeneratorTracker::~GeneratorTracker() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
||||||
@@ -58,7 +82,7 @@ namespace Catch {
|
|||||||
m_config(_config),
|
m_config(_config),
|
||||||
m_reporter(std::move(reporter)),
|
m_reporter(std::move(reporter)),
|
||||||
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
||||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() )
|
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
|
||||||
{
|
{
|
||||||
m_context.setRunner(this);
|
m_context.setRunner(this);
|
||||||
m_context.setConfig(m_config);
|
m_context.setConfig(m_config);
|
||||||
@@ -169,6 +193,13 @@ namespace Catch {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||||
|
using namespace Generators;
|
||||||
|
GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
|
||||||
|
assert( tracker.isOpen() );
|
||||||
|
m_lastAssertionInfo.lineInfo = lineInfo;
|
||||||
|
return tracker;
|
||||||
|
}
|
||||||
|
|
||||||
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
||||||
if (assertions.total() != 0)
|
if (assertions.total() != 0)
|
||||||
@@ -249,7 +280,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// Recreate section for test case (as we will lose the one that was in scope)
|
// Recreate section for test case (as we will lose the one that was in scope)
|
||||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
|
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||||
|
|
||||||
Counts assertions;
|
Counts assertions;
|
||||||
assertions.failed = 1;
|
assertions.failed = 1;
|
||||||
@@ -282,12 +313,12 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool RunContext::aborting() const {
|
bool RunContext::aborting() const {
|
||||||
return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
|
return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
|
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
|
||||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
|
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||||
m_reporter->sectionStarting(testCaseSection);
|
m_reporter->sectionStarting(testCaseSection);
|
||||||
Counts prevAssertions = m_totals.assertions;
|
Counts prevAssertions = m_totals.assertions;
|
||||||
double duration = 0;
|
double duration = 0;
|
||||||
@@ -297,23 +328,29 @@ namespace Catch {
|
|||||||
seedRng(*m_config);
|
seedRng(*m_config);
|
||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
try {
|
CATCH_TRY {
|
||||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
||||||
|
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||||
RedirectedStdOut redirectedStdOut;
|
RedirectedStdOut redirectedStdOut;
|
||||||
RedirectedStdErr redirectedStdErr;
|
RedirectedStdErr redirectedStdErr;
|
||||||
|
|
||||||
timer.start();
|
timer.start();
|
||||||
invokeActiveTestCase();
|
invokeActiveTestCase();
|
||||||
redirectedCout += redirectedStdOut.str();
|
redirectedCout += redirectedStdOut.str();
|
||||||
redirectedCerr += redirectedStdErr.str();
|
redirectedCerr += redirectedStdErr.str();
|
||||||
|
#else
|
||||||
|
OutputRedirect r(redirectedCout, redirectedCerr);
|
||||||
|
timer.start();
|
||||||
|
invokeActiveTestCase();
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
timer.start();
|
timer.start();
|
||||||
invokeActiveTestCase();
|
invokeActiveTestCase();
|
||||||
}
|
}
|
||||||
duration = timer.getElapsedSeconds();
|
duration = timer.getElapsedSeconds();
|
||||||
} catch (TestFailureException&) {
|
} CATCH_CATCH_ANON (TestFailureException&) {
|
||||||
// This just means the test was aborted due to failure
|
// This just means the test was aborted due to failure
|
||||||
} catch (...) {
|
} CATCH_CATCH_ALL {
|
||||||
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
|
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
|
||||||
// are reported without translation at the point of origin.
|
// are reported without translation at the point of origin.
|
||||||
if( m_shouldReportUnexpected ) {
|
if( m_shouldReportUnexpected ) {
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_interfaces_generatortracker.h"
|
||||||
#include "catch_interfaces_runner.h"
|
#include "catch_interfaces_runner.h"
|
||||||
#include "catch_interfaces_reporter.h"
|
#include "catch_interfaces_reporter.h"
|
||||||
#include "catch_interfaces_exception.h"
|
#include "catch_interfaces_exception.h"
|
||||||
@@ -79,6 +80,8 @@ 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;
|
||||||
|
|
||||||
void benchmarkStarting( BenchmarkInfo const& info ) override;
|
void benchmarkStarting( BenchmarkInfo const& info ) override;
|
||||||
void benchmarkEnded( BenchmarkStats const& stats ) override;
|
void benchmarkEnded( BenchmarkStats const& stats ) override;
|
||||||
|
|
||||||
@@ -99,7 +102,7 @@ namespace Catch {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// !TBD We need to do this another way!
|
// !TBD We need to do this another way!
|
||||||
bool aborting() const override;
|
bool aborting() const final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@@ -21,7 +21,7 @@ namespace Catch {
|
|||||||
|
|
||||||
Section::~Section() {
|
Section::~Section() {
|
||||||
if( m_sectionIncluded ) {
|
if( m_sectionIncluded ) {
|
||||||
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
|
||||||
if( uncaught_exceptions() )
|
if( uncaught_exceptions() )
|
||||||
getResultCapture().sectionEndedEarly( endInfo );
|
getResultCapture().sectionEndedEarly( endInfo );
|
||||||
else
|
else
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
#include "catch_section_info.h"
|
#include "catch_section_info.h"
|
||||||
#include "catch_totals.h"
|
#include "catch_totals.h"
|
||||||
#include "catch_timer.h"
|
#include "catch_timer.h"
|
||||||
@@ -35,7 +36,14 @@ namespace Catch {
|
|||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#define INTERNAL_CATCH_SECTION( ... ) \
|
#define INTERNAL_CATCH_SECTION( ... ) \
|
||||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
|
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||||
|
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
|
||||||
|
CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||||
|
|
||||||
|
#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
|
||||||
|
CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||||
|
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
|
||||||
|
CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||||
|
@@ -11,15 +11,9 @@ namespace Catch {
|
|||||||
|
|
||||||
SectionInfo::SectionInfo
|
SectionInfo::SectionInfo
|
||||||
( SourceLineInfo const& _lineInfo,
|
( SourceLineInfo const& _lineInfo,
|
||||||
std::string const& _name,
|
std::string const& _name )
|
||||||
std::string const& _description )
|
|
||||||
: name( _name ),
|
: name( _name ),
|
||||||
description( _description ),
|
|
||||||
lineInfo( _lineInfo )
|
lineInfo( _lineInfo )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
|
|
||||||
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
|
||||||
{}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -16,19 +16,22 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct SectionInfo {
|
struct SectionInfo {
|
||||||
|
SectionInfo
|
||||||
|
( SourceLineInfo const& _lineInfo,
|
||||||
|
std::string const& _name );
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
SectionInfo
|
SectionInfo
|
||||||
( SourceLineInfo const& _lineInfo,
|
( SourceLineInfo const& _lineInfo,
|
||||||
std::string const& _name,
|
std::string const& _name,
|
||||||
std::string const& _description = std::string() );
|
std::string const& ) : SectionInfo( _lineInfo, _name ) {}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string description;
|
std::string description; // !Deprecated: this will always be empty
|
||||||
SourceLineInfo lineInfo;
|
SourceLineInfo lineInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SectionEndInfo {
|
struct SectionEndInfo {
|
||||||
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds );
|
|
||||||
|
|
||||||
SectionInfo sectionInfo;
|
SectionInfo sectionInfo;
|
||||||
Counts prevAssertions;
|
Counts prevAssertions;
|
||||||
double durationInSeconds;
|
double durationInSeconds;
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "catch_text.h"
|
#include "catch_text.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
#include "catch_windows_h_proxy.h"
|
#include "catch_windows_h_proxy.h"
|
||||||
|
#include "../reporters/catch_reporter_listening.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
@@ -36,33 +37,26 @@ namespace Catch {
|
|||||||
return reporter;
|
return reporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
|
||||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
|
IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
|
||||||
auto const& reporterNames = config->getReporterNames();
|
if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
|
||||||
if (reporterNames.empty())
|
return createReporter(config->getReporterName(), config);
|
||||||
return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config);
|
}
|
||||||
|
|
||||||
IStreamingReporterPtr reporter;
|
auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
|
||||||
for (auto const& name : reporterNames)
|
|
||||||
addReporter(reporter, createReporter(name, config));
|
|
||||||
return reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CATCH_CONFIG_DEFAULT_REPORTER
|
|
||||||
|
|
||||||
void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
|
|
||||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||||
for (auto const& listener : listeners)
|
for (auto const& listener : listeners) {
|
||||||
addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
|
multi->addListener(listener->create(Catch::ReporterConfig(config)));
|
||||||
|
}
|
||||||
|
multi->addReporter(createReporter(config->getReporterName(), config));
|
||||||
|
return std::move(multi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
|
Catch::Totals runTests(std::shared_ptr<Config> const& config) {
|
||||||
IStreamingReporterPtr reporter = makeReporter(config);
|
// FixMe: Add listeners in order first, then add reporters.
|
||||||
addListeners(reporter, config);
|
|
||||||
|
auto reporter = makeReporter(config);
|
||||||
|
|
||||||
RunContext context(config, std::move(reporter));
|
RunContext context(config, std::move(reporter));
|
||||||
|
|
||||||
@@ -125,10 +119,12 @@ namespace Catch {
|
|||||||
Session::Session() {
|
Session::Session() {
|
||||||
static bool alreadyInstantiated = false;
|
static bool alreadyInstantiated = false;
|
||||||
if( alreadyInstantiated ) {
|
if( alreadyInstantiated ) {
|
||||||
try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
|
CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
|
||||||
catch(...) { getMutableRegistryHub().registerStartupException(); }
|
CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There cannot be exceptions at startup in no-exception mode.
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||||
if ( !exceptions.empty() ) {
|
if ( !exceptions.empty() ) {
|
||||||
m_startupExceptions = true;
|
m_startupExceptions = true;
|
||||||
@@ -143,6 +139,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
alreadyInstantiated = true;
|
alreadyInstantiated = true;
|
||||||
m_cli = makeCommandLineParser( m_configData );
|
m_cli = makeCommandLineParser( m_configData );
|
||||||
@@ -257,11 +254,11 @@ namespace Catch {
|
|||||||
if( m_startupExceptions )
|
if( m_startupExceptions )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if( m_configData.showHelp || m_configData.libIdentify )
|
if (m_configData.showHelp || m_configData.libIdentify) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
CATCH_TRY {
|
||||||
{
|
|
||||||
config(); // Force config to be constructed
|
config(); // Force config to be constructed
|
||||||
|
|
||||||
seedRng( *m_config );
|
seedRng( *m_config );
|
||||||
@@ -279,10 +276,12 @@ namespace Catch {
|
|||||||
// of 256 tests has failed
|
// of 256 tests has failed
|
||||||
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
|
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
|
||||||
}
|
}
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
catch( std::exception& ex ) {
|
catch( std::exception& ex ) {
|
||||||
Catch::cerr() << ex.what() << std::endl;
|
Catch::cerr() << ex.what() << std::endl;
|
||||||
return MaxExitCode;
|
return MaxExitCode;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
36
include/internal/catch_singletons.cpp
Normal file
36
include/internal/catch_singletons.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_singletons.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static auto getSingletons() -> std::vector<ISingleton*>*& {
|
||||||
|
static std::vector<ISingleton*>* g_singletons = nullptr;
|
||||||
|
if( !g_singletons )
|
||||||
|
g_singletons = new std::vector<ISingleton*>();
|
||||||
|
return g_singletons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ISingleton::~ISingleton() {}
|
||||||
|
|
||||||
|
void addSingleton(ISingleton* singleton ) {
|
||||||
|
getSingletons()->push_back( singleton );
|
||||||
|
}
|
||||||
|
void cleanupSingletons() {
|
||||||
|
auto& singletons = getSingletons();
|
||||||
|
for( auto singleton : *singletons )
|
||||||
|
delete singleton;
|
||||||
|
delete singletons;
|
||||||
|
singletons = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Catch
|
44
include/internal/catch_singletons.hpp
Normal file
44
include/internal/catch_singletons.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct ISingleton {
|
||||||
|
virtual ~ISingleton();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void addSingleton( ISingleton* singleton );
|
||||||
|
void cleanupSingletons();
|
||||||
|
|
||||||
|
|
||||||
|
template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
|
||||||
|
class Singleton : SingletonImplT, public ISingleton {
|
||||||
|
|
||||||
|
static auto getInternal() -> Singleton* {
|
||||||
|
static Singleton* s_instance = nullptr;
|
||||||
|
if( !s_instance ) {
|
||||||
|
s_instance = new Singleton;
|
||||||
|
addSingleton( s_instance );
|
||||||
|
}
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static auto get() -> InterfaceT const& {
|
||||||
|
return *getInternal();
|
||||||
|
}
|
||||||
|
static auto getMutable() -> MutableInterfaceT& {
|
||||||
|
return *getInternal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
|
@@ -7,13 +7,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_startup_exception_registry.h"
|
#include "catch_startup_exception_registry.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
|
void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
|
||||||
try {
|
CATCH_TRY {
|
||||||
m_exceptions.push_back(exception);
|
m_exceptions.push_back(exception);
|
||||||
}
|
} CATCH_CATCH_ALL {
|
||||||
catch(...) {
|
|
||||||
// If we run out of memory during start-up there's really not a lot more we can do about it
|
// If we run out of memory during start-up there's really not a lot more we can do about it
|
||||||
std::terminate();
|
std::terminate();
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
#include "catch_debug_console.h"
|
#include "catch_debug_console.h"
|
||||||
#include "catch_stringref.h"
|
#include "catch_stringref.h"
|
||||||
|
#include "catch_singletons.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -20,11 +21,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
Catch::IStream::~IStream() = default;
|
Catch::IStream::~IStream() = default;
|
||||||
@@ -145,7 +141,6 @@ namespace Catch {
|
|||||||
std::vector<std::unique_ptr<std::ostringstream>> m_streams;
|
std::vector<std::unique_ptr<std::ostringstream>> m_streams;
|
||||||
std::vector<std::size_t> m_unused;
|
std::vector<std::size_t> m_unused;
|
||||||
std::ostringstream m_referenceStream; // Used for copy state/ flags from
|
std::ostringstream m_referenceStream; // Used for copy state/ flags from
|
||||||
static StringStreams* s_instance;
|
|
||||||
|
|
||||||
auto add() -> std::size_t {
|
auto add() -> std::size_t {
|
||||||
if( m_unused.empty() ) {
|
if( m_unused.empty() ) {
|
||||||
@@ -163,34 +158,17 @@ namespace Catch {
|
|||||||
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
|
||||||
m_unused.push_back(index);
|
m_unused.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// !TBD: put in TLS
|
|
||||||
static auto instance() -> StringStreams& {
|
|
||||||
if( !s_instance )
|
|
||||||
s_instance = new StringStreams();
|
|
||||||
return *s_instance;
|
|
||||||
}
|
|
||||||
static void cleanup() {
|
|
||||||
delete s_instance;
|
|
||||||
s_instance = nullptr;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
StringStreams* StringStreams::s_instance = nullptr;
|
|
||||||
|
|
||||||
void ReusableStringStream::cleanup() {
|
|
||||||
StringStreams::cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReusableStringStream::ReusableStringStream()
|
ReusableStringStream::ReusableStringStream()
|
||||||
: m_index( StringStreams::instance().add() ),
|
: m_index( Singleton<StringStreams>::getMutable().add() ),
|
||||||
m_oss( StringStreams::instance().m_streams[m_index].get() )
|
m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ReusableStringStream::~ReusableStringStream() {
|
ReusableStringStream::~ReusableStringStream() {
|
||||||
static_cast<std::ostringstream*>( m_oss )->str("");
|
static_cast<std::ostringstream*>( m_oss )->str("");
|
||||||
m_oss->clear();
|
m_oss->clear();
|
||||||
StringStreams::instance().release( m_index );
|
Singleton<StringStreams>::getMutable().release( m_index );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ReusableStringStream::str() const -> std::string {
|
auto ReusableStringStream::str() const -> std::string {
|
||||||
@@ -207,7 +185,3 @@ namespace Catch {
|
|||||||
std::ostream& clog() { return std::clog; }
|
std::ostream& clog() { return std::clog; }
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
@@ -43,8 +43,6 @@ namespace Catch {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto get() -> std::ostream& { return *m_oss; }
|
auto get() -> std::ostream& { return *m_oss; }
|
||||||
|
|
||||||
static void cleanup();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
char toLowerCh(char c) {
|
||||||
|
return static_cast<char>( std::tolower( c ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||||
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
||||||
}
|
}
|
||||||
@@ -29,9 +35,6 @@ namespace Catch {
|
|||||||
bool contains( std::string const& s, std::string const& infix ) {
|
bool contains( std::string const& s, std::string const& infix ) {
|
||||||
return s.find( infix ) != std::string::npos;
|
return s.find( infix ) != std::string::npos;
|
||||||
}
|
}
|
||||||
char toLowerCh(char c) {
|
|
||||||
return static_cast<char>( std::tolower( c ) );
|
|
||||||
}
|
|
||||||
void toLowerInPlace( std::string& s ) {
|
void toLowerInPlace( std::string& s ) {
|
||||||
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
|
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
|
||||||
}
|
}
|
||||||
|
@@ -127,4 +127,8 @@ namespace Catch {
|
|||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
|
inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
|
||||||
|
return Catch::StringRef( rawChars, size );
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CATCH_STRINGREF_H_INCLUDED
|
#endif // CATCH_STRINGREF_H_INCLUDED
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user