mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 00:15:39 +02:00
Compare commits
153 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
0a34cc201e | ||
![]() |
11c89a5f7d | ||
![]() |
dc3e7f9cf7 | ||
![]() |
d14b7563c2 | ||
![]() |
a3d3a633b2 | ||
![]() |
8d4796309f | ||
![]() |
552589f25b | ||
![]() |
95c849f613 | ||
![]() |
352853ed7e | ||
![]() |
b11175548a | ||
![]() |
d38f782995 | ||
![]() |
dc8a8e6371 | ||
![]() |
9d1858b195 | ||
![]() |
1d1f8dc992 | ||
![]() |
1466686ade | ||
![]() |
93db01c647 | ||
![]() |
2e285b9579 | ||
![]() |
d2ddb997a7 | ||
![]() |
865d5f59b4 | ||
![]() |
05cd05743a | ||
![]() |
950ccf4749 | ||
![]() |
cf4b7eead9 | ||
![]() |
7b6e49d795 | ||
![]() |
0c5df42c28 | ||
![]() |
4e57661919 | ||
![]() |
5a8f9c84dd | ||
![]() |
f988b4eb35 | ||
![]() |
c8d765a575 | ||
![]() |
da783abee9 | ||
![]() |
c0267e5c20 | ||
![]() |
bb84f0788a | ||
![]() |
e84768fff1 | ||
![]() |
31673ee0ca | ||
![]() |
34d7a33574 | ||
![]() |
082c3b84bc | ||
![]() |
ef2e112561 | ||
![]() |
a90305f857 | ||
![]() |
543c9d3a67 | ||
![]() |
ca8470fbad | ||
![]() |
355b3f9952 | ||
![]() |
7cbd0b587a | ||
![]() |
2f15ccd4d3 | ||
![]() |
8f3fc15b73 | ||
![]() |
e13d9cab02 | ||
![]() |
414e2fa946 | ||
![]() |
b5ef68b044 | ||
![]() |
681f5daa13 | ||
![]() |
3b6fda3c1b | ||
![]() |
1b2fa601c6 | ||
![]() |
39bfc6e82b | ||
![]() |
ba6d33fb8c | ||
![]() |
4be81d3588 | ||
![]() |
5201e92564 | ||
![]() |
5e484862f2 | ||
![]() |
5713381d06 | ||
![]() |
1ab6be30a2 | ||
![]() |
126850e76b | ||
![]() |
5e8df1c384 | ||
![]() |
44dbda9f01 | ||
![]() |
ca2455e6e6 | ||
![]() |
42213d4c31 |
7
.gitattributes
vendored
7
.gitattributes
vendored
@@ -10,6 +10,13 @@
|
||||
# Windows specific files should retain windows line-endings
|
||||
*.sln text eol=crlf
|
||||
|
||||
# Keep executable scripts with LFs so they can be run after being
|
||||
# checked out on Windows
|
||||
*.py text eol=lf
|
||||
|
||||
|
||||
# Keep the single include header with LFs to make sure it is uploaded,
|
||||
# hashed etc with LF
|
||||
single_include/*.hpp eol=lf
|
||||
# Also keep the LICENCE file with LFs for the same reason
|
||||
LICENCE.txt eol=lf
|
||||
|
169
.travis.yml
169
.travis.yml
@@ -1,12 +1,17 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /dev-appveyor.*/
|
||||
|
||||
common_sources: &all_sources
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
- llvm-toolchain-trusty-3.9
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- llvm-toolchain-trusty-6.0
|
||||
|
||||
matrix:
|
||||
include:
|
||||
@@ -17,145 +22,169 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'clang-3.5']
|
||||
env: COMPILER='clang++-3.5' VALGRIND=1
|
||||
packages: ['clang-3.5']
|
||||
env: COMPILER='clang++-3.5'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'clang-3.6']
|
||||
env: COMPILER='clang++-3.6' VALGRIND=1
|
||||
packages: ['clang-3.6']
|
||||
env: COMPILER='clang++-3.6'
|
||||
|
||||
# Travis's containers do not seem to have Clang 3.7 in apt, no matter what sources I add.
|
||||
# - os: linux
|
||||
# compiler: clang
|
||||
# addons:
|
||||
# apt:
|
||||
# sources: *all_sources
|
||||
# packages: ['valgrind', 'clang-3.7']
|
||||
# env: COMPILER='clang++-3.7' VALGRIND=1
|
||||
# Clang 3.7 is intentionally skipped as we cannot get it easily on
|
||||
# TravisCI container
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'clang-3.8']
|
||||
env: COMPILER='clang++-3.8' VALGRIND=1
|
||||
packages: ['lcov', 'clang-3.8']
|
||||
env: COMPILER='clang++-3.8'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.9', 'valgrind', 'lcov']
|
||||
env: COMPILER='clang++-3.9' VALGRIND=1
|
||||
packages: ['clang-3.9']
|
||||
env: COMPILER='clang++-3.9'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-4.0', 'valgrind', 'lcov']
|
||||
env: COMPILER='clang++-4.0' VALGRIND=1
|
||||
packages: ['clang-4.0']
|
||||
env: COMPILER='clang++-4.0'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-5.0', 'valgrind', 'lcov']
|
||||
env: COMPILER='clang++-5.0' VALGRIND=1
|
||||
packages: ['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
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['valgrind', 'lcov', 'g++-4.8']
|
||||
env: COMPILER='g++-4.8' VALGRIND=1
|
||||
sources: *all_sources
|
||||
packages: ['g++-4.8']
|
||||
env: COMPILER='g++-4.8'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-4.9']
|
||||
env: COMPILER='g++-4.9' VALGRIND=1
|
||||
packages: ['g++-4.9']
|
||||
env: COMPILER='g++-4.9'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-5']
|
||||
env: COMPILER='g++-5' VALGRIND=1
|
||||
packages: ['g++-5']
|
||||
env: COMPILER='g++-5'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-6']
|
||||
env: COMPILER='g++-6' VALGRIND=1
|
||||
packages: ['g++-6']
|
||||
env: COMPILER='g++-6'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc7
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-7']
|
||||
env: COMPILER='g++-7' VALGRIND=1
|
||||
packages: ['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
|
||||
# Note that we need newer libstdc++ for C++14 support
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
packages: ['clang-3.8', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
||||
packages: ['clang-3.8', 'libstdc++-6-dev']
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
env: COMPILER='clang++-3.8' CPP14=1 VALGRIND=1
|
||||
env: COMPILER='clang++-3.8' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.9', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-3.9' CPP14=1 VALGRIND=1
|
||||
packages: ['clang-3.9', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-3.9' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-4.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-4.0' CPP14=1 VALGRIND=1
|
||||
packages: ['clang-4.0', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-4.0' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-5.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-5.0' CPP14=1 VALGRIND=1
|
||||
packages: ['clang-5.0', 'libstdc++-6-dev']
|
||||
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
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' CPP14=1 VALGRIND=1
|
||||
env: COMPILER='g++-6' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc7
|
||||
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
|
||||
env: COMPILER='g++-7' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc8
|
||||
env: COMPILER='g++-8' CPP14=1
|
||||
|
||||
# 5/ OSX Clang Builds
|
||||
- os: osx
|
||||
@@ -181,15 +210,46 @@ matrix:
|
||||
- os: osx
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' USE_CPP14=1
|
||||
env: COMPILER='clang++' CPP14=1
|
||||
|
||||
# 6/ Special builds -- examples, coverage, valgrind, etc.
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['lcov', 'g++-7']
|
||||
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
packages: ['clang-3.8', 'lcov']
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-7']
|
||||
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1
|
||||
|
||||
install:
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
||||
- |
|
||||
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://www.cmake.org/files/v3.5/cmake-3.5.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
|
||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
@@ -202,25 +262,24 @@ before_script:
|
||||
# Regenerate single header file, so it is tested in the examples...
|
||||
- python scripts/generateSingleHeader.py
|
||||
|
||||
- |
|
||||
# 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=ON -DCATCH_ENABLE_COVERAGE=ON
|
||||
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE}
|
||||
# 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:
|
||||
- |
|
||||
cd Build-Debug
|
||||
make -j 2
|
||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||
- cd Build-Debug
|
||||
- make -j 2
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||
# Coverage collection does not work for OS X atm
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
|
||||
make gcov
|
||||
make lcov
|
||||
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
||||
fi
|
||||
# Go to release build
|
||||
cd ../Build-Release
|
||||
make -j 2
|
||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||
- # Go to release build
|
||||
- cd ../Build-Release
|
||||
- make -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}
|
517
CMakeLists.txt
517
CMakeLists.txt
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# detect if Catch is being bundled,
|
||||
# disable testsuite in that case
|
||||
@@ -6,14 +6,23 @@ if(NOT DEFINED PROJECT_NAME)
|
||||
set(NOT_SUBPROJECT ON)
|
||||
endif()
|
||||
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.1.1)
|
||||
project(Catch2 LANGUAGES CXX VERSION 2.3.0)
|
||||
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CTest)
|
||||
|
||||
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_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
|
||||
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
|
||||
option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
|
||||
option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
|
||||
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
@@ -27,379 +36,149 @@ if(USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
|
||||
#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()
|
||||
|
||||
# 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_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_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()
|
||||
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||
add_subdirectory(projects)
|
||||
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 desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code )
|
||||
if (CATCH_ENABLE_WERROR)
|
||||
target_compile_options( SelfTest PRIVATE -Werror)
|
||||
endif()
|
||||
endif()
|
||||
# Clang specific warning go here
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
# Actually keep these
|
||||
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()
|
||||
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")
|
||||
|
||||
add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
|
||||
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
|
||||
|
||||
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")
|
||||
|
||||
|
||||
|
||||
# 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)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
|
||||
|
||||
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
||||
# add catch as a 'linkable' target
|
||||
add_library(Catch2 INTERFACE)
|
||||
|
||||
|
||||
|
||||
# depend on some obvious c++11 features so the dependency is transitively added dependents
|
||||
target_compile_features(Catch2
|
||||
INTERFACE
|
||||
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
|
||||
add_library(Catch2::Catch2 ALIAS Catch2)
|
||||
|
||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
|
||||
INSTALL_DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
|
||||
# create and install an export set for catch target as Catch2::Catch
|
||||
install(
|
||||
TARGETS
|
||||
Catch2
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
|
||||
install(
|
||||
EXPORT
|
||||
Catch2Targets
|
||||
NAMESPACE
|
||||
Catch2::
|
||||
DESTINATION
|
||||
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
COMPATIBILITY
|
||||
SameMajorVersion
|
||||
)
|
||||
|
||||
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
|
||||
# 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()
|
||||
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}
|
||||
)
|
||||
|
@@ -5,9 +5,11 @@
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/TpIcJaLaH4WrKlhS)
|
||||
[](https://wandbox.org/permlink/Gcuv2Xx3wmWIPNzy)
|
||||
[](https://discord.gg/4CWS9zD)
|
||||
|
||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.1.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.3.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
@@ -32,5 +34,5 @@ This documentation comprises these three parts:
|
||||
|
||||
## More
|
||||
* 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)
|
||||
|
43
appveyor.yml
43
appveyor.yml
@@ -19,18 +19,53 @@ environment:
|
||||
|
||||
- additional_flags: "/D_UNICODE /DUNICODE"
|
||||
wmain: 1
|
||||
coverage: 0
|
||||
|
||||
# Have a coverage dimension
|
||||
- additional_flags: ""
|
||||
wmain: 0
|
||||
coverage: 1
|
||||
|
||||
# Have an examples dimension
|
||||
- additional_flags: ""
|
||||
wmain: 0
|
||||
examples: 1
|
||||
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- os: Visual Studio 2017
|
||||
exclude:
|
||||
- os: Visual Studio 2015
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
- os: Visual Studio 2015
|
||||
additional_flags: "/D_UNICODE /DUNICODE"
|
||||
|
||||
# Exclude unwanted coverage configurations
|
||||
- coverage: 1
|
||||
platform: Win32
|
||||
|
||||
- coverage: 1
|
||||
os: Visual Studio 2015
|
||||
|
||||
- coverage: 1
|
||||
configuration: Release
|
||||
|
||||
# Exclude unwanted examples configurations
|
||||
- examples: 1
|
||||
platform: Win32
|
||||
|
||||
- examples: 1
|
||||
os: Visual Studio 2015
|
||||
|
||||
- examples: 1
|
||||
configuration: Release
|
||||
|
||||
|
||||
install:
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { python -m pip install codecov }
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { .\misc\installOpenCppCoverage.ps1 }
|
||||
- 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 }
|
||||
|
||||
# Win32 and x64 are CMake-compatible solution platform names.
|
||||
# This allows us to pass %PLATFORM% to CMake -A.
|
||||
|
@@ -1,6 +0,0 @@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: Catch
|
||||
Description: Testing library for C++
|
||||
Version: @Catch2_VERSION@
|
||||
Cflags: -I${includedir}
|
18
codecov.yml
18
codecov.yml
@@ -6,17 +6,19 @@ coverage:
|
||||
project:
|
||||
default:
|
||||
threshold: 2%
|
||||
|
||||
codecov:
|
||||
branch: master
|
||||
|
||||
comment:
|
||||
layout: "diff"
|
||||
|
||||
coverage:
|
||||
patch:
|
||||
default:
|
||||
target: 80%
|
||||
ignore:
|
||||
- "projects/SelfTest"
|
||||
- "**/catch_reporter_tap.hpp"
|
||||
- "**/catch_reporter_automake.hpp"
|
||||
- "**/catch_reporter_teamcity.hpp"
|
||||
- "**/external/clara.hpp"
|
||||
|
||||
|
||||
codecov:
|
||||
branch: master
|
||||
|
||||
comment:
|
||||
layout: "diff"
|
||||
|
24
conanfile.py
24
conanfile.py
@@ -1,19 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
from conans import ConanFile
|
||||
from conans import ConanFile, CMake
|
||||
|
||||
|
||||
class CatchConan(ConanFile):
|
||||
name = "Catch"
|
||||
version = "2.1.1"
|
||||
version = "2.3.0"
|
||||
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
||||
author = "philsquared"
|
||||
generators = "cmake"
|
||||
exports_sources = "single_include/*"
|
||||
url = "https://github.com/philsquared/Catch"
|
||||
# Only needed until conan 1.5 is released
|
||||
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"
|
||||
|
||||
def build(self):
|
||||
pass
|
||||
|
||||
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):
|
||||
self.info.header_only()
|
||||
self.info.header_only()
|
||||
|
@@ -50,8 +50,7 @@ string(REPLACE "\n" ";" output "${output}")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
# Test name; strip spaces to get just the name...
|
||||
string(REGEX REPLACE " +" "" test "${line}")
|
||||
set(test ${line})
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
|
@@ -143,6 +143,9 @@ function(ParseFile SourceFile TestTarget)
|
||||
endif()
|
||||
string(REPLACE "]" ";" Tags "${Tags}")
|
||||
string(REPLACE "[" "" Tags "${Tags}")
|
||||
else()
|
||||
# unset tags variable from previous loop
|
||||
unset(Tags)
|
||||
endif()
|
||||
|
||||
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
|
@@ -20,7 +20,10 @@ Fine tuning:
|
||||
|
||||
Running:
|
||||
* [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:
|
||||
* [Why are my tests slow to compile?](slow-compiles.md#top)
|
||||
|
@@ -6,10 +6,11 @@
|
||||
[Exceptions](#exceptions)<br>
|
||||
[Matcher expressions](#matcher-expressions)<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).
|
||||
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxilliary macros as well. We'll describe all of these here.
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
|
||||
Most of these macros come in two forms:
|
||||
|
||||
@@ -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.
|
||||
|
||||
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 ) );
|
||||
```
|
||||
|
||||
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`.
|
||||
* __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`.
|
||||
* __scale__ - scale serves to adjust the epsilon's multiplicator. By default set to `0.0`.
|
||||
`Approx` is constructed with defaults that should cover most simple cases.
|
||||
For the more complex cases, `Approx` provides 3 customization points:
|
||||
|
||||
* __epsilon__ - epsilon serves to set the percentage 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
|
||||
```cpp
|
||||
Approx target = Approx(100).epsilon(0.01);
|
||||
100.0 == target; // Obviously true
|
||||
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 check is used only if the relative (epsilon and scale based) check fails._
|
||||
```cpp
|
||||
Approx target = Approx(100).margin(5);
|
||||
100.0 == target; // Obviously true
|
||||
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
|
||||
@@ -155,6 +168,34 @@ Matchers can be composed using `&&`, `||` and `!` operators.
|
||||
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).
|
||||
|
||||
## 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)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<a id="top"></a>
|
||||
# CI and build system integration
|
||||
# CI and other odd pieces
|
||||
|
||||
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.
|
||||
|
||||
## Continuous Integration systems
|
||||
@@ -71,105 +72,31 @@ Catch offers prototypal support for being included in precompiled headers, but b
|
||||
* 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...)
|
||||
|
||||
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)
|
189
docs/cmake-integration.md
Normal file
189
docs/cmake-integration.md
Normal file
@@ -0,0 +1,189 @@
|
||||
<a id="top"></a>
|
||||
# CMake integration
|
||||
|
||||
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`.
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
@@ -24,6 +24,7 @@
|
||||
[Usage](#usage)<br>
|
||||
[Specify the section to run](#specify-the-section-to-run)<br>
|
||||
[Filenames as tags](#filenames-as-tags)<br>
|
||||
[Override output colouring](#use-colour)<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.
|
||||
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="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
||||
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
||||
<a href="#use-colour"> ` --use-colour`</a><br />
|
||||
|
||||
</br>
|
||||
|
||||
@@ -78,7 +80,7 @@ Wildcards consist of the `*` character at the beginning and/or end of test case
|
||||
|
||||
Test specs are case insensitive.
|
||||
|
||||
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precendence, however.
|
||||
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however.
|
||||
Inclusions and exclusions are evaluated in left-to-right order.
|
||||
|
||||
Test case examples:
|
||||
@@ -94,7 +96,7 @@ a* ~ab* abc Matches all tests that start with 'a', except those that
|
||||
</pre>
|
||||
|
||||
Names within square brackets are interpreted as tags.
|
||||
A series of tags form an AND expression wheras a comma-separated sequence forms an OR expression. e.g.:
|
||||
A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.:
|
||||
|
||||
<pre>[one][two],[three]</pre>
|
||||
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
|
||||
@@ -122,7 +124,9 @@ The JUnit reporter is an xml format that follows the structure of the JUnit XML
|
||||
## Breaking into the debugger
|
||||
<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>
|
||||
## Showing results for successful tests
|
||||
@@ -192,9 +196,16 @@ This option transforms tabs and newline characters into ```\t``` and ```\n``` re
|
||||
## Warnings
|
||||
<pre>-w, --warn <warning name></pre>
|
||||
|
||||
Enables reporting of warnings (only one, at time of this writing). If a warning is issued it fails the test.
|
||||
Enables reporting of suspicious test states. There are currently two
|
||||
available warnings
|
||||
|
||||
```
|
||||
NoAssertions // Fail test case / leaf section if no assertions
|
||||
// (e.g. `REQUIRE`) is encountered.
|
||||
NoTests // Return non-zero exit code when no test cases were run
|
||||
// Also calls reporter's noMatchingTestCases method
|
||||
```
|
||||
|
||||
The ony available warning, presently, is ```NoAssertions```. This warning fails a test case, or (leaf) section if no assertions (```REQUIRE```/ ```CHECK``` etc) are encountered.
|
||||
|
||||
<a id="reporting-timings"></a>
|
||||
## Reporting timings
|
||||
@@ -262,7 +273,7 @@ either before running any tests, after running all tests - or both, depending on
|
||||
|
||||
When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
|
||||
numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but
|
||||
it can be overriden here.
|
||||
it can be overridden here.
|
||||
|
||||
<a id="usage"></a>
|
||||
## Usage
|
||||
@@ -322,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]`.
|
||||
|
||||
<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`.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -7,6 +7,8 @@
|
||||
[Terminal colour](#terminal-colour)<br>
|
||||
[Console width](#console-width)<br>
|
||||
[stdout](#stdout)<br>
|
||||
[Fallback stringifier](#fallback-stringifier)<br>
|
||||
[Default reporter](#default-reporter)<br>
|
||||
[Other toggles](#other-toggles)<br>
|
||||
[Windows header clutter](#windows-header-clutter)<br>
|
||||
[Enabling stringification](#enabling-stringification)<br>
|
||||
@@ -24,7 +26,7 @@ Although Catch is header only it still, internally, maintains a distinction betw
|
||||
|
||||
# Reporter / Listener interfaces
|
||||
|
||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in neccessary headers for Reporter/Listener implementation
|
||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
|
||||
|
||||
Brings in various parts of Catch that are required for user defined Reporters and Listeners. This means that new Reporters and Listeners can be defined in this file as well as in the main file.
|
||||
|
||||
@@ -64,15 +66,70 @@ By default a console width of 80 is assumed but this can be controlled by defini
|
||||
|
||||
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& cerr();
|
||||
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
|
||||
|
||||
By default, when Catch's stringification machinery has to stringify
|
||||
a type that does not specialize `StringMaker`, does not overload `operator<<`,
|
||||
is not an enumeration and is not a range, it uses `"{?}"`. This can be
|
||||
overriden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
|
||||
function that should perform the stringification instead.
|
||||
|
||||
All types that do not provide `StringMaker` specialization or `operator<<`
|
||||
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
|
||||
requires to be stringified, the compilation will fail._
|
||||
|
||||
|
||||
## Default reporter
|
||||
|
||||
Catch's default reporter can be changed by defining macro
|
||||
`CATCH_CONFIG_DEFAULT_REPORTER` to string literal naming the desired
|
||||
default reporter.
|
||||
|
||||
This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
|
||||
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
|
||||
|
||||
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
|
||||
|
||||
Catch contains basic compiler/standard detection and attempts to use
|
||||
some C++17 features whenever appropriate. This automatic detection
|
||||
can be manually overridden in both directions, that is, a feature
|
||||
can be enabled by defining the macro in the table above, and disabled
|
||||
by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
|
||||
|
||||
|
||||
## Other toggles
|
||||
|
||||
@@ -84,6 +141,8 @@ This can be useful on certain platforms that do not provide the standard iostrea
|
||||
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
|
||||
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
||||
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
||||
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.
|
||||
|
||||
@@ -91,14 +150,22 @@ Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC,
|
||||
|
||||
`CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running.
|
||||
|
||||
These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
|
||||
`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently
|
||||
it is only used in support for DJGPP cross-compiler.
|
||||
|
||||
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`
|
||||
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
|
||||
* 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*.
|
||||
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives.
|
||||
This compile-time flag speeds up compilation of assertion macros by ~20%,
|
||||
by disabling the generation of assertion-local try-catch blocks for
|
||||
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`
|
||||
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.
|
||||
|
@@ -44,7 +44,7 @@ _Note that you should not use any assertion macros within a Listener!_
|
||||
|
||||
## Events that can be hooked
|
||||
|
||||
The following are the methods that can be overriden in the Listener:
|
||||
The following are the methods that can be overridden in the Listener:
|
||||
|
||||
```c++
|
||||
// The whole test run, starting and ending
|
||||
|
@@ -21,7 +21,9 @@ TEST_CASE( "Looped section" ) {
|
||||
This section outlines some missing features, what is their status and their possible workarounds.
|
||||
|
||||
### 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
|
||||
```cpp
|
||||
@@ -49,8 +51,8 @@ because only one thread passes the `REQUIRE` macro and this is not
|
||||
REQUIRE(cnt == 16);
|
||||
```
|
||||
|
||||
|
||||
_This limitation is highly unlikely to be lifted before Catch 2 is released._
|
||||
Because C++11 provides the necessary tools to do this, we are planning
|
||||
to remove this limitation in the future.
|
||||
|
||||
### 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.
|
||||
@@ -96,6 +98,14 @@ with expansion:
|
||||
""\" == ""\"
|
||||
```
|
||||
|
||||
### Visual Studio 2015 -- Alignment compilation error (C2718)
|
||||
|
||||
VS 2015 has a known bug, where `declval<T>` can cause compilation error
|
||||
if `T` has alignment requirements that it cannot meet.
|
||||
|
||||
|
||||
A workaround is to explicitly specialize `Catch::is_range` for given
|
||||
type (this avoids code path that uses `declval<T>` in a SFINAE context).
|
||||
|
||||
|
||||
### Visual Studio 2015 -- Wrong line number reported in debug mode
|
||||
|
@@ -1,18 +1,25 @@
|
||||
<a id="top"></a>
|
||||
# List of examples
|
||||
|
||||
## Already available
|
||||
|
||||
- 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)
|
||||
- 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)
|
||||
- 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_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
||||
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
||||
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
||||
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.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)
|
||||
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
||||
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
||||
@@ -21,7 +28,6 @@
|
||||
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
|
||||
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
||||
- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
|
||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
||||
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
||||
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
||||
|
@@ -72,12 +72,6 @@ This would log something like:
|
||||
|
||||
<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)
|
||||
|
@@ -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.
|
||||
|
||||
|
||||
### 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
|
||||
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
||||
|
||||
|
@@ -1,18 +1,18 @@
|
||||
<a id="top"></a>
|
||||
# Open Source projects using Catch
|
||||
|
||||
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
|
||||
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
|
||||
it's easy to just drop the header into your project and start writing tests - what's not to like?
|
||||
|
||||
As a result Catch is now being used in many Open Source projects, including some quite well known ones.
|
||||
This page is an attempt to track those projects. Obviously it can never be complete.
|
||||
This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR
|
||||
(or, if you prefer contact one of the maintainers of Catch directly, use the
|
||||
(or, if you prefer contact one of the maintainers of Catch directly, use the
|
||||
[forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)), or raise an [issue](https://github.com/philsquared/Catch/issues) to let us know).
|
||||
Of course users of those projects might want to update this page too. That's fine - as long you're confident the project maintainers won't mind.
|
||||
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
|
||||
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
|
||||
just let us know via any of the previously mentioned means - although I'm sure there won't be many who feel that way.
|
||||
|
||||
|
||||
Listing a project here does not imply endorsement and the plan is to keep these ordered alphabetically to avoid an implication of relative importance.
|
||||
|
||||
## Libraries & Frameworks
|
||||
@@ -21,7 +21,7 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
||||
Boost Asio style bindings for ZeroMQ
|
||||
|
||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||
The core part of the Chakra Javascript engine that powers Microsoft Edge
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge
|
||||
|
||||
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
||||
@@ -35,6 +35,9 @@ The next-generation core storage and query engine for Couchbase Lite
|
||||
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
||||
A High-performance Cluster Computing Engine
|
||||
|
||||
### [forest](https://github.com/xorz57/forest)
|
||||
Forest is an open-source, template library of tree data structures written in C++11.
|
||||
|
||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||
|
||||
@@ -44,6 +47,9 @@ A header-only template engine for modern C++.
|
||||
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||
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)
|
||||
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.
|
||||
|
||||
@@ -88,6 +94,9 @@ MAME originally stood for Multiple Arcade Machine Emulator
|
||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||
|
||||
### [SpECTRE](https://github.com/sxs-collaboration/spectre)
|
||||
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
|
||||
|
@@ -30,7 +30,7 @@ int main( int argc, char* argv[] ) {
|
||||
|
||||
## Amending the config
|
||||
|
||||
If you still want Catch to process the command line, but you want to programatically tweak the config, you can do so in one of two ways:
|
||||
If you still want Catch to process the command line, but you want to programmatically tweak the config, you can do so in one of two ways:
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
@@ -106,6 +106,20 @@ int main( int argc, char* argv[] )
|
||||
|
||||
See the [Clara documentation](https://github.com/philsquared/Clara/blob/master/README.md) for more details.
|
||||
|
||||
|
||||
## Version detection
|
||||
|
||||
Catch provides a triplet of macros providing the header's version,
|
||||
|
||||
* `CATCH_VERSION_MAJOR`
|
||||
* `CATCH_VERSION_MINOR`
|
||||
* `CATCH_VERSION_PATCH`
|
||||
|
||||
these macros expand into a single number, that corresponds to the appropriate
|
||||
part of the version. As an example, given single header version v2.3.4,
|
||||
the macros would expand into `2`, `3`, and `4` respectively.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
||||
|
@@ -1,5 +1,145 @@
|
||||
<a id="top"></a>
|
||||
|
||||
# 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)
|
||||
* Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
|
||||
* Fixed Catch2 return code always being 0 (#1215)
|
||||
* In the words of STL, "We feel superbad about letting this in"
|
||||
|
||||
|
||||
# 2.2.0
|
||||
|
||||
## Fixes
|
||||
* Hidden tests are not listed by default when listing tests (#1175)
|
||||
* This makes `catch_discover_tests` CMake script work better
|
||||
* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
|
||||
* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
|
||||
|
||||
## Improvements
|
||||
* Added an option to warn (+ exit with error) when no tests were ran (#1158)
|
||||
* Use as `-w NoTests`
|
||||
* Added provisional support for Emscripten (#1114)
|
||||
* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/master/docs/configuration.md#fallback-stringifier) (#1024)
|
||||
* This allows project's own stringification machinery to be easily reused for Catch
|
||||
* `Catch::Session::run()` now accepts `char const * const *`, allowing it to accept array of string literals (#1031, #1178)
|
||||
* The embedded version of Clara was bumped to v1.1.3
|
||||
* Various minor performance improvements
|
||||
* Added support for DJGPP DOS crosscompiler (#1206)
|
||||
|
||||
|
||||
# 2.1.2
|
||||
|
||||
## Fixes
|
||||
* Fixed compilation error with `-fno-rtti` (#1165)
|
||||
* Fixed NoAssertion warnings
|
||||
* `operator<<` is used before range-based stringification (#1172)
|
||||
* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
|
||||
|
||||
|
||||
## Improvements
|
||||
* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
|
||||
* Added `BrightYellow` colour for use in reporters (#979)
|
||||
* It is also used by ConsoleReporter for reconstructed expressions
|
||||
|
||||
## Other changes
|
||||
* Catch is now exported as a CMake package and linkable target (#1170)
|
||||
|
||||
# 2.1.1
|
||||
|
||||
## Improvements
|
||||
@@ -362,8 +502,8 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
|
||||
* Cygwin compatibility fixes
|
||||
* Signal handling is no longer compiled by default.
|
||||
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
|
||||
* Improved `-Wparentheses` supression for gcc (#674)
|
||||
* When compiled with gcc 4.8 or newer, the supression is localized to assertions only
|
||||
* Improved `-Wparentheses` suppression for gcc (#674)
|
||||
* When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
|
||||
* Otherwise it is supressed for the whole TU
|
||||
* Fixed test spec parser issue (with escapes in multiple names)
|
||||
|
||||
@@ -382,7 +522,7 @@ Xml:
|
||||
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
|
||||
* Revert XML output to XML 1.0
|
||||
* Can provide stylesheet references by extending the XML reporter
|
||||
* Added description and tags attribites to XML Reporter
|
||||
* Added description and tags attributes to XML Reporter
|
||||
* Tags are closed and the stream flushed more eagerly to avoid stdout interpolation
|
||||
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<a id="top"></a>
|
||||
# How to release
|
||||
|
||||
When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
|
||||
When enough changes have accumulated, it is time to release new version of Catch. This document describes the process in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
|
||||
|
||||
## Neccessary steps
|
||||
## Necessary steps
|
||||
|
||||
These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
|
||||
These steps are necessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
|
||||
|
||||
|
||||
### Approval testing
|
||||
@@ -49,17 +49,5 @@ on a specific version of the single-include header.
|
||||
|
||||
## 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.
|
||||
|
||||
|
||||
### 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 neccessary work for you, it creates a branch and commits neccessary 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
|
||||
```
|
||||
|
||||
Because Catch's [vcpkg](https://github.com/Microsoft/vcpkg) port updates
|
||||
itself automagically, there are no optional steps at this time.
|
||||
|
@@ -33,6 +33,23 @@ namespace Catch {
|
||||
}
|
||||
```
|
||||
|
||||
## Catch::is_range<T> specialisation
|
||||
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
|
||||
as a range. For certain types this can lead to infinite recursion, so
|
||||
it can be disabled by specializing `Catch::is_range` like so:
|
||||
|
||||
```cpp
|
||||
namespace Catch {
|
||||
template<>
|
||||
struct is_range<T> {
|
||||
static const bool value = false;
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Exceptions
|
||||
|
||||
By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example:
|
||||
|
@@ -12,7 +12,10 @@
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
_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
|
||||
|
||||
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():
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
// That's it
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
// Let Catch provide main():
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
int Factorial( int number ) {
|
||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||
|
@@ -6,7 +6,7 @@
|
||||
// Let Catch provide 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]" ) {
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
// main() provided by Catch in file 020-TestCase-1.cpp.
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
int Factorial( int number ) {
|
||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
std::string one() {
|
||||
return "1";
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
class DBConnection
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
// Let Catch provide the required interfaces:
|
||||
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#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 ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- name: " << info.name << "\n"
|
||||
<< ws(level+1) << "- description: '" << info.description << "'\n";
|
||||
<< ws(level+1) << "- name: " << info.name << "\n";
|
||||
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.");
|
||||
}
|
@@ -17,6 +17,7 @@ set( HEADER_DIR ${CATCH_DIR}/single_include )
|
||||
|
||||
set( SOURCES_SINGLE_FILE
|
||||
010-TestCase.cpp
|
||||
231-Cfg-OutputStreams.cpp
|
||||
)
|
||||
|
||||
# multiple-file modules:
|
||||
@@ -68,16 +69,16 @@ set( TARGETS_ALL ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 0
|
||||
|
||||
# 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_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch.hpp )
|
||||
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
foreach( name ${TARGETS_ALL} )
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 3
|
||||
#define CATCH_VERSION_PATCH 0
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
@@ -30,7 +33,9 @@
|
||||
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
||||
# endif
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||
@@ -132,6 +137,7 @@
|
||||
#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_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_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__ )
|
||||
@@ -141,11 +147,11 @@
|
||||
// "BDD-style" convenience wrappers
|
||||
#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_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc )
|
||||
#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc )
|
||||
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
||||
#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc )
|
||||
#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
||||
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << 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
|
||||
#else
|
||||
@@ -191,6 +197,7 @@
|
||||
#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 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_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__ )
|
||||
@@ -204,15 +211,16 @@
|
||||
#define SCENARIO( ... ) TEST_CASE( "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 WHEN( desc ) SECTION( std::string(" When: ") + desc )
|
||||
#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc )
|
||||
#define THEN( desc ) SECTION( std::string(" Then: ") + desc )
|
||||
#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc )
|
||||
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc )
|
||||
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||
|
||||
using Catch::Detail::Approx;
|
||||
|
||||
#else
|
||||
#else // CATCH_CONFIG_DISABLE
|
||||
|
||||
//////
|
||||
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
||||
#ifdef CATCH_CONFIG_PREFIX_ALL
|
||||
@@ -257,6 +265,7 @@ using Catch::Detail::Approx;
|
||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||
#define CATCH_SECTION( ... )
|
||||
#define CATCH_DYNAMIC_SECTION( ... )
|
||||
#define CATCH_FAIL( ... ) (void)(0)
|
||||
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||
@@ -316,6 +325,7 @@ using Catch::Detail::Approx;
|
||||
#define METHOD_AS_TEST_CASE( method, ... )
|
||||
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||
#define SECTION( ... )
|
||||
#define DYNAMIC_SECTION( ... )
|
||||
#define FAIL( ... ) (void)(0)
|
||||
#define FAIL_CHECK( ... ) (void)(0)
|
||||
#define SUCCEED( ... ) (void)(0)
|
||||
|
54
include/external/clara.hpp
vendored
54
include/external/clara.hpp
vendored
@@ -5,7 +5,7 @@
|
||||
//
|
||||
// See https://github.com/philsquared/Clara for more details
|
||||
|
||||
// Clara v1.1.1
|
||||
// Clara v1.1.4
|
||||
|
||||
#ifndef CATCH_CLARA_HPP_INCLUDED
|
||||
#define CATCH_CLARA_HPP_INCLUDED
|
||||
@@ -18,6 +18,16 @@
|
||||
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#endif
|
||||
|
||||
#ifndef CLARA_CONFIG_OPTIONAL_TYPE
|
||||
#ifdef __has_include
|
||||
#if __has_include(<optional>) && __cplusplus >= 201703L
|
||||
#include <optional>
|
||||
#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ----------- #included from clara_textflow.hpp -----------
|
||||
|
||||
// TextFlowCpp
|
||||
@@ -389,11 +399,9 @@ namespace detail {
|
||||
std::vector<std::string> m_args;
|
||||
|
||||
public:
|
||||
Args( int argc, char *argv[] ) {
|
||||
m_exeName = argv[0];
|
||||
for( int i = 1; i < argc; ++i )
|
||||
m_args.push_back( argv[i] );
|
||||
}
|
||||
Args( int argc, char const* const* argv )
|
||||
: m_exeName(argv[0]),
|
||||
m_args(argv + 1, argv + argc) {}
|
||||
|
||||
Args( std::initializer_list<std::string> args )
|
||||
: m_exeName( *args.begin() ),
|
||||
@@ -580,15 +588,13 @@ namespace detail {
|
||||
|
||||
protected:
|
||||
void enforceOk() const override {
|
||||
// !TBD: If no exceptions, std::terminate here or something
|
||||
switch( m_type ) {
|
||||
case ResultBase::LogicError:
|
||||
throw std::logic_error( m_errorMessage );
|
||||
case ResultBase::RuntimeError:
|
||||
throw std::runtime_error( m_errorMessage );
|
||||
case ResultBase::Ok:
|
||||
break;
|
||||
}
|
||||
|
||||
// Errors shouldn't reach this point, but if they do
|
||||
// the actual error message will be in m_errorMessage
|
||||
assert( m_type != ResultBase::LogicError );
|
||||
assert( m_type != ResultBase::RuntimeError );
|
||||
if( m_type != ResultBase::Ok )
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::string m_errorMessage; // Only populated if resultType is an error
|
||||
@@ -658,6 +664,16 @@ namespace detail {
|
||||
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
}
|
||||
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
|
||||
template<typename T>
|
||||
inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
|
||||
T temp;
|
||||
auto result = convertInto( source, temp );
|
||||
if( result )
|
||||
target = std::move(temp);
|
||||
return result;
|
||||
}
|
||||
#endif // CLARA_CONFIG_OPTIONAL_TYPE
|
||||
|
||||
struct NonCopyable {
|
||||
NonCopyable() = default;
|
||||
@@ -670,12 +686,14 @@ namespace detail {
|
||||
struct BoundRef : NonCopyable {
|
||||
virtual ~BoundRef() = default;
|
||||
virtual auto isContainer() const -> bool { return false; }
|
||||
virtual auto isFlag() const -> bool { return false; }
|
||||
};
|
||||
struct BoundValueRefBase : BoundRef {
|
||||
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
|
||||
};
|
||||
struct BoundFlagRefBase : BoundRef {
|
||||
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
||||
virtual auto isFlag() const -> bool { return true; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -907,7 +925,7 @@ namespace detail {
|
||||
if( token.type != TokenType::Argument )
|
||||
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
|
||||
|
||||
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
|
||||
assert( !m_ref->isFlag() );
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
|
||||
|
||||
auto result = valueRef->setValue( remainingTokens->token );
|
||||
@@ -983,14 +1001,14 @@ namespace detail {
|
||||
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
|
||||
auto const &token = *remainingTokens;
|
||||
if( isMatch(token.token ) ) {
|
||||
if( auto flagRef = dynamic_cast<detail::BoundFlagRefBase*>( m_ref.get() ) ) {
|
||||
if( m_ref->isFlag() ) {
|
||||
auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
|
||||
auto result = flagRef->setFlag( true );
|
||||
if( !result )
|
||||
return InternalParseResult( result );
|
||||
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
||||
} else {
|
||||
assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
|
||||
++remainingTokens;
|
||||
if( !remainingTokens )
|
||||
|
@@ -35,6 +35,13 @@ namespace Detail {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
Approx Approx::operator-() const {
|
||||
auto temp(*this);
|
||||
temp.m_value = -temp.m_value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
std::string Approx::toString() const {
|
||||
ReusableStringStream rss;
|
||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
@@ -49,6 +56,15 @@ 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) {
|
||||
return value.toString();
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@ namespace Detail {
|
||||
|
||||
static Approx custom();
|
||||
|
||||
Approx operator-() const;
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx operator()( T const& value ) {
|
||||
Approx approx( static_cast<double>(value) );
|
||||
@@ -121,7 +123,12 @@ namespace Detail {
|
||||
double m_scale;
|
||||
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<>
|
||||
struct StringMaker<Catch::Detail::Approx> {
|
||||
|
@@ -18,9 +18,11 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
||||
expr.streamReconstructedExpression( os );
|
||||
return os;
|
||||
namespace {
|
||||
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
||||
expr.streamReconstructedExpression( os );
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
LazyExpression::LazyExpression( bool isNegated )
|
||||
|
@@ -65,9 +65,9 @@ namespace Catch {
|
||||
expr = m_info.capturedExpression;
|
||||
else {
|
||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||
expr += m_info.macroName.c_str();
|
||||
expr += m_info.macroName;
|
||||
expr += "( ";
|
||||
expr += m_info.capturedExpression.c_str();
|
||||
expr += m_info.capturedExpression;
|
||||
expr += " )";
|
||||
}
|
||||
return expr;
|
||||
|
@@ -115,7 +115,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( false )
|
||||
|
@@ -13,7 +13,7 @@ namespace Catch {
|
||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||
|
||||
// This is the general overload that takes a any string matcher
|
||||
// There is another overload, in catch_assertinhandler.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)
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
|
||||
std::string exceptionMessage = Catch::translateActiveException();
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_matchers.h"
|
||||
#include "catch_matchers_floating.h"
|
||||
#include "catch_matchers_generic.hpp"
|
||||
#include "catch_matchers_string.h"
|
||||
#include "catch_matchers_vector.h"
|
||||
|
||||
|
@@ -20,9 +20,19 @@ namespace Catch {
|
||||
using namespace clara;
|
||||
|
||||
auto const setWarning = [&]( std::string const& warning ) {
|
||||
if( warning != "NoAssertions" )
|
||||
auto warningSet = [&]() {
|
||||
if( warning == "NoAssertions" )
|
||||
return WarnAbout::NoAssertions;
|
||||
|
||||
if ( warning == "NoTests" )
|
||||
return WarnAbout::NoTests;
|
||||
|
||||
return WarnAbout::Nothing;
|
||||
}();
|
||||
|
||||
if (warningSet == WarnAbout::Nothing)
|
||||
return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
|
||||
@@ -120,7 +130,7 @@ namespace Catch {
|
||||
| Opt( config.outputFilename, "filename" )
|
||||
["-o"]["--out"]
|
||||
( "output filename" )
|
||||
| Opt( config.reporterNames, "name" )
|
||||
| Opt( config.reporterName, "name" )
|
||||
["-r"]["--reporter"]
|
||||
( "reporter to use (defaults to console)" )
|
||||
| Opt( config.name, "name" )
|
||||
|
@@ -24,6 +24,7 @@
|
||||
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
||||
// can be combined, en-mass, with the _NO_ forms later.
|
||||
|
||||
#include "catch_platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -31,6 +32,14 @@
|
||||
# define CATCH_CPP14_OR_GREATER
|
||||
# endif
|
||||
|
||||
# if __cplusplus >= 201703L
|
||||
# define CATCH_CPP17_OR_GREATER
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CPP17_OR_GREATER)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -48,17 +57,25 @@
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
_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__
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Assume that non-Windows platforms support posix signals by default
|
||||
#if !defined(CATCH_PLATFORM_WINDOWS)
|
||||
#define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// We know some environments not to support full POSIX signals
|
||||
#if defined(__CYGWIN__) || defined(__QNX__)
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||
# endif
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
|
||||
#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||
#endif
|
||||
|
||||
#ifdef __OS400__
|
||||
@@ -66,6 +83,24 @@
|
||||
# define CATCH_CONFIG_COLOUR_NONE
|
||||
#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
|
||||
#ifdef __CYGWIN__
|
||||
@@ -80,6 +115,11 @@
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
|
||||
|
||||
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
# endif
|
||||
|
||||
// Universal Windows platform does not support SEH
|
||||
// Or console colours (or console at all...)
|
||||
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
@@ -92,6 +132,13 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// DJGPP
|
||||
#ifdef __DJGPP__
|
||||
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
|
||||
#endif // __DJGPP__
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Use of __COUNTER__ is suppressed during code analysis in
|
||||
// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
|
||||
// handled by it.
|
||||
@@ -104,13 +151,33 @@
|
||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||
# define CATCH_CONFIG_COUNTER
|
||||
#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
|
||||
#endif
|
||||
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
||||
#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
# define CATCH_CONFIG_POSIX_SIGNALS
|
||||
#endif
|
||||
// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
|
||||
#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
|
||||
# define CATCH_CONFIG_WCHAR
|
||||
#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)
|
||||
# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#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_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
@@ -120,6 +187,10 @@
|
||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||
#endif
|
||||
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||
|
@@ -15,12 +15,16 @@ namespace Catch {
|
||||
: m_data( data ),
|
||||
m_stream( openStream() )
|
||||
{
|
||||
if( !data.testsOrTags.empty() ) {
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
TestSpecParser parser(ITagAliasRegistry::get());
|
||||
if (data.testsOrTags.empty()) {
|
||||
parser.parse("~[.]"); // All not hidden tests
|
||||
}
|
||||
else {
|
||||
m_hasTestFilters = true;
|
||||
for( auto const& testOrTags : data.testsOrTags )
|
||||
parser.parse( testOrTags );
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
|
||||
std::string const& Config::getFilename() const {
|
||||
@@ -33,11 +37,13 @@ namespace Catch {
|
||||
bool Config::listReporters() const { return m_data.listReporters; }
|
||||
|
||||
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::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
|
||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
@@ -46,7 +52,8 @@ namespace Catch {
|
||||
std::ostream& Config::stream() const { return m_stream->stream(); }
|
||||
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
|
||||
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
|
||||
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||
|
@@ -54,8 +54,12 @@ namespace Catch {
|
||||
std::string outputFilename;
|
||||
std::string name;
|
||||
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> sectionsToRun;
|
||||
};
|
||||
@@ -76,11 +80,13 @@ namespace Catch {
|
||||
bool listReporters() 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& getSectionsToRun() const override;
|
||||
|
||||
virtual TestSpec const& testSpec() const override;
|
||||
bool hasTestFilters() const override;
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
@@ -90,6 +96,7 @@ namespace Catch {
|
||||
std::string name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
bool warnAboutNoTests() const override;
|
||||
ShowDurations::OrNot showDurations() const override;
|
||||
RunTests::InWhatOrder runOrder() const override;
|
||||
unsigned int rngSeed() const override;
|
||||
@@ -107,6 +114,7 @@ namespace Catch {
|
||||
|
||||
std::unique_ptr<IStream const> m_stream;
|
||||
TestSpec m_testSpec;
|
||||
bool m_hasTestFilters = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -11,8 +11,8 @@
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_errno_guard.h"
|
||||
@@ -84,8 +84,12 @@ namespace {
|
||||
case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
|
||||
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
||||
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
||||
case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
|
||||
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
|
||||
default:
|
||||
CATCH_ERROR( "Unknown colour requested" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,8 +147,10 @@ namespace {
|
||||
case Colour::BrightRed: return setColour( "[1;31m" );
|
||||
case Colour::BrightGreen: return setColour( "[1;32m" );
|
||||
case Colour::BrightWhite: return setColour( "[1;37m" );
|
||||
case Colour::BrightYellow: return setColour( "[1;33m" );
|
||||
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
|
||||
}
|
||||
}
|
||||
static IColourImpl* instance() {
|
||||
@@ -163,7 +169,12 @@ namespace {
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
!isDebuggerActive() &&
|
||||
#endif
|
||||
isatty(STDOUT_FILENO);
|
||||
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
|
||||
isatty(STDOUT_FILENO)
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
;
|
||||
}
|
||||
IColourImpl* platformColourInstance() {
|
||||
ErrnoGuard guard;
|
||||
@@ -196,7 +207,7 @@ namespace Catch {
|
||||
namespace Catch {
|
||||
|
||||
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
||||
Colour::Colour( Colour&& rhs ) noexcept {
|
||||
Colour::Colour( Colour&& rhs ) noexcept {
|
||||
m_moved = rhs.m_moved;
|
||||
rhs.m_moved = true;
|
||||
}
|
||||
@@ -205,7 +216,7 @@ namespace Catch {
|
||||
rhs.m_moved = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
||||
|
||||
void Colour::use( Code _colourCode ) {
|
||||
|
@@ -30,10 +30,11 @@ namespace Catch {
|
||||
BrightGreen = Bright | Green,
|
||||
LightGrey = Bright | Grey,
|
||||
BrightWhite = Bright | White,
|
||||
BrightYellow = Bright | Yellow,
|
||||
|
||||
// By intention
|
||||
FileName = LightGrey,
|
||||
Warning = Yellow,
|
||||
Warning = BrightYellow,
|
||||
ResultError = BrightRed,
|
||||
ResultSuccess = BrightGreen,
|
||||
ResultExpectedFailure = Warning,
|
||||
@@ -42,7 +43,7 @@ namespace Catch {
|
||||
Success = Green,
|
||||
|
||||
OriginalExpression = Cyan,
|
||||
ReconstructedExpression = Yellow,
|
||||
ReconstructedExpression = BrightYellow,
|
||||
|
||||
SecondaryText = LightGrey,
|
||||
Headers = White
|
||||
|
@@ -9,21 +9,23 @@
|
||||
#include "catch_debug_console.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_platform.h"
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
namespace Catch {
|
||||
void writeToDebugConsole( std::string const& text ) {
|
||||
::OutputDebugStringA( text.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
void writeToDebugConsole( std::string const& text ) {
|
||||
// !TBD: Need a version for Mac/ XCode and other IDEs
|
||||
Catch::cout() << text;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // Platform
|
||||
|
@@ -40,7 +40,10 @@ namespace Catch {
|
||||
#ifdef CATCH_TRAP
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() (void)0, 0
|
||||
namespace Catch {
|
||||
inline void doNothing() {}
|
||||
}
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
||||
|
@@ -82,7 +82,7 @@ namespace Catch {
|
||||
|
||||
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); };
|
||||
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
|
||||
template<typename T>
|
||||
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
|
||||
template<typename T>
|
||||
@@ -93,7 +93,7 @@ namespace Catch {
|
||||
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
|
||||
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); };
|
||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
|
||||
template<typename T>
|
||||
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
|
||||
template<typename T>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#ifndef __OBJC__
|
||||
|
||||
#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||
// Standard C/C++ Win32 Unicode wmain entry point
|
||||
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||
#else
|
||||
|
@@ -11,10 +11,9 @@
|
||||
#include "catch_stream.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iosfwd>
|
||||
|
||||
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
||||
type( static_cast<std::ostringstream&&>( Catch::ReusableStringStream().get() << msg ).str() )
|
||||
type( ( Catch::ReusableStringStream() << msg ).str() )
|
||||
#define CATCH_INTERNAL_ERROR( msg ) \
|
||||
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
|
||||
#define CATCH_ERROR( msg ) \
|
||||
|
@@ -17,6 +17,8 @@
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace {
|
||||
// Report the error condition
|
||||
void reportFatal( char const * const message ) {
|
||||
@@ -24,15 +26,9 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
||||
#endif // signals/SEH handling
|
||||
|
||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
@@ -72,7 +68,6 @@ namespace Catch {
|
||||
|
||||
void FatalConditionHandler::reset() {
|
||||
if (isSet) {
|
||||
// Unregister handler and restore the old guarantee
|
||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
exceptionHandlerHandle = nullptr;
|
||||
@@ -91,20 +86,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
|
||||
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
||||
|
||||
#include <signal.h>
|
||||
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -112,6 +94,11 @@ namespace Catch {
|
||||
int id;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
// 32kb for the alternate stack seems to be sufficient. However, this value
|
||||
// is experimentally determined, so that's not guaranteed.
|
||||
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
|
||||
|
||||
static SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||
@@ -139,7 +126,7 @@ namespace Catch {
|
||||
isSet = true;
|
||||
stack_t sigStack;
|
||||
sigStack.ss_sp = altStackMem;
|
||||
sigStack.ss_size = SIGSTKSZ;
|
||||
sigStack.ss_size = sigStackSize;
|
||||
sigStack.ss_flags = 0;
|
||||
sigaltstack(&sigStack, &oldSigStack);
|
||||
struct sigaction sa = { };
|
||||
@@ -171,14 +158,18 @@ namespace Catch {
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||
stack_t FatalConditionHandler::oldSigStack = {};
|
||||
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
|
||||
char FatalConditionHandler::altStackMem[sigStackSize] = {};
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
#else
|
||||
|
||||
#endif // not Windows
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
#endif // signals/SEH handling
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
|
@@ -9,23 +9,12 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "catch_platform.h"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
|
||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -44,20 +33,7 @@ namespace Catch {
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
||||
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -66,7 +42,7 @@ namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
|
||||
static struct sigaction oldSigActions[];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[];
|
||||
|
||||
@@ -79,8 +55,15 @@ namespace Catch {
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#endif // not Windows
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
@@ -25,7 +25,8 @@ namespace Catch {
|
||||
|
||||
struct WarnAbout { enum What {
|
||||
Nothing = 0x00,
|
||||
NoAssertions = 0x01
|
||||
NoAssertions = 0x01,
|
||||
NoTests = 0x02
|
||||
}; };
|
||||
|
||||
struct ShowDurations { enum OrNot {
|
||||
@@ -62,10 +63,12 @@ namespace Catch {
|
||||
virtual bool includeSuccessfulResults() const = 0;
|
||||
virtual bool shouldDebugBreak() const = 0;
|
||||
virtual bool warnAboutMissingAssertions() const = 0;
|
||||
virtual bool warnAboutNoTests() const = 0;
|
||||
virtual int abortAfter() const = 0;
|
||||
virtual bool showInvisibles() const = 0;
|
||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual bool hasTestFilters() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual int benchmarkResolutionMultiple() const = 0;
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "catch_interfaces_reporter.h"
|
||||
#include "../reporters/catch_reporter_multi.h"
|
||||
#include "../reporters/catch_reporter_listening.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -111,25 +111,4 @@ namespace Catch {
|
||||
IReporterFactory::~IReporterFactory() = 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
|
||||
|
@@ -42,6 +42,7 @@ namespace Catch {
|
||||
|
||||
struct ReporterPreferences {
|
||||
bool shouldRedirectStdOut = false;
|
||||
bool shouldReportAllAssertions = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -226,8 +227,6 @@ namespace Catch {
|
||||
virtual Listeners const& getListeners() const = 0;
|
||||
};
|
||||
|
||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||
|
@@ -28,11 +28,10 @@ namespace Catch {
|
||||
|
||||
std::size_t listTests( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( config.testSpec().hasFilters() )
|
||||
if( config.hasTestFilters() )
|
||||
Catch::cout() << "Matching test cases:\n";
|
||||
else {
|
||||
Catch::cout() << "All available test cases:\n";
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
}
|
||||
|
||||
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||
@@ -54,7 +53,7 @@ namespace Catch {
|
||||
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
|
||||
}
|
||||
|
||||
if( !config.testSpec().hasFilters() )
|
||||
if( !config.hasTestFilters() )
|
||||
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
|
||||
else
|
||||
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
|
||||
@@ -63,8 +62,6 @@ namespace Catch {
|
||||
|
||||
std::size_t listTestsNamesOnly( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( !config.testSpec().hasFilters() )
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
std::size_t matchedTests = 0;
|
||||
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||
for( auto const& testCaseInfo : matchedTestCases ) {
|
||||
@@ -94,11 +91,10 @@ namespace Catch {
|
||||
|
||||
std::size_t listTags( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( config.testSpec().hasFilters() )
|
||||
if( config.hasTestFilters() )
|
||||
Catch::cout() << "Tags for matching test cases:\n";
|
||||
else {
|
||||
Catch::cout() << "All available tags:\n";
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
}
|
||||
|
||||
std::map<std::string, TagInfo> tagCounts;
|
||||
|
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "catch_matchers_floating.h"
|
||||
#include "catch_to_string.hpp"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <cstdlib>
|
||||
@@ -88,7 +89,7 @@ namespace Floating {
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
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 {
|
||||
@@ -115,7 +116,7 @@ namespace Floating {
|
||||
}
|
||||
|
||||
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
|
||||
|
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
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "catch_message.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_uncaught_exceptions.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -49,18 +50,9 @@ namespace Catch {
|
||||
getResultCapture().pushScopedMessage( m_info );
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
|
||||
#endif
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !std::uncaught_exception() ){
|
||||
if ( !uncaught_exceptions() ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -93,7 +93,7 @@ namespace Catch {
|
||||
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
139
include/internal/catch_output_redirect.cpp
Normal file
139
include/internal/catch_output_redirect.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 <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)) {
|
||||
throw std::runtime_error("Could not get a temp filename");
|
||||
}
|
||||
if (fopen_s(&m_file, m_buffer, "w")) {
|
||||
char buffer[100];
|
||||
if (strerror_s(buffer, errno)) {
|
||||
throw std::runtime_error("Could not translate errno to string");
|
||||
}
|
||||
throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer);
|
||||
}
|
||||
}
|
||||
#else
|
||||
TempFile::TempFile() {
|
||||
m_file = std::tmpfile();
|
||||
if (!m_file) {
|
||||
throw std::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__)
|
||||
# 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
|
||||
#endif
|
||||
|
||||
|
@@ -9,23 +9,21 @@
|
||||
#include "catch_context.h"
|
||||
#include "catch_interfaces_config.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
if( config.rngSeed() != 0 )
|
||||
std::srand( config.rngSeed() );
|
||||
std::mt19937& rng() {
|
||||
static std::mt19937 s_rng;
|
||||
return s_rng;
|
||||
}
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
if( config.rngSeed() != 0 ) {
|
||||
std::srand( config.rngSeed() );
|
||||
rng().seed( config.rngSeed() );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int 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
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct IConfig;
|
||||
|
||||
std::mt19937& rng();
|
||||
void seedRng( IConfig const& config );
|
||||
|
||||
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
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_random_number_generator.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_output_redirect.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
@@ -10,55 +11,13 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class RedirectedStream {
|
||||
std::ostream& m_originalStream;
|
||||
std::ostream& m_redirectionStream;
|
||||
std::streambuf* m_prevBuf;
|
||||
|
||||
public:
|
||||
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() {
|
||||
m_originalStream.rdbuf( m_prevBuf );
|
||||
}
|
||||
};
|
||||
|
||||
class RedirectedStdOut {
|
||||
ReusableStringStream m_rss;
|
||||
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
|
||||
// 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()
|
||||
: m_cerr( Catch::cerr(), m_rss.get() ),
|
||||
m_clog( Catch::clog(), m_rss.get() )
|
||||
{}
|
||||
auto str() const -> std::string { return m_rss.str(); }
|
||||
};
|
||||
|
||||
|
||||
RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
|
||||
: m_runInfo(_config->name()),
|
||||
m_context(getCurrentMutableContext()),
|
||||
m_config(_config),
|
||||
m_reporter(std::move(reporter)),
|
||||
m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal },
|
||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() )
|
||||
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
|
||||
{
|
||||
m_context.setRunner(this);
|
||||
m_context.setConfig(m_config);
|
||||
@@ -84,7 +43,7 @@ namespace Catch {
|
||||
std::string redirectedCout;
|
||||
std::string redirectedCerr;
|
||||
|
||||
TestCaseInfo testInfo = testCase.getTestCaseInfo();
|
||||
auto const& testInfo = testCase.getTestCaseInfo();
|
||||
|
||||
m_reporter->testCaseStarting(testInfo);
|
||||
|
||||
@@ -249,7 +208,7 @@ namespace Catch {
|
||||
|
||||
// Recreate section for test case (as we will lose the one that was in scope)
|
||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
|
||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||
|
||||
Counts assertions;
|
||||
assertions.failed = 1;
|
||||
@@ -287,25 +246,31 @@ namespace Catch {
|
||||
|
||||
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
|
||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
|
||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||
m_reporter->sectionStarting(testCaseSection);
|
||||
Counts prevAssertions = m_totals.assertions;
|
||||
double duration = 0;
|
||||
m_shouldReportUnexpected = true;
|
||||
m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal };
|
||||
m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
|
||||
|
||||
seedRng(*m_config);
|
||||
|
||||
Timer timer;
|
||||
try {
|
||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
||||
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||
RedirectedStdOut redirectedStdOut;
|
||||
RedirectedStdErr redirectedStdErr;
|
||||
|
||||
timer.start();
|
||||
invokeActiveTestCase();
|
||||
redirectedCout += redirectedStdOut.str();
|
||||
redirectedCerr += redirectedStdErr.str();
|
||||
|
||||
#else
|
||||
OutputRedirect r(redirectedCout, redirectedCerr);
|
||||
timer.start();
|
||||
invokeActiveTestCase();
|
||||
#endif
|
||||
} else {
|
||||
timer.start();
|
||||
invokeActiveTestCase();
|
||||
@@ -321,12 +286,13 @@ namespace Catch {
|
||||
handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
|
||||
}
|
||||
}
|
||||
Counts assertions = m_totals.assertions - prevAssertions;
|
||||
bool missingAssertions = testForMissingAssertions(assertions);
|
||||
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
m_messages.clear();
|
||||
|
||||
Counts assertions = m_totals.assertions - prevAssertions;
|
||||
bool missingAssertions = testForMissingAssertions(assertions);
|
||||
SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
|
||||
m_reporter->sectionEnded(testCaseSectionStats);
|
||||
}
|
||||
|
@@ -99,7 +99,7 @@ namespace Catch {
|
||||
|
||||
public:
|
||||
// !TBD We need to do this another way!
|
||||
bool aborting() const override;
|
||||
bool aborting() const final;
|
||||
|
||||
private:
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "catch_section.h"
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_uncaught_exceptions.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -18,22 +19,15 @@ namespace Catch {
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
|
||||
#endif
|
||||
Section::~Section() {
|
||||
if( m_sectionIncluded ) {
|
||||
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
||||
if( std::uncaught_exception() )
|
||||
SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
|
||||
if( uncaught_exceptions() )
|
||||
getResultCapture().sectionEndedEarly( endInfo );
|
||||
else
|
||||
getResultCapture().sectionEnded( endInfo );
|
||||
}
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// This indicates whether the section should be executed or not
|
||||
Section::operator bool() const {
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
|
||||
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_section_info.h"
|
||||
#include "catch_totals.h"
|
||||
#include "catch_timer.h"
|
||||
@@ -35,7 +36,14 @@ namespace Catch {
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_SECTION( ... ) \
|
||||
if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
|
||||
#define INTERNAL_CATCH_SECTION( ... ) \
|
||||
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
|
||||
|
@@ -11,15 +11,9 @@ namespace Catch {
|
||||
|
||||
SectionInfo::SectionInfo
|
||||
( SourceLineInfo const& _lineInfo,
|
||||
std::string const& _name,
|
||||
std::string const& _description )
|
||||
std::string const& _name )
|
||||
: name( _name ),
|
||||
description( _description ),
|
||||
lineInfo( _lineInfo )
|
||||
{}
|
||||
|
||||
SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
|
||||
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
||||
{}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -16,19 +16,22 @@
|
||||
namespace Catch {
|
||||
|
||||
struct SectionInfo {
|
||||
SectionInfo
|
||||
( SourceLineInfo const& _lineInfo,
|
||||
std::string const& _name );
|
||||
|
||||
// Deprecated
|
||||
SectionInfo
|
||||
( SourceLineInfo const& _lineInfo,
|
||||
std::string const& _name,
|
||||
std::string const& _description = std::string() );
|
||||
std::string const& ) : SectionInfo( _lineInfo, _name ) {}
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string description; // !Deprecated: this will always be empty
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
struct SectionEndInfo {
|
||||
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds );
|
||||
|
||||
SectionInfo sectionInfo;
|
||||
Counts prevAssertions;
|
||||
double durationInSeconds;
|
||||
|
@@ -18,6 +18,9 @@
|
||||
#include "catch_random_number_generator.h"
|
||||
#include "catch_startup_exception_registry.h"
|
||||
#include "catch_text.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_windows_h_proxy.h"
|
||||
#include "../reporters/catch_reporter_listening.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
@@ -34,33 +37,26 @@ namespace Catch {
|
||||
return reporter;
|
||||
}
|
||||
|
||||
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
||||
#endif
|
||||
|
||||
IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
|
||||
auto const& reporterNames = config->getReporterNames();
|
||||
if (reporterNames.empty())
|
||||
return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config);
|
||||
if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
|
||||
return createReporter(config->getReporterName(), config);
|
||||
}
|
||||
|
||||
IStreamingReporterPtr reporter;
|
||||
for (auto const& name : reporterNames)
|
||||
addReporter(reporter, createReporter(name, config));
|
||||
return reporter;
|
||||
}
|
||||
auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
|
||||
|
||||
#undef CATCH_CONFIG_DEFAULT_REPORTER
|
||||
|
||||
void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
|
||||
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
|
||||
for (auto const& listener : listeners)
|
||||
addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
|
||||
for (auto const& listener : listeners) {
|
||||
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) {
|
||||
IStreamingReporterPtr reporter = makeReporter(config);
|
||||
addListeners(reporter, config);
|
||||
// FixMe: Add listeners in order first, then add reporters.
|
||||
|
||||
auto reporter = makeReporter(config);
|
||||
|
||||
RunContext context(config, std::move(reporter));
|
||||
|
||||
@@ -69,8 +65,6 @@ namespace Catch {
|
||||
context.testGroupStarting(config->name(), 1, 1);
|
||||
|
||||
TestSpec testSpec = config->testSpec();
|
||||
if (!testSpec.hasFilters())
|
||||
testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
|
||||
|
||||
auto const& allTestCases = getAllTestCasesSorted(*config);
|
||||
for (auto const& testCase : allTestCases) {
|
||||
@@ -80,6 +74,20 @@ namespace Catch {
|
||||
context.reporter().skipTest(testCase);
|
||||
}
|
||||
|
||||
if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
|
||||
ReusableStringStream testConfig;
|
||||
|
||||
bool first = true;
|
||||
for (const auto& input : config->getTestsOrTags()) {
|
||||
if (!first) { testConfig << ' '; }
|
||||
first = false;
|
||||
testConfig << input;
|
||||
}
|
||||
|
||||
context.reporter().noMatchingTestCases(testConfig.str());
|
||||
totals.error = -1;
|
||||
}
|
||||
|
||||
context.testGroupEnded(config->name(), totals, 1, 1);
|
||||
return totals;
|
||||
}
|
||||
@@ -119,7 +127,7 @@ namespace Catch {
|
||||
if ( !exceptions.empty() ) {
|
||||
m_startupExceptions = true;
|
||||
Colour colourGuard( Colour::Red );
|
||||
Catch::cerr() << "Errors occured during startup!" << '\n';
|
||||
Catch::cerr() << "Errors occurred during startup!" << '\n';
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
@@ -151,7 +159,7 @@ namespace Catch {
|
||||
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
|
||||
}
|
||||
|
||||
int Session::applyCommandLine( int argc, char* argv[] ) {
|
||||
int Session::applyCommandLine( int argc, char const * const * argv ) {
|
||||
if( m_startupExceptions )
|
||||
return 1;
|
||||
|
||||
@@ -188,7 +196,7 @@ namespace Catch {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
|
||||
int Session::run( int argc, wchar_t* const argv[] ) {
|
||||
|
||||
char **utf8Argv = new char *[ argc ];
|
||||
@@ -259,10 +267,11 @@ namespace Catch {
|
||||
if( Option<std::size_t> listed = list( config() ) )
|
||||
return static_cast<int>( *listed );
|
||||
|
||||
auto totals = runTests( m_config );
|
||||
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||
// the return value to 255 prevents false negative when some multiple
|
||||
// of 256 tests has failed
|
||||
return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
|
||||
return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
Catch::cerr() << ex.what() << std::endl;
|
||||
|
@@ -25,12 +25,12 @@ namespace Catch {
|
||||
void showHelp() const;
|
||||
void libIdentify();
|
||||
|
||||
int applyCommandLine( int argc, char* argv[] );
|
||||
int applyCommandLine( int argc, char const * const * argv );
|
||||
|
||||
void useConfigData( ConfigData const& configData );
|
||||
|
||||
int run( int argc, char* argv[] );
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
|
||||
int run( int argc, wchar_t* const argv[] );
|
||||
#endif
|
||||
int run();
|
||||
|
@@ -14,6 +14,12 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
namespace {
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( std::tolower( c ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||
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 ) {
|
||||
return s.find( infix ) != std::string::npos;
|
||||
}
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( std::tolower( c ) );
|
||||
}
|
||||
void toLowerInPlace( std::string& s ) {
|
||||
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
|
||||
}
|
||||
|
@@ -15,6 +15,13 @@
|
||||
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
const uint32_t byte_2_lead = 0xC0;
|
||||
const uint32_t byte_3_lead = 0xE0;
|
||||
const uint32_t byte_4_lead = 0xF0;
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
StringRef::StringRef( char const* rawChars ) noexcept
|
||||
@@ -36,7 +43,7 @@ namespace Catch {
|
||||
const_cast<StringRef*>( this )->takeOwnership();
|
||||
return m_start;
|
||||
}
|
||||
auto StringRef::data() const noexcept -> char const* {
|
||||
auto StringRef::currentData() const noexcept -> char const* {
|
||||
return m_start;
|
||||
}
|
||||
|
||||
@@ -79,13 +86,12 @@ namespace Catch {
|
||||
// Make adjustments for uft encodings
|
||||
for( size_type i=0; i < m_size; ++i ) {
|
||||
char c = m_start[i];
|
||||
if( ( c & 0b11000000 ) == 0b11000000 ) {
|
||||
if( ( c & 0b11100000 ) == 0b11000000 )
|
||||
if( ( c & byte_2_lead ) == byte_2_lead ) {
|
||||
noChars--;
|
||||
if (( c & byte_3_lead ) == byte_3_lead )
|
||||
noChars--;
|
||||
if( ( c & byte_4_lead ) == byte_4_lead )
|
||||
noChars--;
|
||||
else if( ( c & 0b11110000 ) == 0b11100000 )
|
||||
noChars-=2;
|
||||
else if( ( c & 0b11111000 ) == 0b11110000 )
|
||||
noChars-=3;
|
||||
}
|
||||
}
|
||||
return noChars;
|
||||
@@ -106,7 +112,12 @@ namespace Catch {
|
||||
}
|
||||
|
||||
auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
|
||||
return os << str.c_str();
|
||||
return os.write(str.currentData(), str.size());
|
||||
}
|
||||
|
||||
auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
|
||||
lhs.append(rhs.currentData(), rhs.size());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#include <iosfwd>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
||||
class StringData;
|
||||
|
||||
/// A non-owning string class (similar to the forthcoming std::string_view)
|
||||
@@ -31,13 +31,13 @@ namespace Catch {
|
||||
|
||||
char const* m_start;
|
||||
size_type m_size;
|
||||
|
||||
|
||||
char* m_data = nullptr;
|
||||
|
||||
|
||||
void takeOwnership();
|
||||
|
||||
static constexpr char const* const s_empty = "";
|
||||
|
||||
|
||||
public: // construction/ assignment
|
||||
StringRef() noexcept
|
||||
: StringRef( s_empty, 0 )
|
||||
@@ -83,13 +83,13 @@ namespace Catch {
|
||||
operator std::string() const;
|
||||
|
||||
void swap( StringRef& other ) noexcept;
|
||||
|
||||
|
||||
public: // operators
|
||||
auto operator == ( StringRef const& other ) const noexcept -> bool;
|
||||
auto operator != ( StringRef const& other ) const noexcept -> bool;
|
||||
|
||||
|
||||
auto operator[] ( size_type index ) const noexcept -> char;
|
||||
|
||||
|
||||
public: // named queries
|
||||
auto empty() const noexcept -> bool {
|
||||
return m_size == 0;
|
||||
@@ -100,22 +100,27 @@ namespace Catch {
|
||||
|
||||
auto numberOfCharacters() const noexcept -> size_type;
|
||||
auto c_str() const -> char const*;
|
||||
|
||||
|
||||
public: // substrings and searches
|
||||
auto substr( size_type start, size_type size ) const noexcept -> StringRef;
|
||||
|
||||
// Returns the current start pointer.
|
||||
// Note that the pointer can change when if the StringRef is a substring
|
||||
auto currentData() const noexcept -> char const*;
|
||||
|
||||
private: // ownership queries - may not be consistent between calls
|
||||
auto isOwned() const noexcept -> bool;
|
||||
auto isSubstring() const noexcept -> bool;
|
||||
auto data() const noexcept -> char const*;
|
||||
};
|
||||
|
||||
auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
|
||||
auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
|
||||
auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
|
||||
|
||||
auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
|
||||
auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
|
||||
|
||||
|
||||
inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
|
||||
return StringRef( rawChars, size );
|
||||
}
|
||||
|
@@ -10,15 +10,17 @@
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 161 1682)
|
||||
# else // __ICC
|
||||
# pragma clang diagnostic ignored "-Wunused-variable"
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wpadded"
|
||||
# pragma clang diagnostic ignored "-Wswitch-enum"
|
||||
# pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
# endif
|
||||
#elif defined __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
// GCC likes to warn on REQUIREs, and we cannot suppress them
|
||||
// locally because g++'s support for _Pragma is lacking in older,
|
||||
// still supported, versions
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
@@ -19,37 +19,38 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
||||
if( startsWith( tag, '.' ) ||
|
||||
tag == "!hide" )
|
||||
return TestCaseInfo::IsHidden;
|
||||
else if( tag == "!throws" )
|
||||
return TestCaseInfo::Throws;
|
||||
else if( tag == "!shouldfail" )
|
||||
return TestCaseInfo::ShouldFail;
|
||||
else if( tag == "!mayfail" )
|
||||
return TestCaseInfo::MayFail;
|
||||
else if( tag == "!nonportable" )
|
||||
return TestCaseInfo::NonPortable;
|
||||
else if( tag == "!benchmark" )
|
||||
return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
|
||||
else
|
||||
return TestCaseInfo::None;
|
||||
}
|
||||
bool isReservedTag( std::string const& tag ) {
|
||||
return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
|
||||
}
|
||||
void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
|
||||
CATCH_ENFORCE( !isReservedTag(tag),
|
||||
"Tag name: [" << tag << "] is not allowed.\n"
|
||||
<< "Tag names starting with non alpha-numeric characters are reserved\n"
|
||||
<< _lineInfo );
|
||||
namespace {
|
||||
TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
||||
if( startsWith( tag, '.' ) ||
|
||||
tag == "!hide" )
|
||||
return TestCaseInfo::IsHidden;
|
||||
else if( tag == "!throws" )
|
||||
return TestCaseInfo::Throws;
|
||||
else if( tag == "!shouldfail" )
|
||||
return TestCaseInfo::ShouldFail;
|
||||
else if( tag == "!mayfail" )
|
||||
return TestCaseInfo::MayFail;
|
||||
else if( tag == "!nonportable" )
|
||||
return TestCaseInfo::NonPortable;
|
||||
else if( tag == "!benchmark" )
|
||||
return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
|
||||
else
|
||||
return TestCaseInfo::None;
|
||||
}
|
||||
bool isReservedTag( std::string const& tag ) {
|
||||
return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
|
||||
}
|
||||
void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
|
||||
CATCH_ENFORCE( !isReservedTag(tag),
|
||||
"Tag name: [" << tag << "] is not allowed.\n"
|
||||
<< "Tag names starting with non alpha-numeric characters are reserved\n"
|
||||
<< _lineInfo );
|
||||
}
|
||||
}
|
||||
|
||||
TestCase makeTestCase( ITestInvoker* _testCase,
|
||||
std::string const& _className,
|
||||
std::string const& _name,
|
||||
std::string const& _descOrTags,
|
||||
NameAndTags const& nameAndTags,
|
||||
SourceLineInfo const& _lineInfo )
|
||||
{
|
||||
bool isHidden = false;
|
||||
@@ -58,6 +59,7 @@ namespace Catch {
|
||||
std::vector<std::string> tags;
|
||||
std::string desc, tag;
|
||||
bool inTag = false;
|
||||
std::string _descOrTags = nameAndTags.tags;
|
||||
for (char c : _descOrTags) {
|
||||
if( !inTag ) {
|
||||
if( c == '[' )
|
||||
@@ -85,8 +87,8 @@ namespace Catch {
|
||||
tags.push_back( "." );
|
||||
}
|
||||
|
||||
TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
|
||||
return TestCase( _testCase, info );
|
||||
TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
|
||||
return TestCase( _testCase, std::move(info) );
|
||||
}
|
||||
|
||||
void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
|
||||
@@ -147,7 +149,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
|
||||
TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
|
||||
TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
|
||||
|
||||
|
||||
TestCase TestCase::withName( std::string const& _newName ) const {
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
#include "catch_test_registry.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -61,7 +62,7 @@ namespace Catch {
|
||||
class TestCase : public TestCaseInfo {
|
||||
public:
|
||||
|
||||
TestCase( ITestInvoker* testCase, TestCaseInfo const& info );
|
||||
TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
|
||||
|
||||
TestCase withName( std::string const& _newName ) const;
|
||||
|
||||
@@ -78,8 +79,7 @@ namespace Catch {
|
||||
|
||||
TestCase makeTestCase( ITestInvoker* testCase,
|
||||
std::string const& className,
|
||||
std::string const& name,
|
||||
std::string const& description,
|
||||
NameAndTags const& nameAndTags,
|
||||
SourceLineInfo const& lineInfo );
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,7 @@ namespace Catch {
|
||||
break;
|
||||
case RunTests::InRandomOrder:
|
||||
seedRng( config );
|
||||
RandomNumberGenerator::shuffle( sorted );
|
||||
std::shuffle( sorted.begin(), sorted.end(), rng() );
|
||||
break;
|
||||
case RunTests::InDeclarationOrder:
|
||||
// already in declaration order
|
||||
@@ -96,7 +96,7 @@ namespace Catch {
|
||||
m_testAsFunction();
|
||||
}
|
||||
|
||||
std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
||||
std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
|
||||
std::string className = classOrQualifiedMethodName;
|
||||
if( startsWith( className, '&' ) )
|
||||
{
|
||||
|
@@ -22,7 +22,7 @@ namespace Catch {
|
||||
class TestCase;
|
||||
struct IConfig;
|
||||
|
||||
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
|
||||
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
|
||||
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
|
||||
|
||||
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
|
||||
@@ -58,7 +58,7 @@ namespace Catch {
|
||||
};
|
||||
|
||||
|
||||
std::string extractClassName( std::string const& classOrQualifiedMethodName );
|
||||
std::string extractClassName( StringRef const& classOrQualifiedMethodName );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#include "catch_enforce.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -73,8 +73,8 @@ namespace TestCaseTracking {
|
||||
TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
|
||||
bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const {
|
||||
return
|
||||
tracker->nameAndLocation().name == m_nameAndLocation.name &&
|
||||
tracker->nameAndLocation().location == m_nameAndLocation.location;
|
||||
tracker->nameAndLocation().location == m_nameAndLocation.location &&
|
||||
tracker->nameAndLocation().name == m_nameAndLocation.name;
|
||||
}
|
||||
|
||||
TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
|
@@ -15,23 +15,22 @@ namespace Catch {
|
||||
return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
|
||||
}
|
||||
|
||||
NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
|
||||
NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
|
||||
|
||||
AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
|
||||
AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
|
||||
try {
|
||||
getMutableRegistryHub()
|
||||
.registerTest(
|
||||
makeTestCase(
|
||||
invoker,
|
||||
extractClassName( classOrMethod ),
|
||||
nameAndTags.name,
|
||||
nameAndTags.tags,
|
||||
nameAndTags,
|
||||
lineInfo));
|
||||
} catch (...) {
|
||||
// Do not throw when constructing global objects, instead register the exception to be processed later
|
||||
getMutableRegistryHub().registerStartupException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AutoReg::~AutoReg() = default;
|
||||
}
|
||||
|
@@ -35,24 +35,29 @@ auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
|
||||
}
|
||||
|
||||
struct NameAndTags {
|
||||
NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept;
|
||||
NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
|
||||
StringRef name;
|
||||
StringRef tags;
|
||||
};
|
||||
|
||||
struct AutoReg : NonCopyable {
|
||||
AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
|
||||
AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
|
||||
~AutoReg();
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
|
||||
#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
|
||||
#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
|
||||
#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
|
||||
|
||||
#if defined(CATCH_CONFIG_DISABLE)
|
||||
#define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
|
||||
namespace{ \
|
||||
struct TestName : ClassName { \
|
||||
struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
|
||||
void test(); \
|
||||
}; \
|
||||
} \
|
||||
@@ -64,7 +69,7 @@ struct AutoReg : NonCopyable {
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
|
||||
static void TestName(); \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( ... ) \
|
||||
@@ -80,7 +85,7 @@ struct AutoReg : NonCopyable {
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ \
|
||||
struct TestName : ClassName{ \
|
||||
struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \
|
||||
void test(); \
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||
@@ -93,7 +98,7 @@ struct AutoReg : NonCopyable {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||
|
||||
|
||||
|
@@ -10,32 +10,44 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
static const uint64_t nanosecondsInSecond = 1000000000;
|
||||
|
||||
namespace Catch {
|
||||
|
||||
auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
||||
}
|
||||
|
||||
auto estimateClockResolution() -> uint64_t {
|
||||
uint64_t sum = 0;
|
||||
static const uint64_t iterations = 1000000;
|
||||
namespace {
|
||||
auto estimateClockResolution() -> uint64_t {
|
||||
uint64_t sum = 0;
|
||||
static const uint64_t iterations = 1000000;
|
||||
|
||||
for( std::size_t i = 0; i < iterations; ++i ) {
|
||||
auto startTime = getCurrentNanosecondsSinceEpoch();
|
||||
|
||||
uint64_t ticks;
|
||||
uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
|
||||
do {
|
||||
ticks = getCurrentNanosecondsSinceEpoch();
|
||||
for( std::size_t i = 0; i < iterations; ++i ) {
|
||||
|
||||
uint64_t ticks;
|
||||
uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
|
||||
do {
|
||||
ticks = getCurrentNanosecondsSinceEpoch();
|
||||
} while( ticks == baseTicks );
|
||||
|
||||
auto delta = ticks - baseTicks;
|
||||
sum += delta;
|
||||
|
||||
// If we have been calibrating for over 3 seconds -- the clock
|
||||
// is terrible and we should move on.
|
||||
// TBD: How to signal that the measured resolution is probably wrong?
|
||||
if (ticks > startTime + 3 * nanosecondsInSecond) {
|
||||
return sum / i;
|
||||
}
|
||||
}
|
||||
while( ticks == baseTicks );
|
||||
|
||||
auto delta = ticks - baseTicks;
|
||||
sum += delta;
|
||||
// We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
|
||||
// - and potentially do more iterations if there's a high variance.
|
||||
return sum/iterations;
|
||||
}
|
||||
|
||||
// We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
|
||||
// - and potentially do more iterations if there's a high variance.
|
||||
return sum/iterations;
|
||||
}
|
||||
auto getEstimatedClockResolution() -> uint64_t {
|
||||
static auto s_resolution = estimateClockResolution();
|
||||
|
28
include/internal/catch_to_string.hpp
Normal file
28
include/internal/catch_to_string.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Created by Martin on 9/5/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_TO_STRING_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_stream.h"
|
||||
|
||||
namespace Catch {
|
||||
template <typename T>
|
||||
std::string to_string(T const& t) {
|
||||
#if defined(CATCH_CONFIG_CPP11_TO_STRING)
|
||||
return std::to_string(t);
|
||||
#else
|
||||
ReusableStringStream rss;
|
||||
rss << t;
|
||||
return rss.str();
|
||||
#endif
|
||||
}
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TO_STRING_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