mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-13 08:55:39 +02:00
Compare commits
258 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
03d122a35c | ||
![]() |
1d9b506e39 | ||
![]() |
779e83bc20 | ||
![]() |
544c7d7cbf | ||
![]() |
8b3c09c137 | ||
![]() |
b7f41237b1 | ||
![]() |
1faccd601d | ||
![]() |
ab98afe68b | ||
![]() |
054d356332 | ||
![]() |
0144ae9ad2 | ||
![]() |
e1307016f0 | ||
![]() |
6b9ca0888a | ||
![]() |
9f8b848fe5 | ||
![]() |
aaaac35d92 | ||
![]() |
6cede0101a | ||
![]() |
f1faaa9c10 | ||
![]() |
9e1bdca466 | ||
![]() |
be49a539e4 | ||
![]() |
558bbe7d24 | ||
![]() |
f4881f172a | ||
![]() |
de06340e7d | ||
![]() |
4dd6e81d0f | ||
![]() |
9e6d7bbf00 | ||
![]() |
dfb025cf08 | ||
![]() |
c638c57209 | ||
![]() |
a575536abe | ||
![]() |
1eb42eed97 | ||
![]() |
46e99e258f | ||
![]() |
a212fb440b | ||
![]() |
1e98c820bb | ||
![]() |
bcfa9b1775 | ||
![]() |
a3876adba6 | ||
![]() |
2a4725b40e | ||
![]() |
a81c01d4f9 | ||
![]() |
60b05b2041 | ||
![]() |
232ea3c456 | ||
![]() |
a5c900d077 | ||
![]() |
8b01883854 | ||
![]() |
86da2846af | ||
![]() |
ef9150fe6f | ||
![]() |
84fa76e985 | ||
![]() |
fcd91c7d6b | ||
![]() |
efbf50fc7d | ||
![]() |
64fd5b8058 | ||
![]() |
ee73989f9b | ||
![]() |
646e1f608d | ||
![]() |
6f75acbfb5 | ||
![]() |
9c3cc4a076 | ||
![]() |
f3972f0695 | ||
![]() |
38e1731f69 | ||
![]() |
0947752a44 | ||
![]() |
0646e0283c | ||
![]() |
90663b2e75 | ||
![]() |
7667a7d89c | ||
![]() |
9773d89ab4 | ||
![]() |
2067c8d3bd | ||
![]() |
1742ab76a2 | ||
![]() |
898d111f72 | ||
![]() |
5202993555 | ||
![]() |
f061dabbad | ||
![]() |
1a501fcb48 | ||
![]() |
94121a5f6d | ||
![]() |
92e25049cf | ||
![]() |
fdcd46420e | ||
![]() |
7c25dae9ea | ||
![]() |
7f18282d17 | ||
![]() |
1cdaa48a0b | ||
![]() |
1a63fad8d6 | ||
![]() |
d6f2fd486c | ||
![]() |
5884ec1e28 | ||
![]() |
eb783fc20e | ||
![]() |
38248f3f2c | ||
![]() |
c9de7dd12d | ||
![]() |
52cbb507ab | ||
![]() |
83bfae1a50 | ||
![]() |
f7f592dfc9 | ||
![]() |
78804ea304 | ||
![]() |
b93284716e | ||
![]() |
15cf3caace | ||
![]() |
12a8dfa2f2 | ||
![]() |
797d3b04df | ||
![]() |
82b8744b8c | ||
![]() |
ce80358306 | ||
![]() |
283e2e6d41 | ||
![]() |
d6c7392b24 | ||
![]() |
9ee4c1db52 | ||
![]() |
76790604f5 | ||
![]() |
e21c6aa94d | ||
![]() |
7a59d5027f | ||
![]() |
c8941cccb5 | ||
![]() |
5eeb6aa361 | ||
![]() |
1c1b447ede | ||
![]() |
e1d81174db | ||
![]() |
4846ad59e1 | ||
![]() |
ff2b3c85a7 | ||
![]() |
b55424d3b2 | ||
![]() |
e69c7ce297 | ||
![]() |
7be8ba36c1 | ||
![]() |
ad120965cf | ||
![]() |
f460a7d8f9 | ||
![]() |
ebf89000f1 | ||
![]() |
7d00cb83f1 | ||
![]() |
e69afb6252 | ||
![]() |
9fb38fcc14 | ||
![]() |
0f49a600b0 | ||
![]() |
5c0efa1cfc | ||
![]() |
1579744ddd | ||
![]() |
9b0e740e31 | ||
![]() |
1af60ef5ab | ||
![]() |
3743295ca8 | ||
![]() |
ed582bde4d | ||
![]() |
6c1145d922 | ||
![]() |
b957eb4172 | ||
![]() |
0eb99fb569 | ||
![]() |
bf221583b1 | ||
![]() |
44722f9ed3 | ||
![]() |
35a57b070f | ||
![]() |
1dce91d78e | ||
![]() |
b8553d62a3 | ||
![]() |
504607701b | ||
![]() |
788f81230f | ||
![]() |
c5301bf8bf | ||
![]() |
d2a130f243 | ||
![]() |
7be8a41adf | ||
![]() |
021fcee636 | ||
![]() |
3a47b8b072 | ||
![]() |
2771a8ee9a | ||
![]() |
7abd7db2c8 | ||
![]() |
88d7b8da25 | ||
![]() |
df0b0e64e1 | ||
![]() |
4c7b7d04fe | ||
![]() |
90988f578c | ||
![]() |
e5fe3e877a | ||
![]() |
6c5c4c43a0 | ||
![]() |
c323658483 | ||
![]() |
db570b7e24 | ||
![]() |
0074926e5c | ||
![]() |
6496c51c95 | ||
![]() |
3dd523bdf5 | ||
![]() |
8d5d49299b | ||
![]() |
d0287e3b56 | ||
![]() |
dd99a66cf4 | ||
![]() |
ae590fe216 | ||
![]() |
7f791fa08f | ||
![]() |
0510d4755f | ||
![]() |
e92b9c07c3 | ||
![]() |
88a6ff0b65 | ||
![]() |
9e7c281e6e | ||
![]() |
64be2ad96c | ||
![]() |
c651f239f0 | ||
![]() |
43769a19f7 | ||
![]() |
200d3ad824 | ||
![]() |
aa7b0c9104 | ||
![]() |
375f2052bd | ||
![]() |
dc6b83bec9 | ||
![]() |
f00257e374 | ||
![]() |
414dcae34a | ||
![]() |
d2d8455b57 | ||
![]() |
ab30621138 | ||
![]() |
1ca8f43b01 | ||
![]() |
dfb83f20e9 | ||
![]() |
319bddd5b8 | ||
![]() |
931441251e | ||
![]() |
ea1f326261 | ||
![]() |
3641706923 | ||
![]() |
3b801c4fda | ||
![]() |
e11508b48a | ||
![]() |
886d799b79 | ||
![]() |
8b78087412 | ||
![]() |
6c99b04c87 | ||
![]() |
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 | ||
![]() |
62dae592c3 | ||
![]() |
9a5705411a | ||
![]() |
a1aefce6e4 | ||
![]() |
d5959907f5 | ||
![]() |
31e6499e64 | ||
![]() |
b0f4f16ee0 | ||
![]() |
1e3ddbb496 | ||
![]() |
15ad95c8db | ||
![]() |
00a10d5a5e | ||
![]() |
0d687a15d3 | ||
![]() |
bdf431c400 | ||
![]() |
a0359980f0 | ||
![]() |
8d4074aad9 | ||
![]() |
f0f40a0dbf | ||
![]() |
fa4fd7f296 | ||
![]() |
07c84adfba | ||
![]() |
8d854c689b | ||
![]() |
f0909dfe02 | ||
![]() |
de36b2ada6 | ||
![]() |
9700ee4fc0 | ||
![]() |
bbda8cd77c | ||
![]() |
4575594bbf | ||
![]() |
c053dca26e | ||
![]() |
3d7104c124 | ||
![]() |
6441c20a2c | ||
![]() |
5774c4f9c2 | ||
![]() |
2bc33dd04d |
13
.gitattributes
vendored
13
.gitattributes
vendored
@@ -8,4 +8,15 @@
|
|||||||
*.hpp text
|
*.hpp text
|
||||||
|
|
||||||
# Windows specific files should retain windows line-endings
|
# Windows specific files should retain windows line-endings
|
||||||
*.sln text eol=crlf
|
*.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
|
||||||
|
196
.travis.yml
196
.travis.yml
@@ -1,12 +1,17 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
|
branches:
|
||||||
|
except:
|
||||||
|
- /dev-appveyor.*/
|
||||||
|
|
||||||
common_sources: &all_sources
|
common_sources: &all_sources
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-trusty
|
- llvm-toolchain-trusty
|
||||||
- llvm-toolchain-trusty-3.9
|
- llvm-toolchain-trusty-3.9
|
||||||
- llvm-toolchain-trusty-4.0
|
- llvm-toolchain-trusty-4.0
|
||||||
- llvm-toolchain-trusty-5.0
|
- llvm-toolchain-trusty-5.0
|
||||||
|
- llvm-toolchain-trusty-6.0
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
@@ -17,145 +22,169 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'clang-3.5']
|
packages: ['clang-3.5']
|
||||||
env: COMPILER='clang++-3.5' VALGRIND=1
|
env: COMPILER='clang++-3.5'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'clang-3.6']
|
packages: ['clang-3.6']
|
||||||
env: COMPILER='clang++-3.6' VALGRIND=1
|
env: COMPILER='clang++-3.6'
|
||||||
|
|
||||||
# Travis's containers do not seem to have Clang 3.7 in apt, no matter what sources I add.
|
# Clang 3.7 is intentionally skipped as we cannot get it easily on
|
||||||
# - os: linux
|
# TravisCI container
|
||||||
# compiler: clang
|
|
||||||
# addons:
|
|
||||||
# apt:
|
|
||||||
# sources: *all_sources
|
|
||||||
# packages: ['valgrind', 'clang-3.7']
|
|
||||||
# env: COMPILER='clang++-3.7' VALGRIND=1
|
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'clang-3.8']
|
packages: ['lcov', 'clang-3.8']
|
||||||
env: COMPILER='clang++-3.8' VALGRIND=1
|
env: COMPILER='clang++-3.8'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-3.9', 'valgrind', 'lcov']
|
packages: ['clang-3.9']
|
||||||
env: COMPILER='clang++-3.9' VALGRIND=1
|
env: COMPILER='clang++-3.9'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-4.0', 'valgrind', 'lcov']
|
packages: ['clang-4.0']
|
||||||
env: COMPILER='clang++-4.0' VALGRIND=1
|
env: COMPILER='clang++-4.0'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-5.0', 'valgrind', 'lcov']
|
packages: ['clang-5.0']
|
||||||
env: COMPILER='clang++-5.0' VALGRIND=1
|
env: COMPILER='clang++-5.0'
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0']
|
||||||
|
env: COMPILER='clang++-6.0'
|
||||||
|
|
||||||
# 2/ Linux GCC Builds
|
# 2/ Linux GCC Builds
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-4.8']
|
packages: ['g++-4.8']
|
||||||
env: COMPILER='g++-4.8' VALGRIND=1
|
env: COMPILER='g++-4.8'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-4.9']
|
packages: ['g++-4.9']
|
||||||
env: COMPILER='g++-4.9' VALGRIND=1
|
env: COMPILER='g++-4.9'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-5']
|
packages: ['g++-5']
|
||||||
env: COMPILER='g++-5' VALGRIND=1
|
env: COMPILER='g++-5'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons: &gcc6
|
addons: &gcc6
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-6']
|
packages: ['g++-6']
|
||||||
env: COMPILER='g++-6' VALGRIND=1
|
env: COMPILER='g++-6'
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons: &gcc7
|
addons: &gcc7
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['valgrind', 'lcov', 'g++-7']
|
packages: ['g++-7']
|
||||||
env: COMPILER='g++-7' VALGRIND=1
|
env: COMPILER='g++-7'
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: &gcc8
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['g++-8']
|
||||||
|
env: COMPILER='g++-8'
|
||||||
|
|
||||||
# 3b/ Linux C++14 Clang builds
|
# 3b/ Linux C++14 Clang builds
|
||||||
|
# Note that we need newer libstdc++ for C++14 support
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages: ['clang-3.8', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
packages: ['clang-3.8', 'libstdc++-6-dev']
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-trusty
|
- llvm-toolchain-trusty
|
||||||
env: COMPILER='clang++-3.8' CPP14=1 VALGRIND=1
|
env: COMPILER='clang++-3.8' CPP14=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-3.9', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
packages: ['clang-3.9', 'libstdc++-6-dev']
|
||||||
env: COMPILER='clang++-3.9' CPP14=1 VALGRIND=1
|
env: COMPILER='clang++-3.9' CPP14=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-4.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
packages: ['clang-4.0', 'libstdc++-6-dev']
|
||||||
env: COMPILER='clang++-4.0' CPP14=1 VALGRIND=1
|
env: COMPILER='clang++-4.0' CPP14=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: *all_sources
|
sources: *all_sources
|
||||||
packages: ['clang-5.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
|
packages: ['clang-5.0', 'libstdc++-6-dev']
|
||||||
env: COMPILER='clang++-5.0' CPP14=1 VALGRIND=1
|
env: COMPILER='clang++-5.0' CPP14=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-6-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP14=1
|
||||||
|
|
||||||
|
|
||||||
# 4a/ Linux C++14 GCC builds
|
# 4a/ Linux C++14 GCC builds
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons: *gcc6
|
addons: *gcc6
|
||||||
env: COMPILER='g++-6' CPP14=1 VALGRIND=1
|
env: COMPILER='g++-6' CPP14=1
|
||||||
|
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
addons: *gcc7
|
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
|
# 5/ OSX Clang Builds
|
||||||
- os: osx
|
- os: osx
|
||||||
@@ -181,15 +210,73 @@ matrix:
|
|||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode9.1
|
osx_image: xcode9.1
|
||||||
compiler: clang
|
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 EXTRAS=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 EXTRAS=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 EXTRAS=1
|
||||||
|
|
||||||
|
# 7/ C++17 builds
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc7
|
||||||
|
env: COMPILER='g++-7' CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
addons: *gcc7
|
||||||
|
env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-8-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP17=1
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources: *all_sources
|
||||||
|
packages: ['clang-6.0', 'libstdc++-8-dev']
|
||||||
|
env: COMPILER='clang++-6.0' CPP17=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||||
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
- mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
|
||||||
- |
|
- |
|
||||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||||
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
|
CMAKE_URL="http://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz"
|
||||||
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||||
@@ -202,25 +289,24 @@ before_script:
|
|||||||
# Regenerate single header file, so it is tested in the examples...
|
# Regenerate single header file, so it is tested in the examples...
|
||||||
- python scripts/generateSingleHeader.py
|
- python scripts/generateSingleHeader.py
|
||||||
|
|
||||||
- |
|
|
||||||
# Use Debug builds for running Valgrind and building examples
|
# Use Debug builds for running Valgrind and building examples
|
||||||
cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_VALGRIND=${VALGRIND} -DBUILD_EXAMPLES=ON -DENABLE_COVERAGE=ON
|
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
|
||||||
# Don't bother with release build for coverage build
|
# Don't bother with release build for coverage build
|
||||||
cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- |
|
- cd Build-Debug
|
||||||
cd Build-Debug
|
- make -j 2
|
||||||
make -j 2
|
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
|
||||||
# Coverage collection does not work for OS X atm
|
# Coverage collection does not work for OS X atm
|
||||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
- |
|
||||||
|
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
|
||||||
make gcov
|
make gcov
|
||||||
make lcov
|
make lcov
|
||||||
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
||||||
fi
|
fi
|
||||||
# Go to release build
|
- # Go to release build
|
||||||
cd ../Build-Release
|
- cd ../Build-Release
|
||||||
make -j 2
|
- make -j 2
|
||||||
CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||||
|
10
CMake/Catch2Config.cmake.in
Normal file
10
CMake/Catch2Config.cmake.in
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
|
||||||
|
# Avoid repeatedly including the targets
|
||||||
|
if(NOT TARGET Catch2::Catch2)
|
||||||
|
# Provide path for scripts
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
|
||||||
|
endif()
|
26
CMake/MiscFunctions.cmake
Normal file
26
CMake/MiscFunctions.cmake
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#checks that the given hard-coded list contains all headers + sources in the given folder
|
||||||
|
function(CheckFileList LIST_VAR FOLDER)
|
||||||
|
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||||
|
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||||
|
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||||
|
"${FOLDER}/*.hpp"
|
||||||
|
"${FOLDER}/*.h")
|
||||||
|
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||||
|
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||||
|
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||||
|
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(CheckFileListRec LIST_VAR FOLDER)
|
||||||
|
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||||
|
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||||
|
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||||
|
"${FOLDER}/*.hpp"
|
||||||
|
"${FOLDER}/*.h")
|
||||||
|
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||||
|
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||||
|
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||||
|
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
7
CMake/catch2.pc.in
Normal file
7
CMake/catch2.pc.in
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: Catch2
|
||||||
|
Description: A modern, C++-native, header-only, test framework for C++11
|
||||||
|
URL: https://github.com/catchorg/Catch2
|
||||||
|
Version: @Catch2_VERSION@
|
||||||
|
Cflags: -I${includedir}
|
534
CMakeLists.txt
534
CMakeLists.txt
@@ -1,10 +1,29 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
project(CatchSelfTest)
|
# detect if Catch is being bundled,
|
||||||
|
# disable testsuite in that case
|
||||||
|
if(NOT DEFINED PROJECT_NAME)
|
||||||
|
set(NOT_SUBPROJECT ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
project(Catch2 LANGUAGES CXX VERSION 2.4.2)
|
||||||
|
|
||||||
|
# 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_BUILD_EXTRA_TESTS "Build extra tests" 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)
|
||||||
|
|
||||||
option(USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
|
|
||||||
option(BUILD_EXAMPLES "Build documentation examples" OFF)
|
|
||||||
option(ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
|
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
@@ -13,364 +32,177 @@ set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
|||||||
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||||
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
||||||
set(HEADER_DIR ${CATCH_DIR}/include)
|
set(HEADER_DIR ${CATCH_DIR}/include)
|
||||||
set(CATCH_VERSION_NUMBER 2.1.0)
|
|
||||||
|
|
||||||
if(USE_WMAIN)
|
if(USE_WMAIN)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#checks that the given hard-coded list contains all headers + sources in the given folder
|
if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
|
||||||
function(CheckFileList LIST_VAR FOLDER)
|
find_package(PythonInterp)
|
||||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
if (NOT PYTHONINTERP_FOUND)
|
||||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
message(FATAL_ERROR "Python not found, but required for tests")
|
||||||
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
|
|
||||||
"${FOLDER}/*.hpp"
|
|
||||||
"${FOLDER}/*.h")
|
|
||||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
|
||||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
|
||||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
|
||||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(CheckFileListRec LIST_VAR FOLDER)
|
|
||||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
|
||||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
|
||||||
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
|
|
||||||
"${FOLDER}/*.hpp"
|
|
||||||
"${FOLDER}/*.h")
|
|
||||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
|
||||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
|
||||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
|
||||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# define the sources of the self test
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(TEST_SOURCES
|
|
||||||
${SELF_TEST_DIR}/TestMain.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Class.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Compilation.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Condition.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Decomposition.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/EnumToString.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Exception.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringVector.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
|
|
||||||
${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
|
|
||||||
)
|
|
||||||
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
|
|
||||||
|
|
||||||
# A set of impl files that just #include a single header
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(SURROGATE_SOURCES
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
|
|
||||||
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
|
|
||||||
)
|
|
||||||
CheckFileList(SURROGATE_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
|
|
||||||
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(TOP_LEVEL_HEADERS
|
|
||||||
${HEADER_DIR}/catch.hpp
|
|
||||||
${HEADER_DIR}/catch_with_main.hpp
|
|
||||||
)
|
|
||||||
CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(EXTERNAL_HEADERS
|
|
||||||
${HEADER_DIR}/external/clara.hpp
|
|
||||||
)
|
|
||||||
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
|
|
||||||
|
|
||||||
|
|
||||||
# Please keep these ordered alphabetically
|
|
||||||
set(INTERNAL_HEADERS
|
|
||||||
${HEADER_DIR}/internal/catch_approx.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertionhandler.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertioninfo.h
|
|
||||||
${HEADER_DIR}/internal/catch_assertionresult.h
|
|
||||||
${HEADER_DIR}/internal/catch_capture.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_capture_matchers.h
|
|
||||||
${HEADER_DIR}/internal/catch_clara.h
|
|
||||||
${HEADER_DIR}/internal/catch_commandline.h
|
|
||||||
${HEADER_DIR}/internal/catch_common.h
|
|
||||||
${HEADER_DIR}/internal/catch_compiler_capabilities.h
|
|
||||||
${HEADER_DIR}/internal/catch_config.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_console_colour.h
|
|
||||||
${HEADER_DIR}/internal/catch_context.h
|
|
||||||
${HEADER_DIR}/internal/catch_debug_console.h
|
|
||||||
${HEADER_DIR}/internal/catch_debugger.h
|
|
||||||
${HEADER_DIR}/internal/catch_decomposer.h
|
|
||||||
${HEADER_DIR}/internal/catch_default_main.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_enforce.h
|
|
||||||
${HEADER_DIR}/internal/catch_errno_guard.h
|
|
||||||
${HEADER_DIR}/internal/catch_exception_translator_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_external_interfaces.h
|
|
||||||
${HEADER_DIR}/internal/catch_fatal_condition.h
|
|
||||||
${HEADER_DIR}/internal/catch_impl.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_exception.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_reporter.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_runner.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_interfaces_testcase.h
|
|
||||||
${HEADER_DIR}/internal/catch_leak_detector.h
|
|
||||||
${HEADER_DIR}/internal/catch_list.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_floating.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
|
||||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
|
||||||
${HEADER_DIR}/internal/catch_message.h
|
|
||||||
${HEADER_DIR}/internal/catch_objc.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_option.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_platform.h
|
|
||||||
${HEADER_DIR}/internal/catch_random_number_generator.h
|
|
||||||
${HEADER_DIR}/internal/catch_reenable_warnings.h
|
|
||||||
${HEADER_DIR}/internal/catch_reporter_registrars.hpp
|
|
||||||
${HEADER_DIR}/internal/catch_reporter_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_result_type.h
|
|
||||||
${HEADER_DIR}/internal/catch_run_context.h
|
|
||||||
${HEADER_DIR}/internal/catch_benchmark.h
|
|
||||||
${HEADER_DIR}/internal/catch_section.h
|
|
||||||
${HEADER_DIR}/internal/catch_section_info.h
|
|
||||||
${HEADER_DIR}/internal/catch_session.h
|
|
||||||
${HEADER_DIR}/internal/catch_startup_exception_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_stream.h
|
|
||||||
${HEADER_DIR}/internal/catch_stringref.h
|
|
||||||
${HEADER_DIR}/internal/catch_string_manip.h
|
|
||||||
${HEADER_DIR}/internal/catch_suppress_warnings.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.h
|
|
||||||
${HEADER_DIR}/internal/catch_tag_alias_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_info.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_case_tracker.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_registry.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec.h
|
|
||||||
${HEADER_DIR}/internal/catch_test_spec_parser.h
|
|
||||||
${HEADER_DIR}/internal/catch_text.h
|
|
||||||
${HEADER_DIR}/internal/catch_timer.h
|
|
||||||
${HEADER_DIR}/internal/catch_tostring.h
|
|
||||||
${HEADER_DIR}/internal/catch_totals.h
|
|
||||||
${HEADER_DIR}/internal/catch_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 (NOT NO_SELFTEST)
|
|
||||||
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()
|
endif()
|
||||||
|
add_subdirectory(projects)
|
||||||
|
endif()
|
||||||
|
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
|
if(CATCH_BUILD_EXAMPLES)
|
||||||
set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
|
|
||||||
|
|
||||||
if (ENABLE_COVERAGE)
|
|
||||||
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 -Werror )
|
|
||||||
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 /WX /w44061 /w44062 )
|
|
||||||
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 (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(BUILD_EXAMPLES)
|
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(DIRECTORY "single_include/" DESTINATION "include/catch")
|
if(CATCH_BUILD_EXTRA_TESTS)
|
||||||
|
add_subdirectory(projects/ExtraTests)
|
||||||
|
endif()
|
||||||
|
|
||||||
## Provide some pkg-config integration
|
# add catch as a 'linkable' target
|
||||||
# Don't bother on Windows
|
add_library(Catch2 INTERFACE)
|
||||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
|
||||||
|
|
||||||
set(PKGCONFIG_INSTALL_DIR
|
|
||||||
"${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
|
|
||||||
CACHE PATH "Path where catch.pc is installed"
|
# 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)
|
||||||
|
|
||||||
|
# Only perform the installation steps when Catch is not being used as
|
||||||
|
# a subproject via `add_subdirectory`, or the destinations will break,
|
||||||
|
# see https://github.com/catchorg/Catch2/issues/1373
|
||||||
|
if (NOT_SUBPROJECT)
|
||||||
|
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
|
||||||
|
INSTALL_DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
)
|
)
|
||||||
|
|
||||||
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()
|
# 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}
|
||||||
|
)
|
||||||
|
|
||||||
|
# By default, FooConfigVersion is tied to architecture that it was
|
||||||
|
# generated on. Because Catch2 is header-only, it is arch-independent
|
||||||
|
# and thus Catch2ConfigVersion should not be tied to the architecture
|
||||||
|
# it was generated on.
|
||||||
|
#
|
||||||
|
# CMake does not provide a direct customization point for this in
|
||||||
|
# `write_basic_package_version_file`, but it can be accomplished
|
||||||
|
# indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
|
||||||
|
set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||||
|
unset(CMAKE_SIZEOF_VOID_P)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||||
|
COMPATIBILITY
|
||||||
|
SameMajorVersion
|
||||||
|
)
|
||||||
|
set(CMAKE_SIZEOF_VOID_P ${CATCH2_CMAKE_SIZEOF_VOID_P})
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY
|
||||||
|
"single_include/"
|
||||||
|
DESTINATION
|
||||||
|
"${CMAKE_INSTALL_INCLUDEDIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||||
|
DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install documentation
|
||||||
|
if(CATCH_INSTALL_DOCS)
|
||||||
|
install(
|
||||||
|
DIRECTORY
|
||||||
|
docs/
|
||||||
|
DESTINATION
|
||||||
|
"${CMAKE_INSTALL_DOCDIR}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CATCH_INSTALL_HELPERS)
|
||||||
|
# Install CMake scripts
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"contrib/ParseAndAddCatchTests.cmake"
|
||||||
|
"contrib/Catch.cmake"
|
||||||
|
"contrib/CatchAddTests.cmake"
|
||||||
|
DESTINATION
|
||||||
|
${CATCH_CMAKE_CONFIG_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install debugger helpers
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"contrib/gdbinit"
|
||||||
|
"contrib/lldbinit"
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_DATAROOTDIR}/Catch2
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Provide some pkg-config integration
|
||||||
|
set(PKGCONFIG_INSTALL_DIR
|
||||||
|
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||||
|
CACHE PATH "Path where catch2.pc is installed"
|
||||||
|
)
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
|
||||||
|
DESTINATION
|
||||||
|
${PKGCONFIG_INSTALL_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
endif(NOT_SUBPROJECT)
|
||||||
|
@@ -5,9 +5,11 @@
|
|||||||
[](https://travis-ci.org/catchorg/Catch2)
|
[](https://travis-ci.org/catchorg/Catch2)
|
||||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||||
[](https://codecov.io/gh/catchorg/Catch2)
|
[](https://codecov.io/gh/catchorg/Catch2)
|
||||||
[](https://wandbox.org/permlink/nerce2MiN6sVmfCi)
|
[](https://wandbox.org/permlink/rbkudthN4hBNJznk)
|
||||||
|
[](https://discord.gg/4CWS9zD)
|
||||||
|
|
||||||
<a href="https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
|
||||||
|
<a href="https://github.com/catchorg/Catch2/releases/download/v2.4.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||||
|
|
||||||
## Catch2 is released!
|
## Catch2 is released!
|
||||||
|
|
||||||
@@ -32,5 +34,5 @@ This documentation comprises these three parts:
|
|||||||
|
|
||||||
## More
|
## More
|
||||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
|
||||||
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)
|
* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD)
|
||||||
* See [who else is using Catch2](docs/opensource-users.md#top)
|
* See [who else is using Catch2](docs/opensource-users.md#top)
|
||||||
|
43
appveyor.yml
43
appveyor.yml
@@ -19,18 +19,51 @@ environment:
|
|||||||
|
|
||||||
- additional_flags: "/D_UNICODE /DUNICODE"
|
- additional_flags: "/D_UNICODE /DUNICODE"
|
||||||
wmain: 1
|
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:
|
matrix:
|
||||||
exclude:
|
exclude:
|
||||||
- os: Visual Studio 2015
|
- os: Visual Studio 2015
|
||||||
additional_flags: "/permissive- /std:c++latest"
|
additional_flags: "/permissive- /std:c++latest"
|
||||||
|
|
||||||
init:
|
- os: Visual Studio 2015
|
||||||
- git config --global core.autocrlf input
|
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:
|
install:
|
||||||
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { python -m pip install codecov }
|
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
|
||||||
- ps: if (($env:CONFIGURATION) -eq "Debug" ) { .\misc\installOpenCppCoverage.ps1 }
|
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
|
||||||
|
|
||||||
# Win32 and x64 are CMake-compatible solution platform names.
|
# Win32 and x64 are CMake-compatible solution platform names.
|
||||||
# This allows us to pass %PLATFORM% to CMake -A.
|
# This allows us to pass %PLATFORM% to CMake -A.
|
||||||
@@ -54,7 +87,7 @@ before_build:
|
|||||||
|
|
||||||
# build with MSBuild
|
# build with MSBuild
|
||||||
build:
|
build:
|
||||||
project: Build\CatchSelfTest.sln # path to Visual Studio solution or project
|
project: Build\Catch2.sln # path to Visual Studio solution or project
|
||||||
parallel: true # enable MSBuild parallel builds
|
parallel: true # enable MSBuild parallel builds
|
||||||
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}
|
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}
|
||||||
|
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
|
|
||||||
Name: Catch
|
|
||||||
Description: Testing library for C++
|
|
||||||
Requires:
|
|
||||||
Version: @CATCH_VERSION_NUMBER@
|
|
||||||
Libs:
|
|
||||||
Cflags: -I${prefix}/@INCLUDE_INSTALL_DIR@/include
|
|
20
codecov.yml
20
codecov.yml
@@ -1,10 +1,24 @@
|
|||||||
codecov:
|
|
||||||
branch: master
|
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
|
precision: 2
|
||||||
|
round: nearest
|
||||||
|
range: "60...90"
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
threshold: 2%
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
target: 80%
|
||||||
ignore:
|
ignore:
|
||||||
- "projects/SelfTest"
|
- "projects/SelfTest"
|
||||||
- "**/catch_reporter_tap.hpp"
|
- "**/catch_reporter_tap.hpp"
|
||||||
- "**/catch_reporter_automake.hpp"
|
- "**/catch_reporter_automake.hpp"
|
||||||
- "**/catch_reporter_teamcity.hpp"
|
- "**/catch_reporter_teamcity.hpp"
|
||||||
- "**/external/clara.hpp"
|
- "**/external/clara.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
codecov:
|
||||||
|
branch: master
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: "diff"
|
||||||
|
24
conanfile.py
24
conanfile.py
@@ -1,19 +1,31 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from conans import ConanFile
|
from conans import ConanFile, CMake
|
||||||
|
|
||||||
|
|
||||||
class CatchConan(ConanFile):
|
class CatchConan(ConanFile):
|
||||||
name = "Catch"
|
name = "Catch"
|
||||||
version = "2.1.0"
|
version = "2.4.2"
|
||||||
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
||||||
author = "philsquared"
|
author = "philsquared"
|
||||||
generators = "cmake"
|
generators = "cmake"
|
||||||
exports_sources = "single_include/*"
|
# Only needed until conan 1.5 is released
|
||||||
url = "https://github.com/philsquared/Catch"
|
settings = "compiler", "arch"
|
||||||
|
exports_sources = "single_include/*", "CMakeLists.txt", "CMake/catch2.pc.in", "LICENSE.txt"
|
||||||
|
url = "https://github.com/catchorg/Catch2"
|
||||||
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
|
license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
self.copy(pattern="catch.hpp", src="single_include", dst="include")
|
cmake = CMake(self)
|
||||||
|
cmake.definitions["BUILD_TESTING"] = "OFF"
|
||||||
|
cmake.definitions["CATCH_INSTALL_DOCS"] = "OFF"
|
||||||
|
cmake.definitions["CATCH_INSTALL_HELPERS"] = "ON"
|
||||||
|
cmake.configure()
|
||||||
|
cmake.install()
|
||||||
|
|
||||||
|
self.copy(pattern="LICENSE.txt", dst="licenses")
|
||||||
|
|
||||||
def package_id(self):
|
def package_id(self):
|
||||||
self.info.header_only()
|
self.info.header_only()
|
||||||
|
175
contrib/Catch.cmake
Normal file
175
contrib/Catch.cmake
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
Catch
|
||||||
|
-----
|
||||||
|
|
||||||
|
This module defines a function to help use the Catch test framework.
|
||||||
|
|
||||||
|
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||||
|
executable to enumerate its tests. This does not require CMake to be re-run
|
||||||
|
when tests change. However, it may not work in a cross-compiling environment,
|
||||||
|
and setting test properties is less convenient.
|
||||||
|
|
||||||
|
This command is intended to replace use of :command:`add_test` to register
|
||||||
|
tests, and will create a separate CTest test for each Catch test case. Note
|
||||||
|
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||||
|
cannot be shared by multiple test cases executing in the same instance.
|
||||||
|
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||||
|
usually considered as more beneficial. By default, the CTest test name is the
|
||||||
|
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||||
|
|
||||||
|
.. command:: catch_discover_tests
|
||||||
|
|
||||||
|
Automatically add tests with CTest by querying the compiled test executable
|
||||||
|
for available tests::
|
||||||
|
|
||||||
|
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]
|
||||||
|
)
|
||||||
|
|
||||||
|
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||||
|
that generates the list of tests by parsing the output from running the test
|
||||||
|
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||||
|
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||||
|
not necessary to re-run CMake when the list of tests changes.
|
||||||
|
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||||
|
in order to function in a cross-compiling environment.
|
||||||
|
|
||||||
|
Additionally, setting properties on tests is somewhat less convenient, since
|
||||||
|
the tests are not available at CMake time. Additional test properties may be
|
||||||
|
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||||
|
more fine-grained test control is needed, custom content may be provided
|
||||||
|
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||||
|
directory property. The set of discovered tests is made accessible to such a
|
||||||
|
script via the ``<target>_TESTS`` variable.
|
||||||
|
|
||||||
|
The options are:
|
||||||
|
|
||||||
|
``target``
|
||||||
|
Specifies the Catch executable, which must be a known CMake executable
|
||||||
|
target. CMake will substitute the location of the built executable when
|
||||||
|
running the test.
|
||||||
|
|
||||||
|
``TEST_SPEC arg1...``
|
||||||
|
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||||
|
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||||
|
|
||||||
|
``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 prepended 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()`` but with different
|
||||||
|
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||||
|
|
||||||
|
``TEST_SUFFIX suffix``
|
||||||
|
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||||
|
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||||
|
be specified.
|
||||||
|
|
||||||
|
``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.
|
||||||
|
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
function(catch_discover_tests TARGET)
|
||||||
|
cmake_parse_arguments(
|
||||||
|
""
|
||||||
|
""
|
||||||
|
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||||
|
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT _WORKING_DIRECTORY)
|
||||||
|
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
endif()
|
||||||
|
if(NOT _TEST_LIST)
|
||||||
|
set(_TEST_LIST ${TARGET}_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Generate a unique name based on the extra arguments
|
||||||
|
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||||
|
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||||
|
|
||||||
|
# Define rule to generate test list for aforementioned test executable
|
||||||
|
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||||
|
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||||
|
get_property(crosscompiling_emulator
|
||||||
|
TARGET ${TARGET}
|
||||||
|
PROPERTY CROSSCOMPILING_EMULATOR
|
||||||
|
)
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${TARGET} POST_BUILD
|
||||||
|
BYPRODUCTS "${ctest_tests_file}"
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-D "TEST_TARGET=${TARGET}"
|
||||||
|
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||||
|
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||||
|
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||||
|
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||||
|
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||||
|
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||||
|
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||||
|
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||||
|
-D "TEST_LIST=${_TEST_LIST}"
|
||||||
|
-D "CTEST_FILE=${ctest_tests_file}"
|
||||||
|
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
file(WRITE "${ctest_include_file}"
|
||||||
|
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||||
|
" include(\"${ctest_tests_file}\")\n"
|
||||||
|
"else()\n"
|
||||||
|
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||||
|
"endif()\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||||
|
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||||
|
set_property(DIRECTORY
|
||||||
|
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||||
|
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||||
|
if (NOT ${test_include_file_set})
|
||||||
|
set_property(DIRECTORY
|
||||||
|
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||||
|
)
|
78
contrib/CatchAddTests.cmake
Normal file
78
contrib/CatchAddTests.cmake
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
set(prefix "${TEST_PREFIX}")
|
||||||
|
set(suffix "${TEST_SUFFIX}")
|
||||||
|
set(spec ${TEST_SPEC})
|
||||||
|
set(extra_args ${TEST_EXTRA_ARGS})
|
||||||
|
set(properties ${TEST_PROPERTIES})
|
||||||
|
set(script)
|
||||||
|
set(suite)
|
||||||
|
set(tests)
|
||||||
|
|
||||||
|
function(add_command NAME)
|
||||||
|
set(_args "")
|
||||||
|
foreach(_arg ${ARGN})
|
||||||
|
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||||
|
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||||
|
else()
|
||||||
|
set(_args "${_args} ${_arg}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Run test executable to get list of available tests
|
||||||
|
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
||||||
|
OUTPUT_VARIABLE output
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||||
|
if(${result} EQUAL 0)
|
||||||
|
message(WARNING
|
||||||
|
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||||
|
)
|
||||||
|
elseif(${result} LESS 0)
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||||
|
" Result: ${result}\n"
|
||||||
|
" Output: ${output}\n"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REPLACE "\n" ";" output "${output}")
|
||||||
|
|
||||||
|
# Parse output
|
||||||
|
foreach(line ${output})
|
||||||
|
set(test ${line})
|
||||||
|
# use escape commas to handle properly test cases with commans inside the name
|
||||||
|
string(REPLACE "," "\\," test_name ${test})
|
||||||
|
# ...and add to script
|
||||||
|
add_command(add_test
|
||||||
|
"${prefix}${test}${suffix}"
|
||||||
|
${TEST_EXECUTOR}
|
||||||
|
"${TEST_EXECUTABLE}"
|
||||||
|
"${test_name}"
|
||||||
|
${extra_args}
|
||||||
|
)
|
||||||
|
add_command(set_tests_properties
|
||||||
|
"${prefix}${test}${suffix}"
|
||||||
|
PROPERTIES
|
||||||
|
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||||
|
${properties}
|
||||||
|
)
|
||||||
|
list(APPEND tests "${prefix}${test}${suffix}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Create a list of all discovered tests, which users may use to e.g. set
|
||||||
|
# properties on the tests
|
||||||
|
add_command(set ${TEST_LIST} ${tests})
|
||||||
|
|
||||||
|
# Write CTest script
|
||||||
|
file(WRITE "${CTEST_FILE}" "${script}")
|
@@ -39,6 +39,11 @@
|
|||||||
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
||||||
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
||||||
# #
|
# #
|
||||||
|
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
|
||||||
|
# a test should be run. For instance to use test MPI, one can write #
|
||||||
|
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
|
||||||
|
# just before calling this ParseAndAddCatchTests function #
|
||||||
|
# #
|
||||||
#==================================================================================================#
|
#==================================================================================================#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 2.8.8)
|
cmake_minimum_required(VERSION 2.8.8)
|
||||||
@@ -143,6 +148,9 @@ function(ParseFile SourceFile TestTarget)
|
|||||||
endif()
|
endif()
|
||||||
string(REPLACE "]" ";" Tags "${Tags}")
|
string(REPLACE "]" ";" Tags "${Tags}")
|
||||||
string(REPLACE "[" "" Tags "${Tags}")
|
string(REPLACE "[" "" Tags "${Tags}")
|
||||||
|
else()
|
||||||
|
# unset tags variable from previous loop
|
||||||
|
unset(Tags)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND Labels ${Tags})
|
list(APPEND Labels ${Tags})
|
||||||
@@ -165,7 +173,7 @@ function(ParseFile SourceFile TestTarget)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Add the test and set its properties
|
# Add the test and set its properties
|
||||||
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||||
LABELS "${Labels}")
|
LABELS "${Labels}")
|
||||||
endif()
|
endif()
|
||||||
|
16
contrib/gdbinit
Normal file
16
contrib/gdbinit
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# This file provides a way to skip stepping into Catch code when debugging with gdb.
|
||||||
|
#
|
||||||
|
# With the gdb "skip" command you can tell gdb to skip files or functions during debugging.
|
||||||
|
# see https://xaizek.github.io/2016-05-26/skipping-standard-library-in-gdb/ for an example
|
||||||
|
#
|
||||||
|
# Basically the following line tells gdb to skip all functions containing the
|
||||||
|
# regexp "Catch", which matches the complete Catch namespace.
|
||||||
|
# If you want to skip just some parts of the Catch code you can modify the
|
||||||
|
# regexp accordingly.
|
||||||
|
#
|
||||||
|
# If you want to permanently skip stepping into Catch code copy the following
|
||||||
|
# line into your ~/.gdbinit file
|
||||||
|
#
|
||||||
|
|
||||||
|
skip -rfu Catch
|
16
contrib/lldbinit
Normal file
16
contrib/lldbinit
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# This file provides a way to skip stepping into Catch code when debugging with lldb.
|
||||||
|
#
|
||||||
|
# With the setting "target.process.thread.step-avoid-regexp" you can tell lldb
|
||||||
|
# to skip functions matching the regexp
|
||||||
|
#
|
||||||
|
# Basically the following line tells lldb to skip all functions containing the
|
||||||
|
# regexp "Catch", which matches the complete Catch namespace.
|
||||||
|
# If you want to skip just some parts of the Catch code you can modify the
|
||||||
|
# regexp accordingly.
|
||||||
|
#
|
||||||
|
# If you want to permanently skip stepping into Catch code copy the following
|
||||||
|
# line into your ~/.lldbinit file
|
||||||
|
#
|
||||||
|
|
||||||
|
settings set target.process.thread.step-avoid-regexp Catch
|
@@ -12,6 +12,8 @@ Writing tests:
|
|||||||
* [Test fixtures](test-fixtures.md#top)
|
* [Test fixtures](test-fixtures.md#top)
|
||||||
* [Reporters](reporters.md#top)
|
* [Reporters](reporters.md#top)
|
||||||
* [Event Listeners](event-listeners.md#top)
|
* [Event Listeners](event-listeners.md#top)
|
||||||
|
* [Data Generators](generators.md#top)
|
||||||
|
* [Other macros](other-macros.md#top)
|
||||||
|
|
||||||
Fine tuning:
|
Fine tuning:
|
||||||
* [Supplying your own main()](own-main.md#top)
|
* [Supplying your own main()](own-main.md#top)
|
||||||
@@ -20,7 +22,10 @@ Fine tuning:
|
|||||||
|
|
||||||
Running:
|
Running:
|
||||||
* [Command line](command-line.md#top)
|
* [Command line](command-line.md#top)
|
||||||
* [CI and Build system integration](build-systems.md#top)
|
|
||||||
|
Odds and ends:
|
||||||
|
* [CMake integration](cmake-integration.md#top)
|
||||||
|
* [CI and other miscellaneous pieces](ci-and-misc.md#top)
|
||||||
|
|
||||||
FAQ:
|
FAQ:
|
||||||
* [Why are my tests slow to compile?](slow-compiles.md#top)
|
* [Why are my tests slow to compile?](slow-compiles.md#top)
|
||||||
|
@@ -6,10 +6,11 @@
|
|||||||
[Exceptions](#exceptions)<br>
|
[Exceptions](#exceptions)<br>
|
||||||
[Matcher expressions](#matcher-expressions)<br>
|
[Matcher expressions](#matcher-expressions)<br>
|
||||||
[Thread Safety](#thread-safety)<br>
|
[Thread Safety](#thread-safety)<br>
|
||||||
|
[Expressions with commas](#expressions-with-commas)<br>
|
||||||
|
|
||||||
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
||||||
|
|
||||||
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:
|
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.
|
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
|
||||||
|
|
||||||
Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called ```Approx```. ```Approx``` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
|
Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called `Approx`. `Approx` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
REQUIRE( performComputation() == Approx( 2.1 ) );
|
REQUIRE( performComputation() == Approx( 2.1 ) );
|
||||||
```
|
```
|
||||||
|
|
||||||
This way `Approx` is constructed with reasonable defaults, covering most simple cases of rounding errors. If these are insufficient, each `Approx` instance has 3 tuning knobs, that can be used to customize it for your computation.
|
Catch also provides a UDL for `Approx`; `_a`. It resides in
|
||||||
|
the `Catch::literals` namespace and can be used like so:
|
||||||
|
```cpp
|
||||||
|
using namespace Catch::literals;
|
||||||
|
REQUIRE( performComputation() == 2.1_a );
|
||||||
|
```
|
||||||
|
|
||||||
* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
|
`Approx` is constructed with defaults that should cover most simple cases.
|
||||||
* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
|
For the more complex cases, `Approx` provides 3 customization points:
|
||||||
* __scale__ - scale serves to adjust the epsilon's multiplicator. By default set to `0.0`.
|
|
||||||
|
* __epsilon__ - epsilon serves to set the coefficient by which a result
|
||||||
|
can differ from `Approx`'s value before it is rejected.
|
||||||
|
_By default set to `std::numeric_limits<float>::epsilon()*100`._
|
||||||
|
* __margin__ - margin serves to set the the absolute value by which
|
||||||
|
a result can differ from `Approx`'s value before it is rejected.
|
||||||
|
_By default set to `0.0`._
|
||||||
|
* __scale__ - scale is used to change the magnitude of `Approx` for relative check.
|
||||||
|
_By default set to `0.0`._
|
||||||
|
|
||||||
#### epsilon example
|
#### epsilon example
|
||||||
```cpp
|
```cpp
|
||||||
Approx target = Approx(100).epsilon(0.01);
|
Approx target = Approx(100).epsilon(0.01);
|
||||||
100.0 == target; // Obviously true
|
100.0 == target; // Obviously true
|
||||||
200.0 == target; // Obviously still false
|
200.0 == target; // Obviously still false
|
||||||
100.5 == target; // True, because we set target to allow up to 1% error
|
100.5 == target; // True, because we set target to allow up to 1% difference
|
||||||
```
|
```
|
||||||
|
|
||||||
#### margin example
|
#### margin example
|
||||||
_Margin check is used only if the relative (epsilon and scale based) check fails._
|
|
||||||
```cpp
|
```cpp
|
||||||
Approx target = Approx(100).margin(5);
|
Approx target = Approx(100).margin(5);
|
||||||
100.0 == target; // Obviously true
|
100.0 == target; // Obviously true
|
||||||
200.0 == target; // Obviously still false
|
200.0 == target; // Obviously still false
|
||||||
104.0 == target; // True, because we set target to allow absolute error up to 5
|
104.0 == target; // True, because we set target to allow absolute difference of at most 5
|
||||||
```
|
```
|
||||||
|
|
||||||
#### scale
|
#### scale
|
||||||
@@ -155,6 +168,34 @@ Matchers can be composed using `&&`, `||` and `!` operators.
|
|||||||
Currently assertions in Catch are not thread safe.
|
Currently assertions in Catch are not thread safe.
|
||||||
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
|
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
|
||||||
|
|
||||||
|
## Expressions with commas
|
||||||
|
|
||||||
|
Because the preprocessor parses code using different rules than the
|
||||||
|
compiler, multiple-argument assertions (e.g. `REQUIRE_THROWS_AS`) have
|
||||||
|
problems with commas inside the provided expressions. As an example
|
||||||
|
`REQUIRE_THROWS_AS(std::pair<int, int>(1, 2), std::invalid_argument);`
|
||||||
|
will fail to compile, because the preprocessor sees 3 arguments provided,
|
||||||
|
but the macro accepts only 2. There are two possible workarounds.
|
||||||
|
|
||||||
|
1) Use typedef:
|
||||||
|
```cpp
|
||||||
|
using int_pair = std::pair<int, int>;
|
||||||
|
REQUIRE_THROWS_AS(int_pair(1, 2), std::invalid_argument);
|
||||||
|
```
|
||||||
|
|
||||||
|
This solution is always applicable, but makes the meaning of the code
|
||||||
|
less clear.
|
||||||
|
|
||||||
|
2) Parenthesize the expression:
|
||||||
|
```cpp
|
||||||
|
TEST_CASE_METHOD((Fixture<int, int>), "foo", "[bar]") {
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This solution is not always applicable, because it might require extra
|
||||||
|
changes on the Catch's side to work.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -1,6 +1,13 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# CI and build system integration
|
# CI and other odd pieces
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[Continuous Integration systems](#continuous-integration-systems)<br>
|
||||||
|
[Other reporters](#other-reporters)<br>
|
||||||
|
[Low-level tools](#low-level-tools)<br>
|
||||||
|
[CMake](#cmake)<br>
|
||||||
|
|
||||||
|
This page talks about how Catch integrates with Continuous Integration
|
||||||
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
|
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
|
||||||
|
|
||||||
## Continuous Integration systems
|
## Continuous Integration systems
|
||||||
@@ -28,9 +35,14 @@ The advantage of this format is that the JUnit Ant schema is widely understood b
|
|||||||
The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
|
The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
|
||||||
|
|
||||||
## Other reporters
|
## Other reporters
|
||||||
Other reporters are not part of the single-header distribution and need to be downloaded and included separately. All reporters are stored in `include/reporters` directory in the git repository, and are named `catch_reporter_*.hpp`. For example, to use the TeamCity reporter you need to download `include/reporters/catch_reporter_teamcity.hpp` and include it after Catch itself.
|
Other reporters are not part of the single-header distribution and need
|
||||||
|
to be downloaded and included separately. All reporters are stored in
|
||||||
|
`single_include` directory in the git repository, and are named
|
||||||
|
`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you
|
||||||
|
need to download `single_include/catch_reporter_teamcity.hpp` and include
|
||||||
|
it after Catch itself.
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "catch_reporter_teamcity.hpp"
|
#include "catch_reporter_teamcity.hpp"
|
||||||
@@ -66,90 +78,31 @@ Catch offers prototypal support for being included in precompiled headers, but b
|
|||||||
* include "catch.hpp" again
|
* include "catch.hpp" again
|
||||||
|
|
||||||
|
|
||||||
### CMake
|
|
||||||
|
|
||||||
In general we recommend "vendoring" Catch's single-include releases inside your own repository. If you do this, the following example shows a minimal CMake project:
|
|
||||||
```CMake
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
|
|
||||||
project(cmake_test)
|
|
||||||
|
|
||||||
# Prepare "Catch" library for other executables
|
|
||||||
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/catch)
|
|
||||||
add_library(Catch INTERFACE)
|
|
||||||
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
|
|
||||||
|
|
||||||
# Make test executable
|
|
||||||
set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
|
|
||||||
add_executable(tests ${TEST_SOURCES})
|
|
||||||
target_link_libraries(tests Catch)
|
|
||||||
```
|
|
||||||
Note that it assumes that the path to the Catch's header is `catch/catch.hpp` from the `CMakeLists.txt` file.
|
|
||||||
|
|
||||||
|
|
||||||
You can also use the following CMake snippet to automatically fetch the entire Catch repository from github and configure it as an external project:
|
|
||||||
```CMake
|
|
||||||
cmake_minimum_required(VERSION 2.8.8)
|
|
||||||
project(catch_builder CXX)
|
|
||||||
include(ExternalProject)
|
|
||||||
find_package(Git REQUIRED)
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
catch
|
|
||||||
PREFIX ${CMAKE_BINARY_DIR}/catch
|
|
||||||
GIT_REPOSITORY https://github.com/philsquared/Catch.git
|
|
||||||
TIMEOUT 10
|
|
||||||
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
|
|
||||||
CONFIGURE_COMMAND ""
|
|
||||||
BUILD_COMMAND ""
|
|
||||||
INSTALL_COMMAND ""
|
|
||||||
LOG_DOWNLOAD ON
|
|
||||||
)
|
|
||||||
|
|
||||||
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
|
||||||
ExternalProject_Get_Property(catch source_dir)
|
|
||||||
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
|
||||||
```
|
|
||||||
|
|
||||||
If you put it in, e.g., `${PROJECT_SRC_DIR}/${EXT_PROJECTS_DIR}/catch/`, you can use it in your project by adding the following to your root CMake file:
|
|
||||||
|
|
||||||
```CMake
|
|
||||||
# Includes Catch in the project:
|
|
||||||
add_subdirectory(${EXT_PROJECTS_DIR}/catch)
|
|
||||||
include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
|
|
||||||
enable_testing(true) # Enables unit-testing.
|
|
||||||
```
|
|
||||||
|
|
||||||
The advantage of this approach is that you can always automatically update Catch to the latest release. The disadvantage is that it means bringing in lot more than you need.
|
|
||||||
|
|
||||||
|
|
||||||
### Automatic test registration
|
|
||||||
If you are also using ctest, `contrib/ParseAndAddCatchTests.cmake` is a CMake script that attempts to parse your test files and automatically register all test cases, using 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`.
|
|
||||||
|
|
||||||
### CodeCoverage module (GCOV, LCOV...)
|
### CodeCoverage module (GCOV, LCOV...)
|
||||||
|
|
||||||
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
|
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
|
||||||
|
|
||||||
|
|
||||||
|
### pkg-config
|
||||||
|
|
||||||
|
Catch2 provides a rudimentary pkg-config integration, by registering itself
|
||||||
|
under the name `catch2`. This means that after Catch2 is installed, you
|
||||||
|
can use `pkg-config` to get its include path: `pkg-config --cflags catch2`.
|
||||||
|
|
||||||
|
### gdb and lldb scripts
|
||||||
|
|
||||||
|
Catch2's `contrib` folder also contains two simple debugger scripts,
|
||||||
|
`gdbinit` for `gdb` and `lldbinit` for `lldb`. If loaded into their
|
||||||
|
respective debugger, these will tell it to step over Catch2's internals
|
||||||
|
when stepping through code.
|
||||||
|
|
||||||
|
|
||||||
|
## CMake
|
||||||
|
|
||||||
|
[As it has been getting kinda long, the documentation of Catch2's
|
||||||
|
integration with CMake has been moved to its own page.](cmake-integration.md#top)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
226
docs/cmake-integration.md
Normal file
226
docs/cmake-integration.md
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<a id="top"></a>
|
||||||
|
# CMake integration
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[CMake target](#cmake-target)<br>
|
||||||
|
[Automatic test registration](#automatic-test-registration)<br>
|
||||||
|
[CMake project options](#cmake-project-options)<br>
|
||||||
|
[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
|
||||||
|
|
||||||
|
Because we use CMake to build Catch2, we also provide a couple of
|
||||||
|
integration points for our users.
|
||||||
|
|
||||||
|
1) Catch2 exports a (namespaced) CMake target
|
||||||
|
2) Catch2's repository contains CMake scripts for automatic registration
|
||||||
|
of `TEST_CASE`s in CTest
|
||||||
|
|
||||||
|
## CMake target
|
||||||
|
|
||||||
|
Catch2's CMake build exports an interface target `Catch2::Catch2`. Linking
|
||||||
|
against it will add the proper include path and all necessary capabilities
|
||||||
|
to the resulting binary.
|
||||||
|
|
||||||
|
This means that if Catch2 has been installed on the system, it should be
|
||||||
|
enough to do:
|
||||||
|
```cmake
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
target_link_libraries(tests Catch2::Catch2)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
This target is also provided when Catch2 is used as a subdirectory.
|
||||||
|
Assuming that Catch2 has been cloned to `lib/Catch2`:
|
||||||
|
```cmake
|
||||||
|
add_subdirectory(lib/Catch2)
|
||||||
|
target_link_libraries(tests Catch2::Catch2)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic test registration
|
||||||
|
|
||||||
|
Catch2's repository also contains two CMake scripts that help users
|
||||||
|
with automatically registering their `TEST_CASE`s with CTest. They
|
||||||
|
can be found in the `contrib` folder, and are
|
||||||
|
|
||||||
|
1) `Catch.cmake` (and its dependency `CatchAddTests.cmake`)
|
||||||
|
2) `ParseAndAddCatchTests.cmake`
|
||||||
|
|
||||||
|
If Catch2 has been installed in system, both of these can be used after
|
||||||
|
doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
|
||||||
|
to your CMake module path.
|
||||||
|
|
||||||
|
### `Catch.cmake` and `AddCatchTests.cmake`
|
||||||
|
|
||||||
|
`Catch.cmake` provides function `catch_discover_tests` to get tests from
|
||||||
|
a target. This function works by running the resulting executable with
|
||||||
|
`--list-test-names-only` flag, and then parsing the output to find all
|
||||||
|
existing tests.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
```cmake
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(foo test.cpp)
|
||||||
|
target_link_libraries(foo Catch2::Catch2)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(foo)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
`catch_discover_tests` can be given several extra argumets:
|
||||||
|
```cmake
|
||||||
|
catch_discover_tests(target
|
||||||
|
[TEST_SPEC arg1...]
|
||||||
|
[EXTRA_ARGS arg1...]
|
||||||
|
[WORKING_DIRECTORY dir]
|
||||||
|
[TEST_PREFIX prefix]
|
||||||
|
[TEST_SUFFIX suffix]
|
||||||
|
[PROPERTIES name1 value1...]
|
||||||
|
[TEST_LIST var]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
* `TEST_SPEC arg1...`
|
||||||
|
|
||||||
|
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||||
|
pass to the Catch executable alongside the `--list-test-names-only` flag.
|
||||||
|
|
||||||
|
|
||||||
|
* `EXTRA_ARGS arg1...`
|
||||||
|
|
||||||
|
Any extra arguments to pass on the command line to each test case.
|
||||||
|
|
||||||
|
|
||||||
|
* `WORKING_DIRECTORY dir`
|
||||||
|
|
||||||
|
Specifies the directory in which to run the discovered test cases. If this
|
||||||
|
option is not provided, the current binary directory is used.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_PREFIX prefix`
|
||||||
|
|
||||||
|
Specifies a _prefix_ to be added to the name of each discovered test case.
|
||||||
|
This can be useful when the same test executable is being used in multiple
|
||||||
|
calls to `catch_discover_tests()`, with different `TEST_SPEC` or `EXTRA_ARGS`.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_SUFFIX suffix`
|
||||||
|
|
||||||
|
Same as `TEST_PREFIX`, except it specific the _suffix_ for the test names.
|
||||||
|
Both `TEST_PREFIX` and `TEST_SUFFIX` can be specified at the same time.
|
||||||
|
|
||||||
|
|
||||||
|
* `PROPERTIES name1 value1...`
|
||||||
|
|
||||||
|
Specifies additional properties to be set on all tests discovered by this
|
||||||
|
invocation of `catch_discover_tests`.
|
||||||
|
|
||||||
|
|
||||||
|
* `TEST_LIST var`
|
||||||
|
|
||||||
|
Make the list of tests available in the variable `var`, rather than the
|
||||||
|
default `<target>_TESTS`. This can be useful when the same test
|
||||||
|
executable is being used in multiple calls to `catch_discover_tests()`.
|
||||||
|
Note that this variable is only available in CTest.
|
||||||
|
|
||||||
|
|
||||||
|
### `ParseAndAddCatchTests.cmake`
|
||||||
|
|
||||||
|
`ParseAndAddCatchTests` works by parsing all implementation files
|
||||||
|
associated with the provided target, and registering them via CTest's
|
||||||
|
`add_test`. This approach has some limitations, such as the fact that
|
||||||
|
commented-out tests will be registered anyway.
|
||||||
|
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(baz LANGUAGES CXX VERSION 0.0.1)
|
||||||
|
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(foo test.cpp)
|
||||||
|
target_link_libraries(foo Catch2::Catch2)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(ParseAndAddCatchTests)
|
||||||
|
ParseAndAddCatchTests(foo)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
`ParseAndAddCatchTests` provides some customization points:
|
||||||
|
* `PARSE_CATCH_TESTS_VERBOSE` -- When `ON`, the script prints debug
|
||||||
|
messages. Defaults to `OFF`.
|
||||||
|
* `PARSE_CATCH_TESTS_NO_HIDDEN_TESTS` -- When `ON`, hidden tests (tests
|
||||||
|
tagged with any of `[!hide]`, `[.]` or `[.foo]`) will not be registered.
|
||||||
|
Defaults to `OFF`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME` -- When `ON`, adds fixture
|
||||||
|
class name to the test name in CTest. Defaults to `ON`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME` -- When `ON`, adds target
|
||||||
|
name to the test name in CTest. Defaults to `ON`.
|
||||||
|
* `PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS` -- When `ON`, adds test
|
||||||
|
file to `CMAKE_CONFIGURE_DEPENDS`. This means that the CMake configuration
|
||||||
|
step will be re-ran when the test files change, letting new tests be
|
||||||
|
automatically discovered. Defaults to `OFF`.
|
||||||
|
|
||||||
|
|
||||||
|
Optionally, one can specify a launching command to run tests by setting the
|
||||||
|
variable `OptionalCatchTestLauncher` before calling `ParseAndAddCatchTests`. For
|
||||||
|
instance to run some tests using `MPI` and other sequentially, one can write
|
||||||
|
```cmake
|
||||||
|
set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC})
|
||||||
|
ParseAndAddCatchTests(mpi_foo)
|
||||||
|
unset(OptionalCatchTestLauncher)
|
||||||
|
ParseAndAddCatchTests(bar)
|
||||||
|
```
|
||||||
|
|
||||||
|
## CMake project options
|
||||||
|
|
||||||
|
Catch2's CMake project also provides some options for other projects
|
||||||
|
that consume it. These are
|
||||||
|
|
||||||
|
* `CATCH_BUILD_TESTING` -- When `ON`, Catch2's SelfTest project will be
|
||||||
|
built. Defaults to `ON`. Note that Catch2 also obeys `BUILD_TESTING` CMake
|
||||||
|
variable, so _both_ of them need to be `ON` for the SelfTest to be built,
|
||||||
|
and either of them can be set to `OFF` to disable building SelfTest.
|
||||||
|
* `CATCH_BUILD_EXAMPLES` -- When `ON`, Catch2's usage examples will be
|
||||||
|
built. Defaults to `OFF`.
|
||||||
|
* `CATCH_INSTALL_DOCS` -- When `ON`, Catch2's documentation will be
|
||||||
|
included in the installation. Defaults to `ON`.
|
||||||
|
* `CATCH_INSTALL_HELPERS` -- When `ON`, Catch2's contrib folder will be
|
||||||
|
included in the installation. Defaults to `ON`.
|
||||||
|
* `BUILD_TESTING` -- When `ON` and the project is not used as a subproject,
|
||||||
|
Catch2's test binary will be built. Defaults to `ON`.
|
||||||
|
|
||||||
|
|
||||||
|
## Installing Catch2 from git repository
|
||||||
|
|
||||||
|
If you cannot install Catch2 from a package manager (e.g. Ubuntu 16.04
|
||||||
|
provides catch only in version 1.2.0) you might want to install it from
|
||||||
|
the repository instead. Assuming you have enough rights, you can just
|
||||||
|
install it to the default location, like so:
|
||||||
|
```
|
||||||
|
$ git clone https://github.com/catchorg/Catch2.git
|
||||||
|
$ cd Catch2
|
||||||
|
$ cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
$ sudo cmake --build build/ --target install
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not have superuser rights, you will also need to specify
|
||||||
|
[CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
|
||||||
|
when configuring the build, and then modify your calls to
|
||||||
|
[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[Home](Readme.md#top)
|
@@ -24,6 +24,7 @@
|
|||||||
[Usage](#usage)<br>
|
[Usage](#usage)<br>
|
||||||
[Specify the section to run](#specify-the-section-to-run)<br>
|
[Specify the section to run](#specify-the-section-to-run)<br>
|
||||||
[Filenames as tags](#filenames-as-tags)<br>
|
[Filenames as tags](#filenames-as-tags)<br>
|
||||||
|
[Override output colouring](#override-output-colouring)<br>
|
||||||
|
|
||||||
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
||||||
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
|
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
|
||||||
@@ -57,6 +58,7 @@ Click one of the followings links to take you straight to that option - or scrol
|
|||||||
<a href="#libidentify"> ` --libidentify`</a><br />
|
<a href="#libidentify"> ` --libidentify`</a><br />
|
||||||
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
<a href="#wait-for-keypress"> ` --wait-for-keypress`</a><br />
|
||||||
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
<a href="#benchmark-resolution-multiple"> ` --benchmark-resolution-multiple`</a><br />
|
||||||
|
<a href="#use-colour"> ` --use-colour`</a><br />
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ Wildcards consist of the `*` character at the beginning and/or end of test case
|
|||||||
|
|
||||||
Test specs are case insensitive.
|
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.
|
Inclusions and exclusions are evaluated in left-to-right order.
|
||||||
|
|
||||||
Test case examples:
|
Test case examples:
|
||||||
@@ -94,7 +96,7 @@ a* ~ab* abc Matches all tests that start with 'a', except those that
|
|||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Names within square brackets are interpreted as tags.
|
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>
|
<pre>[one][two],[three]</pre>
|
||||||
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
|
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
|
## Breaking into the debugger
|
||||||
<pre>-b, --break</pre>
|
<pre>-b, --break</pre>
|
||||||
|
|
||||||
In some IDEs (currently XCode and Visual Studio) it is possible for Catch to break into the debugger on a test failure. This can be very helpful during debug sessions - especially when there is more than one path through a particular test.
|
Under most debuggers Catch2 is capable of automatically breaking on a test
|
||||||
|
failure. This allows the user to see the current state of the test during
|
||||||
|
failure.
|
||||||
|
|
||||||
<a id="showing-results-for-successful-tests"></a>
|
<a id="showing-results-for-successful-tests"></a>
|
||||||
## Showing results for successful tests
|
## Showing results for successful tests
|
||||||
@@ -192,9 +196,16 @@ This option transforms tabs and newline characters into ```\t``` and ```\n``` re
|
|||||||
## Warnings
|
## Warnings
|
||||||
<pre>-w, --warn <warning name></pre>
|
<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>
|
<a id="reporting-timings"></a>
|
||||||
## Reporting timings
|
## 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
|
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
|
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>
|
<a id="usage"></a>
|
||||||
## Usage
|
## 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]`.
|
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
||||||
|
|
||||||
|
<a id="use-colour"></a>
|
||||||
|
## Override output colouring
|
||||||
|
<pre>--use-colour <yes|no|auto></pre>
|
||||||
|
|
||||||
|
Catch colours output for terminals, but omits colouring when it detects that
|
||||||
|
output is being sent to a pipe. This is done to avoid interfering with automated
|
||||||
|
processing of output.
|
||||||
|
|
||||||
|
`--use-colour yes` forces coloured output, `--use-colour no` disables coloured
|
||||||
|
output. The default behaviour is `--use-colour auto`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -3,13 +3,19 @@
|
|||||||
|
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
[main()/ implementation](#main-implementation)<br>
|
[main()/ implementation](#main-implementation)<br>
|
||||||
|
[Reporter / Listener interfaces](#reporter--listener-interfaces)<br>
|
||||||
[Prefixing Catch macros](#prefixing-catch-macros)<br>
|
[Prefixing Catch macros](#prefixing-catch-macros)<br>
|
||||||
[Terminal colour](#terminal-colour)<br>
|
[Terminal colour](#terminal-colour)<br>
|
||||||
[Console width](#console-width)<br>
|
[Console width](#console-width)<br>
|
||||||
[stdout](#stdout)<br>
|
[stdout](#stdout)<br>
|
||||||
|
[Fallback stringifier](#fallback-stringifier)<br>
|
||||||
|
[Default reporter](#default-reporter)<br>
|
||||||
|
[C++11 toggles](#c11-toggles)<br>
|
||||||
|
[C++17 toggles](#c17-toggles)<br>
|
||||||
[Other toggles](#other-toggles)<br>
|
[Other toggles](#other-toggles)<br>
|
||||||
[Windows header clutter](#windows-header-clutter)<br>
|
[Windows header clutter](#windows-header-clutter)<br>
|
||||||
[Enabling stringification](#enabling-stringification)<br>
|
[Enabling stringification](#enabling-stringification)<br>
|
||||||
|
[Disabling exceptions](#disabling-exceptions)<br>
|
||||||
|
|
||||||
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
|
Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
|
||||||
|
|
||||||
@@ -17,14 +23,14 @@ Nonetheless there are still some occasions where finer control is needed. For th
|
|||||||
|
|
||||||
## main()/ implementation
|
## main()/ implementation
|
||||||
|
|
||||||
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
|
CATCH_CONFIG_MAIN // Designates this as implementation file and defines main()
|
||||||
CATCH_CONFIG_RUNNER // Designates this as implementation file
|
CATCH_CONFIG_RUNNER // Designates this as implementation file
|
||||||
|
|
||||||
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
|
Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
|
||||||
|
|
||||||
# Reporter / Listener interfaces
|
## Reporter / Listener interfaces
|
||||||
|
|
||||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in 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.
|
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.
|
||||||
|
|
||||||
@@ -32,16 +38,16 @@ Implied by both `CATCH_CONFIG_MAIN` and `CATCH_CONFIG_RUNNER`.
|
|||||||
|
|
||||||
## Prefixing Catch macros
|
## Prefixing Catch macros
|
||||||
|
|
||||||
CATCH_CONFIG_PREFIX_ALL
|
CATCH_CONFIG_PREFIX_ALL
|
||||||
|
|
||||||
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
|
To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
|
||||||
|
|
||||||
|
|
||||||
## Terminal colour
|
## Terminal colour
|
||||||
|
|
||||||
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
|
CATCH_CONFIG_COLOUR_NONE // completely disables all text colouring
|
||||||
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
|
CATCH_CONFIG_COLOUR_WINDOWS // forces the Win32 console API to be used
|
||||||
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
|
CATCH_CONFIG_COLOUR_ANSI // forces ANSI colour codes to be used
|
||||||
|
|
||||||
Yes, I am English, so I will continue to spell "colour" with a 'u'.
|
Yes, I am English, so I will continue to spell "colour" with a 'u'.
|
||||||
|
|
||||||
@@ -55,24 +61,81 @@ Typically you should place the ```#define``` before #including "catch.hpp" in yo
|
|||||||
|
|
||||||
## Console width
|
## Console width
|
||||||
|
|
||||||
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
|
CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
|
||||||
|
|
||||||
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
|
Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
|
||||||
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
|
By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
|
||||||
|
|
||||||
## stdout
|
## stdout
|
||||||
|
|
||||||
CATCH_CONFIG_NOSTDOUT
|
CATCH_CONFIG_NOSTDOUT
|
||||||
|
|
||||||
Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly but gets them from ```Catch::cout()```, ```Catch::cerr()``` and ```Catch::clog``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
|
To support platforms that do not provide `std::cout`, `std::cerr` and
|
||||||
|
`std::clog`, Catch does not usem the directly, but rather calls
|
||||||
|
`Catch::cout`, `Catch::cerr` and `Catch::clog`. You can replace their
|
||||||
|
implementation by defining `CATCH_CONFIG_NOSTDOUT` and implementing
|
||||||
|
them yourself, their signatures are:
|
||||||
|
|
||||||
std::ostream& cout();
|
std::ostream& cout();
|
||||||
std::ostream& cerr();
|
std::ostream& cerr();
|
||||||
std::ostream& clog();
|
std::ostream& clog();
|
||||||
|
|
||||||
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
|
[You can see an example of replacing these functions here.](
|
||||||
|
../examples/231-Cfg-OutputStreams.cpp)
|
||||||
|
|
||||||
|
|
||||||
|
## Fallback stringifier
|
||||||
|
|
||||||
|
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_CONFIG_CPP17_STRING_VIEW // Provide StringMaker specialization for std::string_view
|
||||||
|
CATCH_CONFIG_CPP17_VARIANT // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
|
||||||
|
|
||||||
|
Catch contains basic compiler/standard detection and attempts to use
|
||||||
|
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
|
## Other toggles
|
||||||
|
|
||||||
@@ -84,6 +147,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_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
|
||||||
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
||||||
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
||||||
|
CATCH_CONFIG_WCHAR // Enables use of wchart_t
|
||||||
|
CATCH_CONFIG_EXPERIMENTAL_REDIRECT // Enables the new (experimental) way of capturing stdout/stderr
|
||||||
|
|
||||||
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
|
Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
|
||||||
|
|
||||||
@@ -91,14 +156,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.
|
`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`
|
### `CATCH_CONFIG_FAST_COMPILE`
|
||||||
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
|
This compile-time flag speeds up compilation of assertion macros by ~20%,
|
||||||
* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
|
by disabling the generation of assertion-local try-catch blocks for
|
||||||
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives.
|
non-exception family of assertion macros ({`REQUIRE`,`CHECK`}{``,`_FALSE`, `_THAT`}).
|
||||||
|
This disables translation of exceptions thrown under these assertions, but
|
||||||
|
should not lead to false negatives.
|
||||||
|
|
||||||
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
|
`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined,
|
||||||
|
in all translation units that are linked into single test binary.
|
||||||
|
|
||||||
### `CATCH_CONFIG_DISABLE_MATCHERS`
|
### `CATCH_CONFIG_DISABLE_MATCHERS`
|
||||||
When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
|
When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
|
||||||
@@ -130,9 +203,44 @@ By default, Catch does not stringify some types from the standard library. This
|
|||||||
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER // Provide StringMaker specialization for std::pair
|
||||||
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
|
CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER // Provide StringMaker specialization for std::tuple
|
||||||
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
|
CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
|
||||||
|
CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER // Provide StringMaker specialization for std::variant, std::monostate (on C++17)
|
||||||
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
|
CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS // Defines all of the above
|
||||||
|
|
||||||
|
|
||||||
|
## Disabling exceptions
|
||||||
|
|
||||||
|
By default, Catch2 uses exceptions to signal errors and to abort tests
|
||||||
|
when an assertion from the `REQUIRE` family of assertions fails. We also
|
||||||
|
provide an experimental support for disabling exceptions. Catch2 should
|
||||||
|
automatically detect when it is compiled with exceptions disabled, but
|
||||||
|
it can be forced to compile without exceptions by defining
|
||||||
|
|
||||||
|
CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||||
|
|
||||||
|
Note that when using Catch2 without exceptions, there are 2 major
|
||||||
|
limitations:
|
||||||
|
|
||||||
|
1) If there is an error that would normally be signalled by an exception,
|
||||||
|
the exception's message will instead be written to `Catch::cerr` and
|
||||||
|
`std::terminate` will be called.
|
||||||
|
2) If an assertion from the `REQUIRE` family of macros fails,
|
||||||
|
`std::terminate` will be called after the active reporter returns.
|
||||||
|
|
||||||
|
|
||||||
|
There is also a customization point for the exact behaviour of what
|
||||||
|
happens instead of exception being thrown. To use it, define
|
||||||
|
|
||||||
|
CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
|
||||||
|
|
||||||
|
and provide a definition for this function:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Catch {
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const&);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -44,7 +44,7 @@ _Note that you should not use any assertion macros within a Listener!_
|
|||||||
|
|
||||||
## Events that can be hooked
|
## 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++
|
```c++
|
||||||
// The whole test run, starting and ending
|
// The whole test run, starting and ending
|
||||||
|
50
docs/generators.md
Normal file
50
docs/generators.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<a id="top"></a>
|
||||||
|
# Data Generators
|
||||||
|
|
||||||
|
_Generators are currently considered an experimental feature and their
|
||||||
|
API can change between versions freely._
|
||||||
|
|
||||||
|
Data generators (also known as _data driven/parametrized test cases_)
|
||||||
|
let you reuse the same set of assertions across different input values.
|
||||||
|
In Catch2, this means that they respect the ordering and nesting
|
||||||
|
of the `TEST_CASE` and `SECTION` macros.
|
||||||
|
|
||||||
|
How does combining generators and test cases work might be better
|
||||||
|
explained by an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("Generators") {
|
||||||
|
auto i = GENERATE( range(1, 11) );
|
||||||
|
|
||||||
|
SECTION( "Some section" ) {
|
||||||
|
auto j = GENERATE( range( 11, 21 ) );
|
||||||
|
REQUIRE(i < j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
the assertion will be checked 100 times, because there are 10 possible
|
||||||
|
values for `i` (1, 2, ..., 10) and for each of them, there are 10 possible
|
||||||
|
values for `j` (11, 12, ..., 20).
|
||||||
|
|
||||||
|
You can also combine multiple generators by concatenation:
|
||||||
|
```cpp
|
||||||
|
static int square(int x) { return x * x; }
|
||||||
|
TEST_CASE("Generators 2") {
|
||||||
|
auto i = GENERATE(0, 1, -1, range(-20, -10), range(10, 20));
|
||||||
|
CAPTURE(i);
|
||||||
|
REQUIRE(square(i) >= 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will call `square` with arguments `0`, `1`, `-1`, `-20`, ..., `-11`,
|
||||||
|
`10`, ..., `19`.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
Because of the experimental nature of the current Generator implementation,
|
||||||
|
we won't list all of the first-party generators in Catch2. Instead you
|
||||||
|
should look at our current usage tests in
|
||||||
|
[projects/SelfTest/UsageTests/Generators.tests.cpp](/projects/SelfTest/UsageTests/Generators.tests.cpp).
|
||||||
|
For implementing your own generators, you can look at their implementation in
|
||||||
|
[include/internal/catch_generators.hpp](/include/internal/catch_generators.hpp).
|
@@ -1,12 +1,19 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Known limitations
|
# Known limitations
|
||||||
|
|
||||||
Catch has some known limitations, that we are not planning to change. Some of these are caused by our desire to support C++98 compilers, some of these are caused by our desire to keep Catch crossplatform, some exist because their priority is seen as low compared to the development effort they would need and some other yet are compiler/runtime bugs.
|
Over time, some limitations of Catch2 emerged. Some of these are due
|
||||||
|
to implementation details that cannot be easily changed, some of these
|
||||||
|
are due to lack of development resources on our part, and some of these
|
||||||
|
are due to plain old 3rd party bugs.
|
||||||
|
|
||||||
|
|
||||||
## Implementation limits
|
## Implementation limits
|
||||||
### Sections nested in loops
|
### Sections nested in loops
|
||||||
|
|
||||||
If you are using `SECTION`s inside loops, you have to create them with different name per loop's iteration. The recommended way to do so is to incorporate the loop's counter into section's name, like so
|
If you are using `SECTION`s inside loops, you have to create them with
|
||||||
|
different name per loop's iteration. The recommended way to do so is to
|
||||||
|
incorporate the loop's counter into section's name, like so:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
TEST_CASE( "Looped section" ) {
|
TEST_CASE( "Looped section" ) {
|
||||||
for (char i = '0'; i < '5'; ++i) {
|
for (char i = '0'; i < '5'; ++i) {
|
||||||
@@ -17,11 +24,34 @@ TEST_CASE( "Looped section" ) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or with a `DYNAMIC_SECTION` macro (that was made for exactly this purpose):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST_CASE( "Looped section" ) {
|
||||||
|
for (char i = '0'; i < '5'; ++i) {
|
||||||
|
DYNAMIC_SECTION( "Looped section " << i) {
|
||||||
|
SUCCEED( "Everything is OK" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests might be run again if last section fails
|
||||||
|
|
||||||
|
If the last section in a test fails, it might be run again. This is because
|
||||||
|
Catch2 discovers `SECTION`s dynamically, as they are about to run, and
|
||||||
|
if the last section in test case is aborted during execution (e.g. via
|
||||||
|
the `REQUIRE` family of macros), Catch2 does not know that there are no
|
||||||
|
more sections in that test case and must run the test case again.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
This section outlines some missing features, what is their status and their possible workarounds.
|
This section outlines some missing features, what is their status and their possible workarounds.
|
||||||
|
|
||||||
### Thread safe assertions
|
### Thread safe assertions
|
||||||
Because threading support in standard C++98 is limited (well, non-existent), assertion macros in Catch are not thread safe. This does not mean that you cannot use threads inside Catch's test, but that only single thread can interact with Catch's assertions and other macros.
|
Catch2's assertion macros are not thread safe. This does not mean that
|
||||||
|
you cannot use threads inside Catch's test, but that only single thread
|
||||||
|
can interact with Catch's assertions and other macros.
|
||||||
|
|
||||||
This means that this is ok
|
This means that this is ok
|
||||||
```cpp
|
```cpp
|
||||||
@@ -49,8 +79,8 @@ because only one thread passes the `REQUIRE` macro and this is not
|
|||||||
REQUIRE(cnt == 16);
|
REQUIRE(cnt == 16);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Because C++11 provides the necessary tools to do this, we are planning
|
||||||
_This limitation is highly unlikely to be lifted before Catch 2 is released._
|
to remove this limitation in the future.
|
||||||
|
|
||||||
### Process isolation in a test
|
### Process isolation in a test
|
||||||
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
||||||
@@ -96,6 +126,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
|
### Visual Studio 2015 -- Wrong line number reported in debug mode
|
||||||
@@ -127,3 +165,14 @@ If you are seeing a problem like this, i.e. a weird test paths that trigger only
|
|||||||
This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
|
This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
|
||||||
|
|
||||||
Workaround: Use newer version of `libstdc++`.
|
Workaround: Use newer version of `libstdc++`.
|
||||||
|
|
||||||
|
|
||||||
|
### libstdc++, `_GLIBCXX_DEBUG` macro and random ordering of tests
|
||||||
|
|
||||||
|
Running a Catch2 binary compiled against libstdc++ with `_GLIBCXX_DEBUG`
|
||||||
|
macro defined with `--order rand` will cause a debug check to trigger and
|
||||||
|
abort the run due to self-assignment.
|
||||||
|
[This is a known bug inside libstdc++](https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle/23691322)
|
||||||
|
|
||||||
|
Workaround: Don't use `--order rand` when compiling against debug-enabled
|
||||||
|
libstdc++.
|
||||||
|
@@ -1,18 +1,28 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# List of examples
|
# List of examples
|
||||||
|
|
||||||
|
## Already available
|
||||||
|
|
||||||
|
- Catch main: [Catch-provided main](../examples/000-CatchMain.cpp)
|
||||||
- Test Case: [Single-file](../examples/010-TestCase.cpp)
|
- Test Case: [Single-file](../examples/010-TestCase.cpp)
|
||||||
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-1.cpp)
|
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-2.cpp)
|
||||||
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
|
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
|
||||||
|
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
|
||||||
|
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
|
||||||
|
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
|
||||||
|
- Report: [Catch-provided main](../examples/200-Rpt-CatchMain.cpp)
|
||||||
|
- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
|
||||||
|
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||||
|
- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
|
||||||
|
|
||||||
|
## Planned
|
||||||
|
|
||||||
- Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
|
- Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
|
||||||
- Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
- Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
|
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
|
||||||
- Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
|
- Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
|
||||||
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
|
|
||||||
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
|
|
||||||
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
|
|
||||||
- Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
|
- Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
|
||||||
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
||||||
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
||||||
@@ -20,8 +30,10 @@
|
|||||||
- Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
|
- Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
|
||||||
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
|
- Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
|
||||||
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
||||||
- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
|
- Report: [User-defined reporter](../examples/202-Rpt-UserDefinedReporter.cpp)
|
||||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
- Report: [Automake reporter](../examples/205-Rpt-AutomakeReporter.cpp)
|
||||||
|
- Report: [TAP reporter](../examples/206-Rpt-TapReporter.cpp)
|
||||||
|
- Report: [Multiple reporter](../examples/208-Rpt-MultipleReporters.cpp)
|
||||||
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
||||||
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
||||||
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
||||||
|
@@ -72,12 +72,6 @@ This would log something like:
|
|||||||
|
|
||||||
<pre>"theAnswer := 42"</pre>
|
<pre>"theAnswer := 42"</pre>
|
||||||
|
|
||||||
## Deprecated macros
|
|
||||||
|
|
||||||
**SCOPED_INFO and SCOPED_CAPTURE**
|
|
||||||
|
|
||||||
These macros are now deprecated and are just aliases for INFO and CAPTURE (which were not previously scoped).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Home](Readme.md#top)
|
[Home](Readme.md#top)
|
||||||
|
@@ -53,6 +53,25 @@ The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts
|
|||||||
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
|
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
|
||||||
|
|
||||||
|
|
||||||
|
### Generic matchers
|
||||||
|
Catch also aims to provide a set of generic matchers. Currently this set
|
||||||
|
contains only a matcher that takes arbitrary callable predicate and applies
|
||||||
|
it onto the provided object.
|
||||||
|
|
||||||
|
Because of type inference limitations, the argument type of the predicate
|
||||||
|
has to be provided explicitly. Example:
|
||||||
|
```cpp
|
||||||
|
REQUIRE_THAT("Hello olleH",
|
||||||
|
Predicate<std::string>(
|
||||||
|
[] (std::string const& str) -> bool { return str.front() == str.back(); },
|
||||||
|
"First and last character should be equal")
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The second argument is an optional description of the predicate, and is
|
||||||
|
used only during reporting of the result.
|
||||||
|
|
||||||
|
|
||||||
## Custom matchers
|
## Custom matchers
|
||||||
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
||||||
|
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Open Source projects using Catch
|
# 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?
|
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.
|
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 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
|
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).
|
[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.
|
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.
|
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.
|
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
|
## 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
|
Boost Asio style bindings for ZeroMQ
|
||||||
|
|
||||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
### [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)
|
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
||||||
@@ -35,6 +35,9 @@ The next-generation core storage and query engine for Couchbase Lite
|
|||||||
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
||||||
A High-performance Cluster Computing Engine
|
A High-performance Cluster Computing Engine
|
||||||
|
|
||||||
|
### [forest](https://github.com/xorz57/forest)
|
||||||
|
Template Library of Tree Data Structures
|
||||||
|
|
||||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||||
|
|
||||||
@@ -44,6 +47,9 @@ A header-only template engine for modern C++.
|
|||||||
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||||
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
||||||
|
|
||||||
|
### [libcluon](https://github.com/chrberger/libcluon)
|
||||||
|
A single-header-only library written in C++14 to glue distributed software components (UDP, TCP, shared memory) supporting natively Protobuf, LCM/ZCM, MsgPack, and JSON for dynamic message transformations in-between.
|
||||||
|
|
||||||
### [MNMLSTC Core](https://github.com/mnmlstc/core)
|
### [MNMLSTC Core](https://github.com/mnmlstc/core)
|
||||||
A small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions.
|
A small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions.
|
||||||
|
|
||||||
@@ -65,6 +71,9 @@ A C++ client library for Consul. Consul is a distributed tool for discovering an
|
|||||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||||
A library of algorithms for values-distributed-in-time
|
A library of algorithms for values-distributed-in-time
|
||||||
|
|
||||||
|
### [thor](https://github.com/xorz57/thor)
|
||||||
|
Wrapper Library for CUDA
|
||||||
|
|
||||||
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
|
||||||
A small, single-header-only, library for wrapping and composing columns of text
|
A small, single-header-only, library for wrapping and composing columns of text
|
||||||
|
|
||||||
@@ -88,6 +97,9 @@ MAME originally stood for Multiple Arcade Machine Emulator
|
|||||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||||
|
|
||||||
|
### [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](https://github.com/foonathan/standardese)
|
||||||
Standardese aims to be a nextgen Doxygen
|
Standardese aims to be a nextgen Doxygen
|
||||||
|
|
||||||
|
150
docs/other-macros.md
Normal file
150
docs/other-macros.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<a id="top"></a>
|
||||||
|
# Other macros
|
||||||
|
|
||||||
|
This page serves as a reference for macros that are not documented
|
||||||
|
elsewhere. For now, these macros are separated into 2 rough categories,
|
||||||
|
"assertion related macros" and "test case related macros".
|
||||||
|
|
||||||
|
## Assertion related macros
|
||||||
|
|
||||||
|
* `CHECKED_IF` and `CHECKED_ELSE`
|
||||||
|
|
||||||
|
`CHECKED_IF( expr )` is an `if` replacement, that also applies Catch2's
|
||||||
|
stringification machinery to the _expr_ and records the result. As with
|
||||||
|
`if`, the block after a `CHECKED_IF` is entered only if the expression
|
||||||
|
evaluates to `true`. `CHECKED_ELSE( expr )` work similarly, but the block
|
||||||
|
is entered only if the _expr_ evaluated to `false`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
int a = ...;
|
||||||
|
int b = ...;
|
||||||
|
CHECKED_IF( a == b ) {
|
||||||
|
// This block is entered when a == b
|
||||||
|
} CHECKED_ELSE ( a == b ) {
|
||||||
|
// This block is entered when a != b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `CHECK_NOFAIL`
|
||||||
|
|
||||||
|
`CHECK_NOFAIL( expr )` is a variant of `CHECK` that does not fail the test
|
||||||
|
case if _expr_ evaluates to `false`. This can be useful for checking some
|
||||||
|
assumption, that might be violated without the test neccessarily failing.
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```
|
||||||
|
main.cpp:6:
|
||||||
|
FAILED - but was ok:
|
||||||
|
CHECK_NOFAIL( 1 == 2 )
|
||||||
|
|
||||||
|
main.cpp:7:
|
||||||
|
PASSED:
|
||||||
|
CHECK( 2 == 2 )
|
||||||
|
```
|
||||||
|
|
||||||
|
* `SUCCEED`
|
||||||
|
|
||||||
|
`SUCCEED( msg )` is mostly equivalent with `INFO( msg ); REQUIRE( true );`.
|
||||||
|
In other words, `SUCCEED` is for cases where just reaching a certain line
|
||||||
|
means that the test has been a success.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
```cpp
|
||||||
|
TEST_CASE( "SUCCEED showcase" ) {
|
||||||
|
int I = 1;
|
||||||
|
SUCCEED( "I is " << I );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `STATIC_REQUIRE`
|
||||||
|
|
||||||
|
`STATIC_REQUIRE( expr )` is a macro that can be used the same way as a
|
||||||
|
`static_assert`, but also registers the success with Catch2, so it is
|
||||||
|
reported as a success at runtime. The whole check can also be deferred
|
||||||
|
to the runtime, by defining `CATCH_CONFIG_RUNTIME_STATIC_REQUIRE` before
|
||||||
|
including the Catch2 header.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
TEST_CASE("STATIC_REQUIRE showcase", "[traits]") {
|
||||||
|
STATIC_REQUIRE( std::is_void<void>::value );
|
||||||
|
STATIC_REQUIRE_FALSE( std::is_void<int>::value );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test case related macros
|
||||||
|
|
||||||
|
* `METHOD_AS_TEST_CASE`
|
||||||
|
|
||||||
|
`METHOD_AS_TEST_CASE( member-function-pointer, description )` lets you
|
||||||
|
register a member function of a class as a Catch2 test case. The class
|
||||||
|
will be separately instantiated for each method registered in this way.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class TestClass {
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestClass()
|
||||||
|
:s( "hello" )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void testCase() {
|
||||||
|
REQUIRE( s == "hello" );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
METHOD_AS_TEST_CASE( TestClass::testCase, "Use class's method as a test case", "[class]" )
|
||||||
|
```
|
||||||
|
|
||||||
|
* `REGISTER_TEST_CASE`
|
||||||
|
|
||||||
|
`REGISTER_TEST_CASE( function, description )` let's you register
|
||||||
|
a `function` as a test case. The function has to have `void()` signature,
|
||||||
|
the description can contain both name and tags.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
REGISTER_TEST_CASE( someFunction, "ManuallyRegistered", "[tags]" );
|
||||||
|
```
|
||||||
|
|
||||||
|
_Note that the registration still has to happen before Catch2's session
|
||||||
|
is initiated. This means that it either needs to be done in a global
|
||||||
|
constructor, or before Catch2's session is created in user's own main._
|
||||||
|
|
||||||
|
|
||||||
|
* `ANON_TEST_CASE`
|
||||||
|
|
||||||
|
`ANON_TEST_CASE` is a `TEST_CASE` replacement that will autogenerate
|
||||||
|
unique name. The advantage of this is that you do not have to think
|
||||||
|
of a name for the test case,`the disadvantage is that the name doesn't
|
||||||
|
neccessarily remain stable across different links, and thus it might be
|
||||||
|
hard to run directly.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
ANON_TEST_CASE() {
|
||||||
|
SUCCEED("Hello from anonymous test case");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `DYNAMIC_SECTION`
|
||||||
|
|
||||||
|
`DYNAMIC_SECTION` is a `SECTION` where the user can use `operator<<` to
|
||||||
|
create the final name for that section. This can be useful with e.g.
|
||||||
|
generators, or when creating a `SECTION` dynamically, within a loop.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
TEST_CASE( "looped SECTION tests" ) {
|
||||||
|
int a = 1;
|
||||||
|
|
||||||
|
for( int b = 0; b < 10; ++b ) {
|
||||||
|
DYNAMIC_SECTION( "b is currently: " << b ) {
|
||||||
|
CHECK( b > a );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@@ -1,6 +1,12 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# Supplying main() yourself
|
# Supplying main() yourself
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[Let Catch take full control of args and config](#let-catch-take-full-control-of-args-and-config)<br>
|
||||||
|
[Amending the config](#amending-the-config)<br>
|
||||||
|
[Adding your own command line options](#adding-your-own-command-line-options)<br>
|
||||||
|
[Version detection](#version-detection)<br>
|
||||||
|
|
||||||
The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
|
The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
|
||||||
|
|
||||||
This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
|
This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
|
||||||
@@ -30,7 +36,7 @@ int main( int argc, char* argv[] ) {
|
|||||||
|
|
||||||
## Amending the config
|
## 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++
|
```c++
|
||||||
#define CATCH_CONFIG_RUNNER
|
#define CATCH_CONFIG_RUNNER
|
||||||
@@ -45,7 +51,7 @@ int main( int argc, char* argv[] )
|
|||||||
|
|
||||||
int returnCode = session.applyCommandLine( argc, argv );
|
int returnCode = session.applyCommandLine( argc, argv );
|
||||||
if( returnCode != 0 ) // Indicates a command line error
|
if( returnCode != 0 ) // Indicates a command line error
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
// writing to session.configData() or session.Config() here
|
// writing to session.configData() or session.Config() here
|
||||||
// overrides command line args
|
// overrides command line args
|
||||||
@@ -81,6 +87,7 @@ int main( int argc, char* argv[] )
|
|||||||
int height = 0; // Some user variable you want to be able to set
|
int height = 0; // Some user variable you want to be able to set
|
||||||
|
|
||||||
// Build a new parser on top of Catch's
|
// Build a new parser on top of Catch's
|
||||||
|
using namespace Catch::clara;
|
||||||
auto cli
|
auto cli
|
||||||
= session.cli() // Get Catch's composite command line parser
|
= session.cli() // Get Catch's composite command line parser
|
||||||
| Opt( height, "height" ) // bind variable to a new option, with a hint string
|
| Opt( height, "height" ) // bind variable to a new option, with a hint string
|
||||||
@@ -93,7 +100,7 @@ int main( int argc, char* argv[] )
|
|||||||
// Let Catch (using Clara) parse the command line
|
// Let Catch (using Clara) parse the command line
|
||||||
int returnCode = session.applyCommandLine( argc, argv );
|
int returnCode = session.applyCommandLine( argc, argv );
|
||||||
if( returnCode != 0 ) // Indicates a command line error
|
if( returnCode != 0 ) // Indicates a command line error
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
// if set on the command line then 'height' is now set at this point
|
// if set on the command line then 'height' is now set at this point
|
||||||
if( height > 0 )
|
if( height > 0 )
|
||||||
@@ -105,6 +112,20 @@ int main( int argc, char* argv[] )
|
|||||||
|
|
||||||
See the [Clara documentation](https://github.com/philsquared/Clara/blob/master/README.md) for more details.
|
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)
|
[Home](Readme.md#top)
|
||||||
|
@@ -1,8 +1,255 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
|
|
||||||
# 2.1.0
|
# Release notes
|
||||||
|
**Contents**<br>
|
||||||
|
[2.4.2](#242)<br>
|
||||||
|
[2.4.1](#241)<br>
|
||||||
|
[2.4.0](#240)<br>
|
||||||
|
[2.3.0](#230)<br>
|
||||||
|
[2.2.3](#223)<br>
|
||||||
|
[2.2.2](#222)<br>
|
||||||
|
[2.2.1](#221)<br>
|
||||||
|
[2.2.0](#220)<br>
|
||||||
|
[2.1.2](#212)<br>
|
||||||
|
[2.1.1](#211)<br>
|
||||||
|
[2.1.0](#210)<br>
|
||||||
|
[2.0.1](#201)<br>
|
||||||
|
[Older versions](#older-versions)<br>
|
||||||
|
[Even Older versions](#even-older-versions)<br>
|
||||||
|
|
||||||
## Improvements
|
|
||||||
|
## 2.4.2
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* XmlReporter now also outputs the RNG seed that was used in a run (#1404)
|
||||||
|
* `Catch::Session::applyCommandLine` now also accepts `wchar_t` arguments.
|
||||||
|
* However, Catch2 still does not support unicode.
|
||||||
|
* Added `STATIC_REQUIRE` macro (#1356, #1362)
|
||||||
|
* Catch2's singleton's are now cleaned up even if tests are run (#1411)
|
||||||
|
* This is mostly useful as a FP prevention for users who define their own main.
|
||||||
|
* Specifying an invalid reporter via `-r` is now reported sooner (#1351, #1422)
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Stringification no longer assumes that `char` is signed (#1399, #1407)
|
||||||
|
* This caused a `Wtautological-compare` warning.
|
||||||
|
* SFINAE for `operator<<` no longer sees different overload set than the actual insertion (#1403)
|
||||||
|
|
||||||
|
|
||||||
|
### Contrib
|
||||||
|
* `catch_discover_tests` correctly adds tests with comma in name (#1327, #1409)
|
||||||
|
* Added a new customization point in how the tests are launched to `catch_discover_tests`
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added a StringMaker for `std::(w)string_view` (#1375, #1376)
|
||||||
|
* Added a StringMaker for `std::variant` (#1380)
|
||||||
|
* This one is disabled by default to avoid increased compile-time drag
|
||||||
|
* Added detection for cygwin environment without `std::to_string` (#1396, #1397)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* `UnorderedEqualsMatcher` will no longer accept erroneously accept
|
||||||
|
vectors that share suffix, but are not permutation of the desired vector
|
||||||
|
* Abort after (`-x N`) can no longer be overshot by nested `REQUIRES` and
|
||||||
|
subsequently ignored (#1391, #1392)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
|
||||||
|
**This release brings two new experimental features, generator support
|
||||||
|
and a `-fno-exceptions` support. Being experimental means that they
|
||||||
|
will not be subject to the usual stability guarantees provided by semver.**
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Various small runtime performance improvements
|
||||||
|
* `CAPTURE` macro is now variadic
|
||||||
|
* Added `AND_GIVEN` macro (#1360)
|
||||||
|
* Added experimental support for data generators
|
||||||
|
* See [their documentation](generators.md) for details
|
||||||
|
* Added support for compiling and running Catch without exceptions
|
||||||
|
* Doing so limits the functionality somewhat
|
||||||
|
* Look [into the documentation](configuration.md#disablingexceptions) for details
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Suppressed `-Wnon-virtual-dtor` warnings in Matchers (#1357)
|
||||||
|
* Suppressed `-Wunreachable-code` warnings in floating point matchers (#1350)
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
* It is now possible to override which Python is used to run Catch's tests (#1365)
|
||||||
|
* Catch now provides infrastructure for adding tests that check compile-time configuration
|
||||||
|
* Catch no longer tries to install itself when used as a subproject (#1373)
|
||||||
|
* Catch2ConfigVersion.cmake is now generated as arch-independent (#1368)
|
||||||
|
* This means that installing Catch from 32-bit machine and copying it to 64-bit one works
|
||||||
|
* This fixes conan installation of Catch
|
||||||
|
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
|
||||||
|
**This release changes the include paths provided by our CMake and
|
||||||
|
pkg-config integration. The proper include path for the single-header
|
||||||
|
when using one of the above is now `<catch2/catch.hpp>`. This change
|
||||||
|
also necessitated changes to paths inside the repository, so that the
|
||||||
|
single-header version is now at `single_include/catch2/catch.hpp`, rather
|
||||||
|
than `single_include/catch.hpp`.**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed Objective-C++ build
|
||||||
|
* `-Wunused-variable` suppression no longer leaks from Catch's header under Clang
|
||||||
|
* Implementation of the experimental new output capture can now be disabled (#1335)
|
||||||
|
* This allows building Catch2 on platforms that do not provide things like `dup` or `tmpfile`.
|
||||||
|
* The JUnit and XML reporters will no longer skip over successful tests when running without `-s` (#1264, #1267, #1310)
|
||||||
|
* See improvements for more details
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* pkg-config and CMake integration has been rewritten
|
||||||
|
* If you use them, the new include path is `#include <catch2/catch.hpp>`
|
||||||
|
* CMake installation now also installs scripts from `contrib/`
|
||||||
|
* For details see the [new documentation](cmake-integration.md#top)
|
||||||
|
* Reporters now have a new customization point, `ReporterPreferences::shouldReportAllAssertions`
|
||||||
|
* When this is set to `false` and the tests are run without `-s`, passing assertions are not sent to the reporter.
|
||||||
|
* Defaults to `false`.
|
||||||
|
* Added `DYNAMIC_SECTION`, a section variant that constructs its name using stream
|
||||||
|
* This means that you can do `DYNAMIC_SECTION("For X := " << x)`.
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.3
|
||||||
|
|
||||||
|
**To fix some of the bugs, some behavior had to change in potentially breaking manner.**
|
||||||
|
**This means that even though this is a patch release, it might not be a drop-in replacement.**
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Listeners are now called before reporter
|
||||||
|
* This was always documented to be the case, now it actually works that way
|
||||||
|
* Catch's commandline will no longer accept multiple reporters
|
||||||
|
* This was done because multiple reporters never worked properly and broke things in non-obvious ways
|
||||||
|
* **This has potential to be a breaking change**
|
||||||
|
* MinGW is now detected as Windows platform w/o SEH support (#1257)
|
||||||
|
* This means that Catch2 no longer tries to use POSIX signal handling when compiled with MinGW
|
||||||
|
* Fixed potential UB in parsing tags using non-ASCII characters (#1266)
|
||||||
|
* Note that Catch2 still supports only ASCII test names/tags/etc
|
||||||
|
* `TEST_CASE_METHOD` can now be used on classnames containing commas (#1245)
|
||||||
|
* You have to enclose the classname in extra set of parentheses
|
||||||
|
* Fixed insufficient alt stack size for POSIX signal handling (#1225)
|
||||||
|
* Fixed compilation error on Android due to missing `std::to_string` in C++11 mode (#1280)
|
||||||
|
* Fixed the order of user-provided `FALLBACK_STRINGIFIER` in stringification machinery (#1024)
|
||||||
|
* It was intended to be replacement for built-in fallbacks, but it was used _after_ them.
|
||||||
|
* **This has potential to be a breaking change**
|
||||||
|
* Fixed compilation error when a type has an `operator<<` with templated lhs (#1285, #1306)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* Added a new, experimental, output capture (#1243)
|
||||||
|
* This capture can also redirect output written via C apis, e.g. `printf`
|
||||||
|
* To opt-in, define `CATCH_CONFIG_EXPERIMENTAL_REDIRECT` in the implementation file
|
||||||
|
* Added a new fallback stringifier for classes derived from `std::exception`
|
||||||
|
* Both `StringMaker` specialization and `operator<<` overload are given priority
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* `contrib/` now contains dbg scripts that skip over Catch's internals (#904, #1283)
|
||||||
|
* `gdbinit` for gdb `lldbinit` for lldb
|
||||||
|
* `CatchAddTests.cmake` no longer strips whitespace from tests (#1265, #1281)
|
||||||
|
* Online documentation now describes `--use-colour` option (#1263)
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed bug in `WithinAbs::match()` failing spuriously (#1228)
|
||||||
|
* Fixed clang-tidy diagnostic about virtual call in destructor (#1226)
|
||||||
|
* Reduced the number of GCC warnings suppression leaking out of the header (#1090, #1091)
|
||||||
|
* Only `-Wparentheses` should be leaking now
|
||||||
|
* Added upper bound on the time benchmark timer calibration is allowed to take (#1237)
|
||||||
|
* On platforms where `std::chrono::high_resolution_clock`'s resolution is low, the calibration would appear stuck
|
||||||
|
* Fixed compilation error when stringifying static arrays of `unsigned char`s (#1238)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* XML encoder now hex-encodes invalid UTF-8 sequences (#1207)
|
||||||
|
* This affects xml and junit reporters
|
||||||
|
* Some invalid UTF-8 parts are left as is, e.g. surrogate pairs. This is because certain extensions of UTF-8 allow them, such as WTF-8.
|
||||||
|
* CLR objects (`T^`) can now be stringified (#1216)
|
||||||
|
* This affects code compiled as C++/CLI
|
||||||
|
* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236)
|
||||||
|
* See [documentation for details](https://github.com/catchorg/Catch2/blob/master/docs/matchers.md)
|
||||||
|
|
||||||
|
### Others
|
||||||
|
* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
|
||||||
|
* The plans to standardize on `#include <catch2/catch.hpp>` are still in effect
|
||||||
|
|
||||||
|
|
||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
|
||||||
|
* 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
|
||||||
|
* Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
|
||||||
|
* Embedded newer version of Clara -- v1.1.1
|
||||||
|
* This should fix some warnings dragged in from Clara
|
||||||
|
* MSVC's CLR exceptions are supported
|
||||||
|
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fixed compilation when comparison operators do not return bool (#1147)
|
||||||
|
* Fixed CLR exceptions blowing up the executable during translation (#1138)
|
||||||
|
|
||||||
|
|
||||||
|
### Other changes
|
||||||
|
* Many CMake changes
|
||||||
|
* `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
|
||||||
|
* Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
|
||||||
|
* Other changes to simplify Catch2's packaging
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Improvements
|
||||||
* Various performance improvements
|
* Various performance improvements
|
||||||
* On top of the performance regression fixes
|
* On top of the performance regression fixes
|
||||||
* Experimental support for PCH was added (#1061)
|
* Experimental support for PCH was added (#1061)
|
||||||
@@ -12,7 +259,7 @@
|
|||||||
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
|
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
|
||||||
|
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Fixed performance regression from Catch classic
|
* Fixed performance regression from Catch classic
|
||||||
* One of the performance improvement patches for Catch classic was not applied to Catch2
|
* One of the performance improvement patches for Catch classic was not applied to Catch2
|
||||||
* Fixed platform detection for iOS (#1084)
|
* Fixed platform detection for iOS (#1084)
|
||||||
@@ -25,7 +272,7 @@
|
|||||||
* Fixed `std::uncaught_exception` deprecation warning (#1124)
|
* Fixed `std::uncaught_exception` deprecation warning (#1124)
|
||||||
|
|
||||||
|
|
||||||
## New features
|
### New features
|
||||||
* New Matchers
|
* New Matchers
|
||||||
* Regex matcher for strings, `Matches`.
|
* Regex matcher for strings, `Matches`.
|
||||||
* Set-equal matcher for vectors, `UnorderedEquals`
|
* Set-equal matcher for vectors, `UnorderedEquals`
|
||||||
@@ -34,15 +281,15 @@
|
|||||||
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
|
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
|
||||||
|
|
||||||
|
|
||||||
## Other changes
|
### Other changes
|
||||||
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
|
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
## Breaking changes
|
### Breaking changes
|
||||||
* Removed C++98 support
|
* Removed C++98 support
|
||||||
* Removed legacy reporter support
|
* Removed legacy reporter support
|
||||||
* Removed legacy generator support
|
* Removed legacy generator support
|
||||||
@@ -72,7 +319,7 @@
|
|||||||
* `INFINITY == Approx(INFINITY)` returns true
|
* `INFINITY == Approx(INFINITY)` returns true
|
||||||
|
|
||||||
|
|
||||||
## Improvements
|
### Improvements
|
||||||
* Reporters and Listeners can be defined in files different from the main file
|
* Reporters and Listeners can be defined in files different from the main file
|
||||||
* The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
|
* The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
|
||||||
* Errors that happen during set up before main are now caught and properly reported once main is entered
|
* Errors that happen during set up before main are now caught and properly reported once main is entered
|
||||||
@@ -106,7 +353,7 @@
|
|||||||
* Add `pkg-config` support to CMake install command
|
* Add `pkg-config` support to CMake install command
|
||||||
|
|
||||||
|
|
||||||
## Fixes
|
### Fixes
|
||||||
* Don't use console colour if running in XCode
|
* Don't use console colour if running in XCode
|
||||||
* Explicit constructor in reporter base class
|
* Explicit constructor in reporter base class
|
||||||
* Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
|
* Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
|
||||||
@@ -118,7 +365,7 @@
|
|||||||
* Suppressed C4061 warning under MSVC
|
* Suppressed C4061 warning under MSVC
|
||||||
|
|
||||||
|
|
||||||
## Internal changes
|
### Internal changes
|
||||||
* The development version now uses .cpp files instead of header files containing implementation.
|
* The development version now uses .cpp files instead of header files containing implementation.
|
||||||
* This makes partial rebuilds much faster during development
|
* This makes partial rebuilds much faster during development
|
||||||
* The expression decomposition layer has been rewritten
|
* The expression decomposition layer has been rewritten
|
||||||
@@ -126,13 +373,33 @@
|
|||||||
* New library (TextFlow) is used for formatting text to output
|
* New library (TextFlow) is used for formatting text to output
|
||||||
|
|
||||||
|
|
||||||
# Older versions
|
## Older versions
|
||||||
|
|
||||||
## 1.11.x
|
### 1.12.x
|
||||||
|
|
||||||
### 1.11.0
|
#### 1.12.2
|
||||||
|
##### Fixes
|
||||||
|
* Fixed missing <cassert> include
|
||||||
|
|
||||||
#### Fixes
|
#### 1.12.1
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
|
* Fixed deprecation warning in `ScopedMessage::~ScopedMessage`
|
||||||
|
* All uses of `min` or `max` identifiers are now wrapped in parentheses
|
||||||
|
* This avoids problems when Windows headers define `min` and `max` macros
|
||||||
|
|
||||||
|
#### 1.12.0
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
|
* Fixed compilation for strict C++98 mode (ie not gnu++98) and older compilers (#1103)
|
||||||
|
* `INFO` messages are included in the `xml` reporter output even without `-s` specified.
|
||||||
|
|
||||||
|
|
||||||
|
### 1.11.x
|
||||||
|
|
||||||
|
#### 1.11.0
|
||||||
|
|
||||||
|
##### Fixes
|
||||||
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
|
* The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
|
||||||
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
|
* Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
|
||||||
* `Approx::Margin` is now inclusive (#952)
|
* `Approx::Margin` is now inclusive (#952)
|
||||||
@@ -140,7 +407,7 @@
|
|||||||
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
|
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
|
||||||
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
|
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
|
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
|
||||||
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
|
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
|
||||||
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
|
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
|
||||||
@@ -148,35 +415,35 @@
|
|||||||
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
|
* `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
|
||||||
* This means you do not have to manually rerun CMake configuration step to detect new tests
|
* This means you do not have to manually rerun CMake configuration step to detect new tests
|
||||||
|
|
||||||
## 1.10.x
|
### 1.10.x
|
||||||
|
|
||||||
### 1.10.0
|
#### 1.10.0
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Evaluation layer has been rewritten (backported from Catch 2)
|
* Evaluation layer has been rewritten (backported from Catch 2)
|
||||||
* The new layer is much simpler and fixes some issues (#981)
|
* The new layer is much simpler and fixes some issues (#981)
|
||||||
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
|
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
|
||||||
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
|
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
|
||||||
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
|
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
|
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
|
||||||
* Added "wait-for-keypress" option
|
* Added "wait-for-keypress" option
|
||||||
|
|
||||||
## 1.9.x
|
### 1.9.x
|
||||||
|
|
||||||
### 1.9.6
|
#### 1.9.6
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* Catch's runtime overhead has been significantly decreased (#937, #939)
|
* Catch's runtime overhead has been significantly decreased (#937, #939)
|
||||||
* Added `--list-extra-info` cli option (#934).
|
* Added `--list-extra-info` cli option (#934).
|
||||||
* It lists all tests together with extra information, ie filename, line number and description.
|
* It lists all tests together with extra information, ie filename, line number and description.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.9.5
|
#### 1.9.5
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Truthy expressions are now reconstructed properly, not as booleans (#914)
|
* Truthy expressions are now reconstructed properly, not as booleans (#914)
|
||||||
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
|
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
|
||||||
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
|
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
|
||||||
@@ -184,35 +451,35 @@
|
|||||||
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
|
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
|
||||||
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
|
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
|
||||||
|
|
||||||
#### Improvements
|
##### Improvements
|
||||||
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
|
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
|
||||||
* Various documentation improvements
|
* Various documentation improvements
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.9.4
|
#### 1.9.4
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
|
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
|
||||||
* `INFO` messages are no longer cleared after being reported once
|
* `INFO` messages are no longer cleared after being reported once
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
|
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
|
||||||
* Note that Catch still officially supports only ASCII
|
* Note that Catch still officially supports only ASCII
|
||||||
|
|
||||||
### 1.9.3
|
#### 1.9.3
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
|
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
|
||||||
|
|
||||||
### 1.9.2
|
#### 1.9.2
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
|
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
|
||||||
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
|
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
|
||||||
|
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* POSIX signals are now disabled by default under QNX (#889)
|
* POSIX signals are now disabled by default under QNX (#889)
|
||||||
* QNX does not support current enough (2001) POSIX specification
|
* QNX does not support current enough (2001) POSIX specification
|
||||||
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
|
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
|
||||||
@@ -220,22 +487,22 @@
|
|||||||
* Catch no longer attempts to define `uint64_t` on windows (#862)
|
* Catch no longer attempts to define `uint64_t` on windows (#862)
|
||||||
* This was causing trouble when compiled under Cygwin
|
* This was causing trouble when compiled under Cygwin
|
||||||
|
|
||||||
#### Other
|
##### Other
|
||||||
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
|
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
|
||||||
* We now provide cmake script that autoregisters Catch tests into ctest.
|
* We now provide cmake script that autoregisters Catch tests into ctest.
|
||||||
* See `contrib` folder.
|
* See `contrib` folder.
|
||||||
|
|
||||||
|
|
||||||
### 1.9.1
|
#### 1.9.1
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Unexpected exceptions are no longer ignored by default (#885, #887)
|
* Unexpected exceptions are no longer ignored by default (#885, #887)
|
||||||
|
|
||||||
|
|
||||||
### 1.9.0
|
#### 1.9.0
|
||||||
|
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
|
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
|
||||||
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
|
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
|
||||||
* This actually reverts changes made in v1.7.2
|
* This actually reverts changes made in v1.7.2
|
||||||
@@ -249,7 +516,7 @@
|
|||||||
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
|
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
|
||||||
* Captured messages are now printed on unexpected exceptions
|
* Captured messages are now printed on unexpected exceptions
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
|
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
|
||||||
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
|
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
|
||||||
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
|
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
|
||||||
@@ -258,18 +525,18 @@
|
|||||||
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
|
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
|
||||||
|
|
||||||
|
|
||||||
#### Other notes:
|
##### Other notes:
|
||||||
* We have added VS 2017 to our CI
|
* We have added VS 2017 to our CI
|
||||||
* Work on Catch 2 should start soon
|
* Work on Catch 2 should start soon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 1.8.x
|
### 1.8.x
|
||||||
|
|
||||||
### 1.8.2
|
#### 1.8.2
|
||||||
|
|
||||||
|
|
||||||
#### Improvements and minor changes
|
##### Improvements and minor changes
|
||||||
* TAP reporter now behaves as if `-s` was always set
|
* TAP reporter now behaves as if `-s` was always set
|
||||||
* This should be more consistent with the protocol desired behaviour.
|
* This should be more consistent with the protocol desired behaviour.
|
||||||
* Compact reporter now obeys `-d yes` argument (#780)
|
* Compact reporter now obeys `-d yes` argument (#780)
|
||||||
@@ -283,7 +550,7 @@
|
|||||||
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
|
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
|
||||||
|
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
|
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
|
||||||
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
|
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
|
||||||
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
|
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
|
||||||
@@ -300,21 +567,21 @@
|
|||||||
* Regression in Objective-C bindings (Matchers) fixed (#854)
|
* Regression in Objective-C bindings (Matchers) fixed (#854)
|
||||||
|
|
||||||
|
|
||||||
#### Other notes:
|
##### Other notes:
|
||||||
* We have added VS 2013 and 2015 to our CI
|
* We have added VS 2013 and 2015 to our CI
|
||||||
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
|
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 1.8.1
|
#### 1.8.1
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
|
|
||||||
Cygwin issue with `gettimeofday` - `#define` was not early enough
|
Cygwin issue with `gettimeofday` - `#define` was not early enough
|
||||||
|
|
||||||
### 1.8.0
|
#### 1.8.0
|
||||||
|
|
||||||
#### New features/ minor changes
|
##### New features/ minor changes
|
||||||
|
|
||||||
* Matchers have new, simpler (and documented) interface.
|
* Matchers have new, simpler (and documented) interface.
|
||||||
* Catch provides string and vector matchers.
|
* Catch provides string and vector matchers.
|
||||||
@@ -334,33 +601,33 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
|
|||||||
* `Approx` now supports an optional margin of absolute error
|
* `Approx` now supports an optional margin of absolute error
|
||||||
* It has also received [new documentation](assertions.md#top).
|
* It has also received [new documentation](assertions.md#top).
|
||||||
|
|
||||||
#### Fixes
|
##### Fixes
|
||||||
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
|
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
|
||||||
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
|
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
|
||||||
* Cygwin compatibility fixes
|
* Cygwin compatibility fixes
|
||||||
* Signal handling is no longer compiled by default.
|
* Signal handling is no longer compiled by default.
|
||||||
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
|
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
|
||||||
* Improved `-Wparentheses` supression for gcc (#674)
|
* Improved `-Wparentheses` suppression for gcc (#674)
|
||||||
* When compiled with gcc 4.8 or newer, the supression is localized to assertions only
|
* When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
|
||||||
* Otherwise it is supressed for the whole TU
|
* Otherwise it is supressed for the whole TU
|
||||||
* Fixed test spec parser issue (with escapes in multiple names)
|
* Fixed test spec parser issue (with escapes in multiple names)
|
||||||
|
|
||||||
#### Other
|
##### Other
|
||||||
* Various documentation fixes and improvements
|
* Various documentation fixes and improvements
|
||||||
|
|
||||||
|
|
||||||
## 1.7.x
|
### 1.7.x
|
||||||
|
|
||||||
### 1.7.2
|
#### 1.7.2
|
||||||
|
|
||||||
#### Fixes and minor improvements
|
##### Fixes and minor improvements
|
||||||
Xml:
|
Xml:
|
||||||
|
|
||||||
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
|
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
|
||||||
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
|
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
|
||||||
* Revert XML output to XML 1.0
|
* Revert XML output to XML 1.0
|
||||||
* Can provide stylesheet references by extending the XML reporter
|
* 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
|
* Tags are closed and the stream flushed more eagerly to avoid stdout interpolation
|
||||||
|
|
||||||
|
|
||||||
@@ -372,9 +639,9 @@ Other:
|
|||||||
* Silenced a few more warnings in different circumstances
|
* Silenced a few more warnings in different circumstances
|
||||||
* Travis improvements
|
* Travis improvements
|
||||||
|
|
||||||
### 1.7.1
|
#### 1.7.1
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
|
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
|
||||||
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
|
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
|
||||||
* For specifics, look into the [documentation](configuration.md#top).
|
* For specifics, look into the [documentation](configuration.md#top).
|
||||||
@@ -384,9 +651,9 @@ Other:
|
|||||||
* Fixed possible infinite recursion in Windows SEH.
|
* Fixed possible infinite recursion in Windows SEH.
|
||||||
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
|
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
|
||||||
|
|
||||||
### 1.7.0
|
#### 1.7.0
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Catch now runs significantly faster for passing tests
|
* Catch now runs significantly faster for passing tests
|
||||||
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
||||||
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
||||||
@@ -400,30 +667,30 @@ Other:
|
|||||||
* Certain characters (space, tab, etc) are now pretty printed.
|
* Certain characters (space, tab, etc) are now pretty printed.
|
||||||
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
||||||
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
||||||
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
||||||
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Catch's CMakeLists now defines install command.
|
* Catch's CMakeLists now defines install command.
|
||||||
* Catch's CMakeLists now generates projects with warnings enabled.
|
* Catch's CMakeLists now generates projects with warnings enabled.
|
||||||
|
|
||||||
|
|
||||||
## 1.6.x
|
### 1.6.x
|
||||||
|
|
||||||
### 1.6.1
|
#### 1.6.1
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Catch now supports breaking into debugger on Linux
|
* Catch now supports breaking into debugger on Linux
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Generators no longer leak memory (generators are still unsupported in general)
|
* Generators no longer leak memory (generators are still unsupported in general)
|
||||||
* JUnit reporter now reports UTC timestamps, instead of "tbd"
|
* JUnit reporter now reports UTC timestamps, instead of "tbd"
|
||||||
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
|
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
|
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
|
||||||
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
|
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
|
||||||
* This change is not active when compiling a binary
|
* This change is not active when compiling a binary
|
||||||
@@ -433,28 +700,28 @@ Other:
|
|||||||
* This can be disabled if needed, see [documentation](configuration.md#top) for details.
|
* This can be disabled if needed, see [documentation](configuration.md#top) for details.
|
||||||
|
|
||||||
|
|
||||||
### 1.6.0
|
#### 1.6.0
|
||||||
|
|
||||||
#### Cmake/ projects:
|
##### Cmake/ projects:
|
||||||
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
|
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
|
||||||
|
|
||||||
#### Features/ Changes:
|
##### Features/ Changes:
|
||||||
* Approx now supports `>=` and `<=`
|
* Approx now supports `>=` and `<=`
|
||||||
* Can now use `\` to escape chars in test names on command line
|
* Can now use `\` to escape chars in test names on command line
|
||||||
* Standardize C++11 feature toggles
|
* Standardize C++11 feature toggles
|
||||||
|
|
||||||
#### Fixes:
|
##### Fixes:
|
||||||
* Blue shell colour
|
* Blue shell colour
|
||||||
* Missing argument to `CATCH_CHECK_THROWS`
|
* Missing argument to `CATCH_CHECK_THROWS`
|
||||||
* Don't encode extended ASCII in XML
|
* Don't encode extended ASCII in XML
|
||||||
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
|
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
|
||||||
* Use `__COUNTER__` more consistently (where available)
|
* Use `__COUNTER__` more consistently (where available)
|
||||||
|
|
||||||
#### Other:
|
##### Other:
|
||||||
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
|
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
|
||||||
|
|
||||||
|
|
||||||
# Even Older versions
|
## Even Older versions
|
||||||
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# How to release
|
# 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
|
### Approval testing
|
||||||
@@ -21,10 +21,8 @@ Catch uses a variant of [semantic versioning](http://semver.org/), with breaking
|
|||||||
|
|
||||||
After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch.
|
After deciding which part of version number should be incremented, you can use one of the `*Release.py` scripts to perform the required changes to Catch.
|
||||||
|
|
||||||
|
This will take care of generating the single include header, updating
|
||||||
### Generate updated single-include header
|
version numbers everywhere and pushing the new version to Wandbox.
|
||||||
|
|
||||||
After updating version number, regenerate single-include header using `generateSingleHeader.py`.
|
|
||||||
|
|
||||||
|
|
||||||
### Release notes
|
### Release notes
|
||||||
@@ -39,26 +37,17 @@ After version number is incremented, single-include header is regenerated and re
|
|||||||
|
|
||||||
### Release on GitHub
|
### Release on GitHub
|
||||||
|
|
||||||
After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings.
|
After pushing changes to GitHub, GitHub release *needs* to be created.
|
||||||
|
Tag version and release title should be same as the new version,
|
||||||
|
description should contain the release notes for the current release.
|
||||||
|
Single header version of `catch.hpp` *needs* to be attached as a binary,
|
||||||
|
as that is where the official download link links to. Preferably
|
||||||
|
it should use linux line endings. All non-bundled reporters (Automake,
|
||||||
|
TAP, TeamCity) should also be attached as binaries, as they are dependent
|
||||||
|
on a specific version of the single-include header.
|
||||||
|
|
||||||
|
|
||||||
## Optional steps
|
## Optional steps
|
||||||
|
|
||||||
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they are *should* happen, but they can happen the next day without losing anything significant.
|
Because Catch's [vcpkg](https://github.com/Microsoft/vcpkg) port updates
|
||||||
|
itself automagically, there are no optional steps at this time.
|
||||||
|
|
||||||
### vcpkg update
|
|
||||||
|
|
||||||
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of 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
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Wandbox update
|
|
||||||
|
|
||||||
Recently we also included a link to wandbox with preloaded Catch on the main page. Strictly speaking it is unneccessary to update this after every release, Catch usually does not change that much between versions, but it should be kept up to date anyway.
|
|
||||||
|
|
||||||
|
@@ -25,8 +25,8 @@ Because of the way the junit format is structured the run must complete before a
|
|||||||
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
|
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
|
||||||
Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
|
Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
|
||||||
|
|
||||||
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
|
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
|
||||||
Use this when building as part of a TeamCity build to see results as they happen.
|
Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
|
||||||
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
||||||
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
||||||
|
|
||||||
|
@@ -20,10 +20,10 @@ Tags allow an arbitrary number of additional strings to be associated with a tes
|
|||||||
|
|
||||||
As an example - given the following test cases:
|
As an example - given the following test cases:
|
||||||
|
|
||||||
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
TEST_CASE( "A", "[widget]" ) { /* ... */ }
|
||||||
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
TEST_CASE( "B", "[widget]" ) { /* ... */ }
|
||||||
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
TEST_CASE( "C", "[gadget]" ) { /* ... */ }
|
||||||
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
|
||||||
|
|
||||||
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
|
The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
|||||||
|
|
||||||
* `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
* `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
||||||
|
|
||||||
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
|
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
|
||||||
|
|
||||||
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
* `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
||||||
|
|
||||||
@@ -55,11 +55,11 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
|||||||
|
|
||||||
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
|
Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
|
||||||
|
|
||||||
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
|
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
|
||||||
|
|
||||||
Aliases must begin with the `@` character. An example of a tag alias is:
|
Aliases must begin with the `@` character. An example of a tag alias is:
|
||||||
|
|
||||||
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
|
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
|
||||||
|
|
||||||
Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.
|
Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
<a id="top"></a>
|
<a id="top"></a>
|
||||||
# String conversions
|
# String conversions
|
||||||
|
|
||||||
|
**Contents**<br>
|
||||||
|
[operator << overload for std::ostream](#operator--overload-for-stdostream)<br>
|
||||||
|
[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
|
||||||
|
[Catch::is_range specialisation](#catchis_range-specialisation)<br>
|
||||||
|
[Exceptions](#exceptions)<br>
|
||||||
|
|
||||||
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
|
Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
|
||||||
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
|
||||||
|
|
||||||
@@ -10,8 +16,8 @@ This is the standard way of providing string conversions in C++ - and the chance
|
|||||||
|
|
||||||
```
|
```
|
||||||
std::ostream& operator << ( std::ostream& os, T const& value ) {
|
std::ostream& operator << ( std::ostream& os, T const& value ) {
|
||||||
os << convertMyTypeToString( value );
|
os << convertMyTypeToString( value );
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -19,27 +25,44 @@ std::ostream& operator << ( std::ostream& os, T const& value ) {
|
|||||||
|
|
||||||
You should put this function in the same namespace as your type and have it declared before including Catch's header.
|
You should put this function in the same namespace as your type and have it declared before including Catch's header.
|
||||||
|
|
||||||
## Catch::StringMaker<T> specialisation
|
## Catch::StringMaker specialisation
|
||||||
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
|
If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
|
||||||
|
|
||||||
```
|
```
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<T> {
|
struct StringMaker<T> {
|
||||||
static std::string convert( T const& value ) {
|
static std::string convert( T const& value ) {
|
||||||
return convertMyTypeToString( value );
|
return convertMyTypeToString( value );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Catch::is_range 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
|
## 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:
|
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:
|
||||||
|
|
||||||
```
|
```
|
||||||
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
|
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
|
||||||
return ex.message();
|
return ex.message();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
## Getting Catch2
|
## Getting Catch2
|
||||||
|
|
||||||
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/CatchOrg/Catch2/master/single_include/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
|
The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
|
||||||
|
|
||||||
|
Alternative ways of getting Catch2 include using your system package
|
||||||
|
manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).
|
||||||
|
|
||||||
The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
|
The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
|
||||||
|
|
||||||
@@ -23,6 +26,9 @@ Catch2 is header only. All you need to do is drop the file somewhere reachable f
|
|||||||
|
|
||||||
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
|
||||||
|
|
||||||
|
_If you have installed Catch2 from system package manager, or CMake
|
||||||
|
package, you need to include the header as `#include <catch2/catch.hpp>`_
|
||||||
|
|
||||||
## Writing tests
|
## Writing tests
|
||||||
|
|
||||||
Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
|
Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
// That's it
|
// That's it
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
int Factorial( int number ) {
|
int Factorial( int number ) {
|
||||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
// Let Catch provide main():
|
// Let Catch provide main():
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
|
TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// main() provided by Catch in file 020-TestCase-1.cpp.
|
// main() provided by Catch in file 020-TestCase-1.cpp.
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
int Factorial( int number ) {
|
int Factorial( int number ) {
|
||||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
std::string one() {
|
std::string one() {
|
||||||
return "1";
|
return "1";
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
class DBConnection
|
class DBConnection
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// main() provided in 000-CatchMain.cpp
|
// main() provided in 000-CatchMain.cpp
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
||||||
|
|
||||||
|
27
examples/200-Rpt-CatchMain.cpp
Normal file
27
examples/200-Rpt-CatchMain.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 200-Rpt-CatchMain.cpp
|
||||||
|
|
||||||
|
// In a Catch project with multiple files, dedicate one file to compile the
|
||||||
|
// source code of Catch itself and reuse the resulting object file for linking.
|
||||||
|
|
||||||
|
// Let Catch provide main():
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_1
|
||||||
|
#include CATCH_EXAMPLE_RPT_1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_2
|
||||||
|
#include CATCH_EXAMPLE_RPT_2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CATCH_EXAMPLE_RPT_3
|
||||||
|
#include CATCH_EXAMPLE_RPT_3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// That's it
|
||||||
|
|
||||||
|
// Compile implementation of Catch for use with files that do contain tests:
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
|
||||||
|
// cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
|
171
examples/207-Rpt-TeamCityReporter.cpp
Normal file
171
examples/207-Rpt-TeamCityReporter.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
// 207-Rpt-TeamCityReporter.cpp
|
||||||
|
|
||||||
|
// Catch has built-in and external reporters:
|
||||||
|
// Built-in:
|
||||||
|
// - compact
|
||||||
|
// - console
|
||||||
|
// - junit
|
||||||
|
// - xml
|
||||||
|
// External:
|
||||||
|
// - automake
|
||||||
|
// - tap
|
||||||
|
// - teamcity (this example)
|
||||||
|
|
||||||
|
// main() and reporter code provided in 200-Rpt-CatchMain.cpp
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning (disable : 4702) // Disable warning: unreachable code
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity passes unconditionally succeeding assertion", "[teamcity]" ) {
|
||||||
|
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unconditionally failing assertion", "[teamcity]" ) {
|
||||||
|
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE( 3 == 7 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check-false", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_FALSE( 3 == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports failing check-that", "[teamcity]" ) {
|
||||||
|
|
||||||
|
using namespace Catch;
|
||||||
|
|
||||||
|
REQUIRE_THAT( "hello", Contains( "world" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unexpected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE( (throw std::runtime_error("surprise!"), true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports undesired exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW( (throw std::runtime_error("surprise!"), true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports missing expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports missing specific expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS_AS( throw std::bad_alloc(), std::runtime_error );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity reports unexpected message in expected exception", "[teamcity]" ) {
|
||||||
|
|
||||||
|
using namespace Catch;
|
||||||
|
|
||||||
|
CHECK_THROWS_WITH( throw std::runtime_error("hello"), "world" );
|
||||||
|
CHECK_THROWS_WITH( throw std::runtime_error("hello"), Contains("world") );
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyException: public std::runtime_error
|
||||||
|
{
|
||||||
|
MyException( char const * text )
|
||||||
|
: std::runtime_error( text ) {}
|
||||||
|
|
||||||
|
~MyException() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// prevent -Wweak-vtables:
|
||||||
|
MyException::~MyException() = default;
|
||||||
|
|
||||||
|
struct MyExceptionMatcher : Catch::MatcherBase< std::runtime_error >
|
||||||
|
{
|
||||||
|
std::string m_text;
|
||||||
|
|
||||||
|
MyExceptionMatcher( char const * text )
|
||||||
|
: m_text( text )
|
||||||
|
{}
|
||||||
|
|
||||||
|
~MyExceptionMatcher() override;
|
||||||
|
|
||||||
|
bool match( std::runtime_error const & arg ) const override
|
||||||
|
{
|
||||||
|
return m_text == arg.what() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string describe() const override
|
||||||
|
{
|
||||||
|
return "it's me";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// prevent -Wweak-vtables:
|
||||||
|
MyExceptionMatcher::~MyExceptionMatcher() = default;
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity failing check-throws-matches", "[teamcity]" ) {
|
||||||
|
|
||||||
|
CHECK_THROWS_MATCHES( throw MyException("hello"), MyException, MyExceptionMatcher("world") );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!throws] - lets Catch know that this test is likely to throw an exception even if successful.
|
||||||
|
// This causes the test to be excluded when running with -e or --nothrow.
|
||||||
|
|
||||||
|
// No special effects for the reporter.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity throwing exception with tag [!throws]", "[teamcity][!throws]" ) {
|
||||||
|
|
||||||
|
REQUIRE_THROWS( throw std::runtime_error("unsurprisingly") );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!mayfail] - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity failing assertion with tag [!mayfail]", "[teamcity][!mayfail] " ) {
|
||||||
|
|
||||||
|
REQUIRE( 3 == 7 ); // doesn't fail test case this time, reports: testIgnored
|
||||||
|
REQUIRE( 3 == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// [!shouldfail] - like [!mayfail] but fails the test if it passes.
|
||||||
|
// This can be useful if you want to be notified of accidental, or third-party, fixes.
|
||||||
|
|
||||||
|
TEST_CASE( "TeamCity succeeding assertion with tag [!shouldfail]", "[teamcity][!shouldfail]" ) {
|
||||||
|
|
||||||
|
SUCCEED( "Marked [!shouldfail]" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile & run:
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
|
||||||
|
// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -o 207-Rpt-TeamCityReporter 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
|
||||||
|
//
|
||||||
|
// - cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
|
||||||
|
// - cl -EHsc -I%CATCH_ROOT% 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
|
||||||
|
|
||||||
|
// Compilation output (--list-reporters):
|
||||||
|
// Available reporters:
|
||||||
|
// compact: Reports test results on a single line, suitable for IDEs
|
||||||
|
// console: Reports test results as plain lines of text
|
||||||
|
// junit: Reports test results in an XML format that looks like Ant's
|
||||||
|
// junitreport target
|
||||||
|
// teamcity: Reports test results as TeamCity service messages
|
||||||
|
// xml: Reports test results as an XML document
|
||||||
|
|
||||||
|
// Expected output (abbreviated and broken into shorter lines):
|
||||||
|
//
|
||||||
|
// prompt> 207-Rpt-TeamCityReporter.exe --reporter teamcity
|
||||||
|
// ##teamcity[testSuiteStarted name='207-Rpt-TeamCityReporter.exe']
|
||||||
|
// ##teamcity[testStarted name='TeamCity passes unconditionally succeeding assertion']
|
||||||
|
// ##teamcity[testFinished name='TeamCity passes unconditionally succeeding assertion' duration='1']
|
||||||
|
// ##teamcity[testStarted name='TeamCity reports unconditionally failing assertion']
|
||||||
|
// ##teamcity[testFailed name='TeamCity reports unconditionally failing assertion' /
|
||||||
|
// message='.../examples/207-Rpt-TeamCityReporter.cpp:23|n/
|
||||||
|
// ...............................................................................|n|n/
|
||||||
|
// .../examples/207-Rpt-TeamCityReporter.cpp:25|nexplicit failure']
|
||||||
|
// ##teamcity[testFinished name='TeamCity reports unconditionally failing assertion' duration='3']
|
||||||
|
// ...
|
@@ -10,7 +10,7 @@
|
|||||||
// Let Catch provide the required interfaces:
|
// Let Catch provide the required interfaces:
|
||||||
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include <catch2/catch.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@@ -187,8 +187,7 @@ void print( std::ostream& os, int const level, std::string const& title, Catch::
|
|||||||
|
|
||||||
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
|
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
|
||||||
os << ws(level ) << title << ":\n"
|
os << ws(level ) << title << ":\n"
|
||||||
<< ws(level+1) << "- name: " << info.name << "\n"
|
<< ws(level+1) << "- name: " << info.name << "\n";
|
||||||
<< ws(level+1) << "- description: '" << info.description << "'\n";
|
|
||||||
print( os, level+1 , "- lineInfo", info.lineInfo );
|
print( os, level+1 , "- lineInfo", info.lineInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
examples/231-Cfg-OutputStreams.cpp
Normal file
49
examples/231-Cfg-OutputStreams.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// 231-Cfg-OutputStreams.cpp
|
||||||
|
// Show how to replace the streams with a simple custom made streambuf.
|
||||||
|
|
||||||
|
// Note that this reimplementation _does not_ follow `std::cerr`
|
||||||
|
// semantic, because it buffers the output. For most uses however,
|
||||||
|
// there is no important difference between having `std::cerr` buffered
|
||||||
|
// or unbuffered.
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_NOSTDOUT
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
class out_buff : public std::stringbuf {
|
||||||
|
std::FILE* m_stream;
|
||||||
|
public:
|
||||||
|
out_buff(std::FILE* stream) :m_stream(stream) {}
|
||||||
|
~out_buff() { pubsync(); }
|
||||||
|
int sync() {
|
||||||
|
int ret = 0;
|
||||||
|
for (unsigned char c : str()) {
|
||||||
|
if (putc(c, m_stream) == EOF) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reset the buffer to avoid printing it multiple times
|
||||||
|
str("");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
std::ostream& cout() {
|
||||||
|
static std::ostream ret(new out_buff(stdout));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::ostream& clog() {
|
||||||
|
static std::ostream ret(new out_buff(stderr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::ostream& cerr() {
|
||||||
|
return clog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("This binary uses putc to write out output", "[compilation-only]") {
|
||||||
|
SUCCEED("Nothing to test.");
|
||||||
|
}
|
@@ -1,22 +1,26 @@
|
|||||||
#
|
#
|
||||||
# Build examples.
|
# Build examples.
|
||||||
#
|
#
|
||||||
# Requires BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
|
# Requires CATCH_BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required( VERSION 3.0 )
|
cmake_minimum_required( VERSION 3.0 )
|
||||||
|
|
||||||
project( CatchExamples CXX )
|
project( CatchExamples CXX )
|
||||||
|
|
||||||
|
message( STATUS "Examples included" )
|
||||||
|
|
||||||
# define folders used:
|
# define folders used:
|
||||||
|
|
||||||
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
|
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
|
||||||
set( HEADER_DIR ${CATCH_DIR}/single_include )
|
set( HEADER_DIR ${CATCH_DIR}/single_include )
|
||||||
|
set( REPORTER_HEADER_DIR ${CATCH_DIR}/include/reporters )
|
||||||
|
|
||||||
# single-file sources:
|
# single-file sources:
|
||||||
|
|
||||||
set( SOURCES_SINGLE_FILE
|
set( SOURCES_SINGLE_FILE
|
||||||
010-TestCase.cpp
|
010-TestCase.cpp
|
||||||
|
231-Cfg-OutputStreams.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# multiple-file modules:
|
# multiple-file modules:
|
||||||
@@ -42,6 +46,26 @@ set( SOURCES_IDIOMATIC_TESTS
|
|||||||
210-Evt-EventListeners.cpp
|
210-Evt-EventListeners.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# main-s for reporter-specific test sources:
|
||||||
|
|
||||||
|
set( SOURCES_REPORTERS_MAIN
|
||||||
|
200-Rpt-CatchMain.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN 200-Rpt-CatchMain.cpp )
|
||||||
|
|
||||||
|
set( NAMES_REPORTERS TeamCity )
|
||||||
|
|
||||||
|
foreach( reporter ${NAMES_REPORTERS} )
|
||||||
|
list( APPEND SOURCES_SPECIFIC_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN}${reporter}.cpp )
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# sources to combine with 200-Rpt-CatchMain{Reporter}.cpp:
|
||||||
|
|
||||||
|
set( SOURCES_REPORTERS_TESTS
|
||||||
|
207-Rpt-TeamCityReporter.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# check if all sources are listed, warn if not:
|
# check if all sources are listed, warn if not:
|
||||||
|
|
||||||
set( SOURCES_ALL
|
set( SOURCES_ALL
|
||||||
@@ -49,6 +73,8 @@ set( SOURCES_ALL
|
|||||||
${SOURCES_SINGLE_FILE}
|
${SOURCES_SINGLE_FILE}
|
||||||
${SOURCES_IDIOMATIC_MAIN}
|
${SOURCES_IDIOMATIC_MAIN}
|
||||||
${SOURCES_IDIOMATIC_TESTS}
|
${SOURCES_IDIOMATIC_TESTS}
|
||||||
|
${SOURCES_REPORTERS_MAIN}
|
||||||
|
${SOURCES_REPORTERS_TESTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach( name ${SOURCES_ALL} )
|
foreach( name ${SOURCES_ALL} )
|
||||||
@@ -61,29 +87,55 @@ CheckFileList( SOURCES_ALL_PATH ${EXAMPLES_DIR} )
|
|||||||
|
|
||||||
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
|
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
|
||||||
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
|
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_TESTS "${SOURCES_REPORTERS_TESTS}" )
|
||||||
|
string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN "${SOURCES_REPORTERS_MAIN}" )
|
||||||
|
|
||||||
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
|
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
|
||||||
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
|
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
|
||||||
set( TARGETS_ALL ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 020-TestCase CatchMain )
|
set( TARGETS_REPORTERS_TESTS ${BASENAMES_REPORTERS_TESTS} )
|
||||||
|
set( TARGETS_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN} )
|
||||||
|
|
||||||
|
set( TARGETS_ALL
|
||||||
|
${TARGETS_SINGLE_FILE}
|
||||||
|
020-TestCase
|
||||||
|
${TARGETS_IDIOMATIC_TESTS} CatchMain
|
||||||
|
${TARGETS_REPORTERS_TESTS} CatchMainTeamCity
|
||||||
|
)
|
||||||
|
|
||||||
# define program targets:
|
# define program targets:
|
||||||
|
|
||||||
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch.hpp )
|
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_library( CatchMainAutomake OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_library( CatchMainTap OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
add_library( CatchMainTeamCity OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch.hpp )
|
#target_compile_definitions( CatchMainAutomake PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_automake.hpp\" )
|
||||||
|
#target_compile_definitions( CatchMainTap PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_tap.hpp\" )
|
||||||
|
target_compile_definitions( CatchMainTeamCity PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" )
|
||||||
|
|
||||||
foreach( name ${TARGETS_SINGLE_FILE} )
|
foreach( name ${TARGETS_SINGLE_FILE} )
|
||||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch.hpp )
|
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
foreach( name ${TARGETS_IDIOMATIC_TESTS} )
|
foreach( name ${TARGETS_IDIOMATIC_TESTS} )
|
||||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch.hpp )
|
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
|
#add_executable( 207-Rpt-AutomakeReporter ${EXAMPLES_DIR}/207-Rpt-AutomakeReporter.cpp $<TARGET_OBJECTS:CatchMainAutomake> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#add_executable( 207-Rpt-TapReporter ${EXAMPLES_DIR}/207-Rpt-TapReporter.cpp $<TARGET_OBJECTS:CatchMainTap> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
add_executable( 207-Rpt-TeamCityReporter ${EXAMPLES_DIR}/207-Rpt-TeamCityReporter.cpp $<TARGET_OBJECTS:CatchMainTeamCity> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
|
||||||
|
#foreach( name ${TARGETS_REPORTERS_TESTS} )
|
||||||
|
# add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
|
||||||
|
#endforeach()
|
||||||
|
|
||||||
foreach( name ${TARGETS_ALL} )
|
foreach( name ${TARGETS_ALL} )
|
||||||
target_include_directories( ${name} PRIVATE ${HEADER_DIR} )
|
target_include_directories( ${name} PRIVATE ${HEADER_DIR} ${CATCH_DIR} )
|
||||||
|
|
||||||
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
|
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
|
||||||
|
set_property(TARGET ${name} PROPERTY CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
# Add desired warnings
|
# Add desired warnings
|
||||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||||
@@ -98,3 +150,4 @@ foreach( name ${TARGETS_ALL} )
|
|||||||
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
|
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
@@ -9,6 +9,9 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||||
|
|
||||||
|
#define CATCH_VERSION_MAJOR 2
|
||||||
|
#define CATCH_VERSION_MINOR 4
|
||||||
|
#define CATCH_VERSION_PATCH 2
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
# pragma clang system_header
|
# pragma clang system_header
|
||||||
@@ -30,7 +33,9 @@
|
|||||||
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||||
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
||||||
# endif
|
# endif
|
||||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
|
||||||
|
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||||
@@ -57,6 +62,7 @@
|
|||||||
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
#ifndef CATCH_CONFIG_DISABLE_MATCHERS
|
||||||
#include "internal/catch_capture_matchers.h"
|
#include "internal/catch_capture_matchers.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "internal/catch_generators.hpp"
|
||||||
|
|
||||||
// These files are included here so the single_include script doesn't put them
|
// These files are included here so the single_include script doesn't put them
|
||||||
// in the conditionally compiled sections
|
// in the conditionally compiled sections
|
||||||
@@ -125,27 +131,38 @@
|
|||||||
|
|
||||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
|
||||||
|
|
||||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
|
|
||||||
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
|
||||||
|
#else
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// "BDD-style" convenience wrappers
|
// "BDD-style" convenience wrappers
|
||||||
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc )
|
#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc )
|
#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc )
|
#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc )
|
#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
||||||
#else
|
#else
|
||||||
@@ -184,18 +201,27 @@
|
|||||||
|
|
||||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||||
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
|
#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
|
||||||
|
|
||||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
|
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||||
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||||
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
|
||||||
|
#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
|
||||||
|
#else
|
||||||
|
#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
|
||||||
@@ -204,15 +230,17 @@
|
|||||||
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
|
||||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
|
||||||
|
|
||||||
#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc )
|
#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
|
||||||
#define WHEN( desc ) SECTION( std::string(" When: ") + desc )
|
#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
|
||||||
#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc )
|
#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
|
||||||
#define THEN( desc ) SECTION( std::string(" Then: ") + desc )
|
#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
|
||||||
#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc )
|
#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
|
||||||
|
#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
|
||||||
|
|
||||||
using Catch::Detail::Approx;
|
using Catch::Detail::Approx;
|
||||||
|
|
||||||
#else
|
#else // CATCH_CONFIG_DISABLE
|
||||||
|
|
||||||
//////
|
//////
|
||||||
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
||||||
#ifdef CATCH_CONFIG_PREFIX_ALL
|
#ifdef CATCH_CONFIG_PREFIX_ALL
|
||||||
@@ -257,6 +285,7 @@ using Catch::Detail::Approx;
|
|||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define CATCH_SECTION( ... )
|
#define CATCH_SECTION( ... )
|
||||||
|
#define CATCH_DYNAMIC_SECTION( ... )
|
||||||
#define CATCH_FAIL( ... ) (void)(0)
|
#define CATCH_FAIL( ... ) (void)(0)
|
||||||
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
#define CATCH_FAIL_CHECK( ... ) (void)(0)
|
||||||
#define CATCH_SUCCEED( ... ) (void)(0)
|
#define CATCH_SUCCEED( ... ) (void)(0)
|
||||||
@@ -267,11 +296,15 @@ using Catch::Detail::Approx;
|
|||||||
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
||||||
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
||||||
#define CATCH_GIVEN( desc )
|
#define CATCH_GIVEN( desc )
|
||||||
|
#define CATCH_AND_GIVEN( desc )
|
||||||
#define CATCH_WHEN( desc )
|
#define CATCH_WHEN( desc )
|
||||||
#define CATCH_AND_WHEN( desc )
|
#define CATCH_AND_WHEN( desc )
|
||||||
#define CATCH_THEN( desc )
|
#define CATCH_THEN( desc )
|
||||||
#define CATCH_AND_THEN( desc )
|
#define CATCH_AND_THEN( desc )
|
||||||
|
|
||||||
|
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
|
||||||
|
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -316,11 +349,16 @@ using Catch::Detail::Approx;
|
|||||||
#define METHOD_AS_TEST_CASE( method, ... )
|
#define METHOD_AS_TEST_CASE( method, ... )
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define SECTION( ... )
|
#define SECTION( ... )
|
||||||
|
#define DYNAMIC_SECTION( ... )
|
||||||
#define FAIL( ... ) (void)(0)
|
#define FAIL( ... ) (void)(0)
|
||||||
#define FAIL_CHECK( ... ) (void)(0)
|
#define FAIL_CHECK( ... ) (void)(0)
|
||||||
#define SUCCEED( ... ) (void)(0)
|
#define SUCCEED( ... ) (void)(0)
|
||||||
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
|
||||||
|
|
||||||
|
|
||||||
|
#define STATIC_REQUIRE( ... ) (void)(0)
|
||||||
|
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||||
@@ -330,6 +368,7 @@ using Catch::Detail::Approx;
|
|||||||
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
|
||||||
|
|
||||||
#define GIVEN( desc )
|
#define GIVEN( desc )
|
||||||
|
#define AND_GIVEN( desc )
|
||||||
#define WHEN( desc )
|
#define WHEN( desc )
|
||||||
#define AND_WHEN( desc )
|
#define AND_WHEN( desc )
|
||||||
#define THEN( desc )
|
#define THEN( desc )
|
||||||
|
681
include/external/clara.hpp
vendored
681
include/external/clara.hpp
vendored
@@ -1,5 +1,11 @@
|
|||||||
// v1.0-develop.2
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
// See https://github.com/philsquared/Clara
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
// See https://github.com/philsquared/Clara for more details
|
||||||
|
|
||||||
|
// Clara v1.1.5
|
||||||
|
|
||||||
#ifndef CATCH_CLARA_HPP_INCLUDED
|
#ifndef CATCH_CLARA_HPP_INCLUDED
|
||||||
#define CATCH_CLARA_HPP_INCLUDED
|
#define CATCH_CLARA_HPP_INCLUDED
|
||||||
@@ -12,14 +18,24 @@
|
|||||||
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
||||||
#endif
|
#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 -----------
|
// ----------- #included from clara_textflow.hpp -----------
|
||||||
|
|
||||||
// TextFlowCpp
|
// TextFlowCpp
|
||||||
//
|
//
|
||||||
// A single-header library for wrapping and laying out basic text, by Phil Nash
|
// A single-header library for wrapping and laying out basic text, by Phil Nash
|
||||||
//
|
//
|
||||||
// This work is licensed under the BSD 2-Clause license.
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
// This project is hosted at https://github.com/philsquared/textflowcpp
|
// This project is hosted at https://github.com/philsquared/textflowcpp
|
||||||
|
|
||||||
@@ -36,317 +52,326 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace Catch { namespace clara { namespace TextFlow {
|
namespace Catch {
|
||||||
|
namespace clara {
|
||||||
|
namespace TextFlow {
|
||||||
|
|
||||||
inline auto isWhitespace( char c ) -> bool {
|
inline auto isWhitespace(char c) -> bool {
|
||||||
static std::string chars = " \t\n\r";
|
static std::string chars = " \t\n\r";
|
||||||
return chars.find( c ) != std::string::npos;
|
return chars.find(c) != std::string::npos;
|
||||||
}
|
}
|
||||||
inline auto isBreakableBefore( char c ) -> bool {
|
inline auto isBreakableBefore(char c) -> bool {
|
||||||
static std::string chars = "[({<|";
|
static std::string chars = "[({<|";
|
||||||
return chars.find( c ) != std::string::npos;
|
return chars.find(c) != std::string::npos;
|
||||||
}
|
}
|
||||||
inline auto isBreakableAfter( char c ) -> bool {
|
inline auto isBreakableAfter(char c) -> bool {
|
||||||
static std::string chars = "])}>.,:;*+-=&/\\";
|
static std::string chars = "])}>.,:;*+-=&/\\";
|
||||||
return chars.find( c ) != std::string::npos;
|
return chars.find(c) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Columns;
|
class Columns;
|
||||||
|
|
||||||
class Column {
|
class Column {
|
||||||
std::vector<std::string> m_strings;
|
std::vector<std::string> m_strings;
|
||||||
size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
|
size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
|
||||||
size_t m_indent = 0;
|
size_t m_indent = 0;
|
||||||
size_t m_initialIndent = std::string::npos;
|
size_t m_initialIndent = std::string::npos;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class iterator {
|
class iterator {
|
||||||
friend Column;
|
friend Column;
|
||||||
|
|
||||||
Column const& m_column;
|
Column const& m_column;
|
||||||
size_t m_stringIndex = 0;
|
size_t m_stringIndex = 0;
|
||||||
size_t m_pos = 0;
|
size_t m_pos = 0;
|
||||||
|
|
||||||
size_t m_len = 0;
|
size_t m_len = 0;
|
||||||
size_t m_end = 0;
|
size_t m_end = 0;
|
||||||
bool m_suffix = false;
|
bool m_suffix = false;
|
||||||
|
|
||||||
iterator( Column const& column, size_t stringIndex )
|
iterator(Column const& column, size_t stringIndex)
|
||||||
: m_column( column ),
|
: m_column(column),
|
||||||
m_stringIndex( stringIndex )
|
m_stringIndex(stringIndex) {}
|
||||||
{}
|
|
||||||
|
|
||||||
auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
|
auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
|
||||||
|
|
||||||
auto isBoundary( size_t at ) const -> bool {
|
auto isBoundary(size_t at) const -> bool {
|
||||||
assert( at > 0 );
|
assert(at > 0);
|
||||||
assert( at <= line().size() );
|
assert(at <= line().size());
|
||||||
|
|
||||||
return at == line().size() ||
|
return at == line().size() ||
|
||||||
( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
|
(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
|
||||||
isBreakableBefore( line()[at] ) ||
|
isBreakableBefore(line()[at]) ||
|
||||||
isBreakableAfter( line()[at-1] );
|
isBreakableAfter(line()[at - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calcLength() {
|
void calcLength() {
|
||||||
assert( m_stringIndex < m_column.m_strings.size() );
|
assert(m_stringIndex < m_column.m_strings.size());
|
||||||
|
|
||||||
m_suffix = false;
|
m_suffix = false;
|
||||||
auto width = m_column.m_width-indent();
|
auto width = m_column.m_width - indent();
|
||||||
m_end = m_pos;
|
m_end = m_pos;
|
||||||
while( m_end < line().size() && line()[m_end] != '\n' )
|
while (m_end < line().size() && line()[m_end] != '\n')
|
||||||
++m_end;
|
++m_end;
|
||||||
|
|
||||||
if( m_end < m_pos + width ) {
|
if (m_end < m_pos + width) {
|
||||||
m_len = m_end - m_pos;
|
m_len = m_end - m_pos;
|
||||||
}
|
} else {
|
||||||
else {
|
size_t len = width;
|
||||||
size_t len = width;
|
while (len > 0 && !isBoundary(m_pos + len))
|
||||||
while (len > 0 && !isBoundary(m_pos + len))
|
--len;
|
||||||
--len;
|
while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
|
||||||
while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
|
--len;
|
||||||
--len;
|
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
m_len = len;
|
m_len = len;
|
||||||
} else {
|
} else {
|
||||||
m_suffix = true;
|
m_suffix = true;
|
||||||
m_len = width - 1;
|
m_len = width - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto indent() const -> size_t {
|
auto indent() const -> size_t {
|
||||||
auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
|
auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
|
||||||
return initial == std::string::npos ? m_column.m_indent : initial;
|
return initial == std::string::npos ? m_column.m_indent : initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addIndentAndSuffix(std::string const &plain) const -> std::string {
|
auto addIndentAndSuffix(std::string const &plain) const -> std::string {
|
||||||
return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
|
return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit iterator( Column const& column ) : m_column( column ) {
|
using difference_type = std::ptrdiff_t;
|
||||||
assert( m_column.m_width > m_column.m_indent );
|
using value_type = std::string;
|
||||||
assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
|
using pointer = value_type * ;
|
||||||
calcLength();
|
using reference = value_type & ;
|
||||||
if( m_len == 0 )
|
using iterator_category = std::forward_iterator_tag;
|
||||||
m_stringIndex++; // Empty string
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator *() const -> std::string {
|
explicit iterator(Column const& column) : m_column(column) {
|
||||||
assert( m_stringIndex < m_column.m_strings.size() );
|
assert(m_column.m_width > m_column.m_indent);
|
||||||
assert( m_pos <= m_end );
|
assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
|
||||||
if( m_pos + m_column.m_width < m_end )
|
calcLength();
|
||||||
return addIndentAndSuffix(line().substr(m_pos, m_len));
|
if (m_len == 0)
|
||||||
else
|
m_stringIndex++; // Empty string
|
||||||
return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto operator ++() -> iterator& {
|
auto operator *() const -> std::string {
|
||||||
m_pos += m_len;
|
assert(m_stringIndex < m_column.m_strings.size());
|
||||||
if( m_pos < line().size() && line()[m_pos] == '\n' )
|
assert(m_pos <= m_end);
|
||||||
m_pos += 1;
|
return addIndentAndSuffix(line().substr(m_pos, m_len));
|
||||||
else
|
}
|
||||||
while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
|
|
||||||
++m_pos;
|
|
||||||
|
|
||||||
if( m_pos == line().size() ) {
|
auto operator ++() -> iterator& {
|
||||||
m_pos = 0;
|
m_pos += m_len;
|
||||||
++m_stringIndex;
|
if (m_pos < line().size() && line()[m_pos] == '\n')
|
||||||
}
|
m_pos += 1;
|
||||||
if( m_stringIndex < m_column.m_strings.size() )
|
else
|
||||||
calcLength();
|
while (m_pos < line().size() && isWhitespace(line()[m_pos]))
|
||||||
return *this;
|
++m_pos;
|
||||||
}
|
|
||||||
auto operator ++(int) -> iterator {
|
|
||||||
iterator prev( *this );
|
|
||||||
operator++();
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator ==( iterator const& other ) const -> bool {
|
if (m_pos == line().size()) {
|
||||||
return
|
m_pos = 0;
|
||||||
m_pos == other.m_pos &&
|
++m_stringIndex;
|
||||||
m_stringIndex == other.m_stringIndex &&
|
}
|
||||||
&m_column == &other.m_column;
|
if (m_stringIndex < m_column.m_strings.size())
|
||||||
}
|
calcLength();
|
||||||
auto operator !=( iterator const& other ) const -> bool {
|
return *this;
|
||||||
return !operator==( other );
|
}
|
||||||
}
|
auto operator ++(int) -> iterator {
|
||||||
};
|
iterator prev(*this);
|
||||||
using const_iterator = iterator;
|
operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
explicit Column( std::string const& text ) { m_strings.push_back( text ); }
|
auto operator ==(iterator const& other) const -> bool {
|
||||||
|
return
|
||||||
|
m_pos == other.m_pos &&
|
||||||
|
m_stringIndex == other.m_stringIndex &&
|
||||||
|
&m_column == &other.m_column;
|
||||||
|
}
|
||||||
|
auto operator !=(iterator const& other) const -> bool {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using const_iterator = iterator;
|
||||||
|
|
||||||
auto width( size_t newWidth ) -> Column& {
|
explicit Column(std::string const& text) { m_strings.push_back(text); }
|
||||||
assert( newWidth > 0 );
|
|
||||||
m_width = newWidth;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
auto indent( size_t newIndent ) -> Column& {
|
|
||||||
m_indent = newIndent;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
auto initialIndent( size_t newIndent ) -> Column& {
|
|
||||||
m_initialIndent = newIndent;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto width() const -> size_t { return m_width; }
|
auto width(size_t newWidth) -> Column& {
|
||||||
auto begin() const -> iterator { return iterator( *this ); }
|
assert(newWidth > 0);
|
||||||
auto end() const -> iterator { return { *this, m_strings.size() }; }
|
m_width = newWidth;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto indent(size_t newIndent) -> Column& {
|
||||||
|
m_indent = newIndent;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto initialIndent(size_t newIndent) -> Column& {
|
||||||
|
m_initialIndent = newIndent;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
|
auto width() const -> size_t { return m_width; }
|
||||||
bool first = true;
|
auto begin() const -> iterator { return iterator(*this); }
|
||||||
for( auto line : col ) {
|
auto end() const -> iterator { return { *this, m_strings.size() }; }
|
||||||
if( first )
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
os << "\n";
|
|
||||||
os << line;
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator + ( Column const& other ) -> Columns;
|
inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
|
||||||
|
bool first = true;
|
||||||
|
for (auto line : col) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
os << "\n";
|
||||||
|
os << line;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
auto toString() const -> std::string {
|
auto operator + (Column const& other)->Columns;
|
||||||
std::ostringstream oss;
|
|
||||||
oss << *this;
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Spacer : public Column {
|
auto toString() const -> std::string {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << *this;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
class Spacer : public Column {
|
||||||
explicit Spacer( size_t spaceWidth ) : Column( "" ) {
|
|
||||||
width( spaceWidth );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Columns {
|
public:
|
||||||
std::vector<Column> m_columns;
|
explicit Spacer(size_t spaceWidth) : Column("") {
|
||||||
|
width(spaceWidth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
class Columns {
|
||||||
|
std::vector<Column> m_columns;
|
||||||
|
|
||||||
class iterator {
|
public:
|
||||||
friend Columns;
|
|
||||||
struct EndTag {};
|
|
||||||
|
|
||||||
std::vector<Column> const& m_columns;
|
class iterator {
|
||||||
std::vector<Column::iterator> m_iterators;
|
friend Columns;
|
||||||
size_t m_activeIterators;
|
struct EndTag {};
|
||||||
|
|
||||||
iterator( Columns const& columns, EndTag )
|
std::vector<Column> const& m_columns;
|
||||||
: m_columns( columns.m_columns ),
|
std::vector<Column::iterator> m_iterators;
|
||||||
m_activeIterators( 0 )
|
size_t m_activeIterators;
|
||||||
{
|
|
||||||
m_iterators.reserve( m_columns.size() );
|
|
||||||
|
|
||||||
for( auto const& col : m_columns )
|
iterator(Columns const& columns, EndTag)
|
||||||
m_iterators.push_back( col.end() );
|
: m_columns(columns.m_columns),
|
||||||
}
|
m_activeIterators(0) {
|
||||||
|
m_iterators.reserve(m_columns.size());
|
||||||
|
|
||||||
public:
|
for (auto const& col : m_columns)
|
||||||
explicit iterator( Columns const& columns )
|
m_iterators.push_back(col.end());
|
||||||
: m_columns( columns.m_columns ),
|
}
|
||||||
m_activeIterators( m_columns.size() )
|
|
||||||
{
|
|
||||||
m_iterators.reserve( m_columns.size() );
|
|
||||||
|
|
||||||
for( auto const& col : m_columns )
|
public:
|
||||||
m_iterators.push_back( col.begin() );
|
using difference_type = std::ptrdiff_t;
|
||||||
}
|
using value_type = std::string;
|
||||||
|
using pointer = value_type * ;
|
||||||
|
using reference = value_type & ;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
|
||||||
auto operator ==( iterator const& other ) const -> bool {
|
explicit iterator(Columns const& columns)
|
||||||
return m_iterators == other.m_iterators;
|
: m_columns(columns.m_columns),
|
||||||
}
|
m_activeIterators(m_columns.size()) {
|
||||||
auto operator !=( iterator const& other ) const -> bool {
|
m_iterators.reserve(m_columns.size());
|
||||||
return m_iterators != other.m_iterators;
|
|
||||||
}
|
|
||||||
auto operator *() const -> std::string {
|
|
||||||
std::string row, padding;
|
|
||||||
|
|
||||||
for( size_t i = 0; i < m_columns.size(); ++i ) {
|
for (auto const& col : m_columns)
|
||||||
auto width = m_columns[i].width();
|
m_iterators.push_back(col.begin());
|
||||||
if( m_iterators[i] != m_columns[i].end() ) {
|
}
|
||||||
std::string col = *m_iterators[i];
|
|
||||||
row += padding + col;
|
|
||||||
if( col.size() < width )
|
|
||||||
padding = std::string( width - col.size(), ' ' );
|
|
||||||
else
|
|
||||||
padding = "";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
padding += std::string( width, ' ' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
auto operator ++() -> iterator& {
|
|
||||||
for( size_t i = 0; i < m_columns.size(); ++i ) {
|
|
||||||
if (m_iterators[i] != m_columns[i].end())
|
|
||||||
++m_iterators[i];
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
auto operator ++(int) -> iterator {
|
|
||||||
iterator prev( *this );
|
|
||||||
operator++();
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using const_iterator = iterator;
|
|
||||||
|
|
||||||
auto begin() const -> iterator { return iterator( *this ); }
|
auto operator ==(iterator const& other) const -> bool {
|
||||||
auto end() const -> iterator { return { *this, iterator::EndTag() }; }
|
return m_iterators == other.m_iterators;
|
||||||
|
}
|
||||||
|
auto operator !=(iterator const& other) const -> bool {
|
||||||
|
return m_iterators != other.m_iterators;
|
||||||
|
}
|
||||||
|
auto operator *() const -> std::string {
|
||||||
|
std::string row, padding;
|
||||||
|
|
||||||
auto operator += ( Column const& col ) -> Columns& {
|
for (size_t i = 0; i < m_columns.size(); ++i) {
|
||||||
m_columns.push_back( col );
|
auto width = m_columns[i].width();
|
||||||
return *this;
|
if (m_iterators[i] != m_columns[i].end()) {
|
||||||
}
|
std::string col = *m_iterators[i];
|
||||||
auto operator + ( Column const& col ) -> Columns {
|
row += padding + col;
|
||||||
Columns combined = *this;
|
if (col.size() < width)
|
||||||
combined += col;
|
padding = std::string(width - col.size(), ' ');
|
||||||
return combined;
|
else
|
||||||
}
|
padding = "";
|
||||||
|
} else {
|
||||||
|
padding += std::string(width, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
auto operator ++() -> iterator& {
|
||||||
|
for (size_t i = 0; i < m_columns.size(); ++i) {
|
||||||
|
if (m_iterators[i] != m_columns[i].end())
|
||||||
|
++m_iterators[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator ++(int) -> iterator {
|
||||||
|
iterator prev(*this);
|
||||||
|
operator++();
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using const_iterator = iterator;
|
||||||
|
|
||||||
inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
|
auto begin() const -> iterator { return iterator(*this); }
|
||||||
|
auto end() const -> iterator { return { *this, iterator::EndTag() }; }
|
||||||
|
|
||||||
bool first = true;
|
auto operator += (Column const& col) -> Columns& {
|
||||||
for( auto line : cols ) {
|
m_columns.push_back(col);
|
||||||
if( first )
|
return *this;
|
||||||
first = false;
|
}
|
||||||
else
|
auto operator + (Column const& col) -> Columns {
|
||||||
os << "\n";
|
Columns combined = *this;
|
||||||
os << line;
|
combined += col;
|
||||||
}
|
return combined;
|
||||||
return os;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto toString() const -> std::string {
|
inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
|
||||||
std::ostringstream oss;
|
|
||||||
oss << *this;
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto Column::operator + ( Column const& other ) -> Columns {
|
bool first = true;
|
||||||
Columns cols;
|
for (auto line : cols) {
|
||||||
cols += *this;
|
if (first)
|
||||||
cols += other;
|
first = false;
|
||||||
return cols;
|
else
|
||||||
}
|
os << "\n";
|
||||||
}}} // namespace Catch::clara::TextFlow
|
os << line;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto toString() const -> std::string {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << *this;
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto Column::operator + (Column const& other) -> Columns {
|
||||||
|
Columns cols;
|
||||||
|
cols += *this;
|
||||||
|
cols += other;
|
||||||
|
return cols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
||||||
|
|
||||||
// ----------- end of #include from clara_textflow.hpp -----------
|
// ----------- end of #include from clara_textflow.hpp -----------
|
||||||
// ........... back in clara.hpp
|
// ........... back in clara.hpp
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -370,7 +395,7 @@ namespace detail {
|
|||||||
template<typename ClassT, typename ReturnT, typename ArgT>
|
template<typename ClassT, typename ReturnT, typename ArgT>
|
||||||
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
|
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
|
||||||
static const bool isValid = true;
|
static const bool isValid = true;
|
||||||
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
|
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
|
||||||
using ReturnType = ReturnT;
|
using ReturnType = ReturnT;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -383,11 +408,9 @@ namespace detail {
|
|||||||
std::vector<std::string> m_args;
|
std::vector<std::string> m_args;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Args( int argc, char *argv[] ) {
|
Args( int argc, char const* const* argv )
|
||||||
m_exeName = argv[0];
|
: m_exeName(argv[0]),
|
||||||
for( int i = 1; i < argc; ++i )
|
m_args(argv + 1, argv + argc) {}
|
||||||
m_args.push_back( argv[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
Args( std::initializer_list<std::string> args )
|
Args( std::initializer_list<std::string> args )
|
||||||
: m_exeName( *args.begin() ),
|
: m_exeName( *args.begin() ),
|
||||||
@@ -535,7 +558,7 @@ namespace detail {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ResultValueBase() {
|
~ResultValueBase() override {
|
||||||
if( m_type == Ok )
|
if( m_type == Ok )
|
||||||
m_value.~T();
|
m_value.~T();
|
||||||
}
|
}
|
||||||
@@ -573,16 +596,14 @@ namespace detail {
|
|||||||
auto errorMessage() const -> std::string { return m_errorMessage; }
|
auto errorMessage() const -> std::string { return m_errorMessage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void enforceOk() const {
|
void enforceOk() const override {
|
||||||
// !TBD: If no exceptions, std::terminate here or something
|
|
||||||
switch( m_type ) {
|
// Errors shouldn't reach this point, but if they do
|
||||||
case ResultBase::LogicError:
|
// the actual error message will be in m_errorMessage
|
||||||
throw std::logic_error( m_errorMessage );
|
assert( m_type != ResultBase::LogicError );
|
||||||
case ResultBase::RuntimeError:
|
assert( m_type != ResultBase::RuntimeError );
|
||||||
throw std::runtime_error( m_errorMessage );
|
if( m_type != ResultBase::Ok )
|
||||||
case ResultBase::Ok:
|
std::abort();
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string m_errorMessage; // Only populated if resultType is an error
|
std::string m_errorMessage; // Only populated if resultType is an error
|
||||||
@@ -652,47 +673,43 @@ namespace detail {
|
|||||||
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
||||||
return ParserResult::ok( ParseResultType::Matched );
|
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 BoundRefBase {
|
struct NonCopyable {
|
||||||
BoundRefBase() = default;
|
NonCopyable() = default;
|
||||||
BoundRefBase( BoundRefBase const & ) = delete;
|
NonCopyable( NonCopyable const & ) = delete;
|
||||||
BoundRefBase( BoundRefBase && ) = delete;
|
NonCopyable( NonCopyable && ) = delete;
|
||||||
BoundRefBase &operator=( BoundRefBase const & ) = delete;
|
NonCopyable &operator=( NonCopyable const & ) = delete;
|
||||||
BoundRefBase &operator=( BoundRefBase && ) = delete;
|
NonCopyable &operator=( NonCopyable && ) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~BoundRefBase() = default;
|
struct BoundRef : NonCopyable {
|
||||||
|
virtual ~BoundRef() = default;
|
||||||
virtual auto isFlag() const -> bool = 0;
|
|
||||||
virtual auto isContainer() const -> bool { return false; }
|
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;
|
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
|
||||||
|
};
|
||||||
|
struct BoundFlagRefBase : BoundRef {
|
||||||
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
||||||
};
|
virtual auto isFlag() const -> bool { return true; }
|
||||||
|
|
||||||
struct BoundValueRefBase : BoundRefBase {
|
|
||||||
auto isFlag() const -> bool override { return false; }
|
|
||||||
|
|
||||||
auto setFlag( bool ) -> ParserResult override {
|
|
||||||
return ParserResult::logicError( "Flags can only be set on boolean fields" );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BoundFlagRefBase : BoundRefBase {
|
|
||||||
auto isFlag() const -> bool override { return true; }
|
|
||||||
|
|
||||||
auto setValue( std::string const &arg ) -> ParserResult override {
|
|
||||||
bool flag;
|
|
||||||
auto result = convertInto( arg, flag );
|
|
||||||
if( result )
|
|
||||||
setFlag( flag );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct BoundRef : BoundValueRefBase {
|
struct BoundValueRef : BoundValueRefBase {
|
||||||
T &m_ref;
|
T &m_ref;
|
||||||
|
|
||||||
explicit BoundRef( T &ref ) : m_ref( ref ) {}
|
explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
|
||||||
|
|
||||||
auto setValue( std::string const &arg ) -> ParserResult override {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
return convertInto( arg, m_ref );
|
return convertInto( arg, m_ref );
|
||||||
@@ -700,10 +717,10 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
|
||||||
std::vector<T> &m_ref;
|
std::vector<T> &m_ref;
|
||||||
|
|
||||||
explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {}
|
explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
|
||||||
|
|
||||||
auto isContainer() const -> bool override { return true; }
|
auto isContainer() const -> bool override { return true; }
|
||||||
|
|
||||||
@@ -748,12 +765,12 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename ArgType, typename L>
|
template<typename ArgType, typename L>
|
||||||
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
|
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
|
||||||
ArgType temp;
|
ArgType temp{};
|
||||||
auto result = convertInto( arg, temp );
|
auto result = convertInto( arg, temp );
|
||||||
return !result
|
return !result
|
||||||
? result
|
? result
|
||||||
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
|
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename L>
|
template<typename L>
|
||||||
@@ -803,6 +820,9 @@ namespace detail {
|
|||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto operator|( T const &other ) const -> Parser;
|
auto operator|( T const &other ) const -> Parser;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto operator+( T const &other ) const -> Parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Common code and state for Args and Opts
|
// Common code and state for Args and Opts
|
||||||
@@ -810,16 +830,16 @@ namespace detail {
|
|||||||
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
|
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
|
||||||
protected:
|
protected:
|
||||||
Optionality m_optionality = Optionality::Optional;
|
Optionality m_optionality = Optionality::Optional;
|
||||||
std::shared_ptr<BoundRefBase> m_ref;
|
std::shared_ptr<BoundRef> m_ref;
|
||||||
std::string m_hint;
|
std::string m_hint;
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
|
|
||||||
explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {}
|
explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ParserRefImpl( T &ref, std::string const &hint )
|
ParserRefImpl( T &ref, std::string const &hint )
|
||||||
: m_ref( std::make_shared<BoundRef<T>>( ref ) ),
|
: m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
|
||||||
m_hint( hint )
|
m_hint( hint )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -860,10 +880,10 @@ namespace detail {
|
|||||||
|
|
||||||
class ExeName : public ComposableParserImpl<ExeName> {
|
class ExeName : public ComposableParserImpl<ExeName> {
|
||||||
std::shared_ptr<std::string> m_name;
|
std::shared_ptr<std::string> m_name;
|
||||||
std::shared_ptr<BoundRefBase> m_ref;
|
std::shared_ptr<BoundValueRefBase> m_ref;
|
||||||
|
|
||||||
template<typename LambdaT>
|
template<typename LambdaT>
|
||||||
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
|
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
|
||||||
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
|
return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,7 +891,7 @@ namespace detail {
|
|||||||
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
|
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
|
||||||
|
|
||||||
explicit ExeName( std::string &ref ) : ExeName() {
|
explicit ExeName( std::string &ref ) : ExeName() {
|
||||||
m_ref = std::make_shared<BoundRef<std::string>>( ref );
|
m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename LambdaT>
|
template<typename LambdaT>
|
||||||
@@ -914,7 +934,10 @@ namespace detail {
|
|||||||
if( token.type != TokenType::Argument )
|
if( token.type != TokenType::Argument )
|
||||||
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
|
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
|
||||||
|
|
||||||
auto result = m_ref->setValue( remainingTokens->token );
|
assert( !m_ref->isFlag() );
|
||||||
|
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
|
||||||
|
|
||||||
|
auto result = valueRef->setValue( remainingTokens->token );
|
||||||
if( !result )
|
if( !result )
|
||||||
return InternalParseResult( result );
|
return InternalParseResult( result );
|
||||||
else
|
else
|
||||||
@@ -988,19 +1011,21 @@ namespace detail {
|
|||||||
auto const &token = *remainingTokens;
|
auto const &token = *remainingTokens;
|
||||||
if( isMatch(token.token ) ) {
|
if( isMatch(token.token ) ) {
|
||||||
if( m_ref->isFlag() ) {
|
if( m_ref->isFlag() ) {
|
||||||
auto result = m_ref->setFlag( true );
|
auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
|
||||||
|
auto result = flagRef->setFlag( true );
|
||||||
if( !result )
|
if( !result )
|
||||||
return InternalParseResult( result );
|
return InternalParseResult( result );
|
||||||
if( result.value() == ParseResultType::ShortCircuitAll )
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
||||||
} else {
|
} else {
|
||||||
|
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
|
||||||
++remainingTokens;
|
++remainingTokens;
|
||||||
if( !remainingTokens )
|
if( !remainingTokens )
|
||||||
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto const &argToken = *remainingTokens;
|
auto const &argToken = *remainingTokens;
|
||||||
if( argToken.type != TokenType::Argument )
|
if( argToken.type != TokenType::Argument )
|
||||||
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto result = m_ref->setValue( argToken.token );
|
auto result = valueRef->setValue( argToken.token );
|
||||||
if( !result )
|
if( !result )
|
||||||
return InternalParseResult( result );
|
return InternalParseResult( result );
|
||||||
if( result.value() == ParseResultType::ShortCircuitAll )
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
@@ -1077,6 +1102,12 @@ namespace detail {
|
|||||||
return Parser( *this ) |= other;
|
return Parser( *this ) |= other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward deprecated interface with '+' instead of '|'
|
||||||
|
template<typename T>
|
||||||
|
auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
|
||||||
|
template<typename T>
|
||||||
|
auto operator+( T const &other ) const -> Parser { return operator|( other ); }
|
||||||
|
|
||||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||||
std::vector<HelpColumns> cols;
|
std::vector<HelpColumns> cols;
|
||||||
for (auto const &o : m_options) {
|
for (auto const &o : m_options) {
|
||||||
@@ -1116,6 +1147,8 @@ namespace detail {
|
|||||||
for( auto const &cols : rows )
|
for( auto const &cols : rows )
|
||||||
optWidth = (std::max)(optWidth, cols.left.size() + 2);
|
optWidth = (std::max)(optWidth, cols.left.size() + 2);
|
||||||
|
|
||||||
|
optWidth = (std::min)(optWidth, consoleWidth/2);
|
||||||
|
|
||||||
for( auto const &cols : rows ) {
|
for( auto const &cols : rows ) {
|
||||||
auto row =
|
auto row =
|
||||||
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
|
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_approx.h"
|
#include "catch_approx.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@@ -35,6 +36,13 @@ namespace Detail {
|
|||||||
return Approx( 0 );
|
return Approx( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Approx Approx::operator-() const {
|
||||||
|
auto temp(*this);
|
||||||
|
temp.m_value = -temp.m_value;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Approx::toString() const {
|
std::string Approx::toString() const {
|
||||||
ReusableStringStream rss;
|
ReusableStringStream rss;
|
||||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||||
@@ -47,8 +55,31 @@ namespace Detail {
|
|||||||
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Approx::setMargin(double margin) {
|
||||||
|
CATCH_ENFORCE(margin >= 0,
|
||||||
|
"Invalid Approx::margin: " << margin << '.'
|
||||||
|
<< " Approx::Margin has to be non-negative.");
|
||||||
|
m_margin = margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Approx::setEpsilon(double epsilon) {
|
||||||
|
CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
|
||||||
|
"Invalid Approx::epsilon: " << epsilon << '.'
|
||||||
|
<< " Approx::epsilon has to be in [0, 1]");
|
||||||
|
m_epsilon = epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace Detail
|
} // end namespace Detail
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Detail::Approx operator "" _a(long double val) {
|
||||||
|
return Detail::Approx(val);
|
||||||
|
}
|
||||||
|
Detail::Approx operator "" _a(unsigned long long val) {
|
||||||
|
return Detail::Approx(val);
|
||||||
|
}
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
#include "catch_tostring.h"
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
@@ -19,18 +18,26 @@ namespace Detail {
|
|||||||
class Approx {
|
class Approx {
|
||||||
private:
|
private:
|
||||||
bool equalityComparisonImpl(double other) const;
|
bool equalityComparisonImpl(double other) const;
|
||||||
|
// Validates the new margin (margin >= 0)
|
||||||
|
// out-of-line to avoid including stdexcept in the header
|
||||||
|
void setMargin(double margin);
|
||||||
|
// Validates the new epsilon (0 < epsilon < 1)
|
||||||
|
// out-of-line to avoid including stdexcept in the header
|
||||||
|
void setEpsilon(double epsilon);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Approx ( double value );
|
explicit Approx ( double value );
|
||||||
|
|
||||||
static Approx custom();
|
static Approx custom();
|
||||||
|
|
||||||
|
Approx operator-() const;
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx operator()( T const& value ) {
|
Approx operator()( T const& value ) {
|
||||||
Approx approx( static_cast<double>(value) );
|
Approx approx( static_cast<double>(value) );
|
||||||
approx.epsilon( m_epsilon );
|
approx.m_epsilon = m_epsilon;
|
||||||
approx.margin( m_margin );
|
approx.m_margin = m_margin;
|
||||||
approx.scale( m_scale );
|
approx.m_scale = m_scale;
|
||||||
return approx;
|
return approx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,27 +90,14 @@ namespace Detail {
|
|||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx& epsilon( T const& newEpsilon ) {
|
Approx& epsilon( T const& newEpsilon ) {
|
||||||
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||||
if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
|
setEpsilon(epsilonAsDouble);
|
||||||
throw std::domain_error
|
|
||||||
( "Invalid Approx::epsilon: " +
|
|
||||||
Catch::Detail::stringify( epsilonAsDouble ) +
|
|
||||||
", Approx::epsilon has to be between 0 and 1" );
|
|
||||||
}
|
|
||||||
m_epsilon = epsilonAsDouble;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||||
Approx& margin( T const& newMargin ) {
|
Approx& margin( T const& newMargin ) {
|
||||||
double marginAsDouble = static_cast<double>(newMargin);
|
double marginAsDouble = static_cast<double>(newMargin);
|
||||||
if( marginAsDouble < 0 ) {
|
setMargin(marginAsDouble);
|
||||||
throw std::domain_error
|
|
||||||
( "Invalid Approx::margin: " +
|
|
||||||
Catch::Detail::stringify( marginAsDouble ) +
|
|
||||||
", Approx::Margin has to be non-negative." );
|
|
||||||
|
|
||||||
}
|
|
||||||
m_margin = marginAsDouble;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +115,12 @@ namespace Detail {
|
|||||||
double m_scale;
|
double m_scale;
|
||||||
double m_value;
|
double m_value;
|
||||||
};
|
};
|
||||||
}
|
} // end namespace Detail
|
||||||
|
|
||||||
|
namespace literals {
|
||||||
|
Detail::Approx operator "" _a(long double val);
|
||||||
|
Detail::Approx operator "" _a(unsigned long long val);
|
||||||
|
} // end namespace literals
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<Catch::Detail::Approx> {
|
struct StringMaker<Catch::Detail::Approx> {
|
||||||
|
@@ -18,9 +18,11 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
namespace {
|
||||||
expr.streamReconstructedExpression( os );
|
auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
|
||||||
return os;
|
expr.streamReconstructedExpression( os );
|
||||||
|
return os;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyExpression::LazyExpression( bool isNegated )
|
LazyExpression::LazyExpression( bool isNegated )
|
||||||
@@ -50,7 +52,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AssertionHandler::AssertionHandler
|
AssertionHandler::AssertionHandler
|
||||||
( StringRef macroName,
|
( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
StringRef capturedExpression,
|
StringRef capturedExpression,
|
||||||
ResultDisposition::Flags resultDisposition )
|
ResultDisposition::Flags resultDisposition )
|
||||||
@@ -79,8 +81,13 @@ namespace Catch {
|
|||||||
// (To go back to the test and change execution, jump over the throw, next)
|
// (To go back to the test and change execution, jump over the throw, next)
|
||||||
CATCH_BREAK_INTO_DEBUGGER();
|
CATCH_BREAK_INTO_DEBUGGER();
|
||||||
}
|
}
|
||||||
if( m_reaction.shouldThrow )
|
if (m_reaction.shouldThrow) {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
throw Catch::TestFailureException();
|
throw Catch::TestFailureException();
|
||||||
|
#else
|
||||||
|
CATCH_ERROR( "Test failure requires aborting test!" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void AssertionHandler::setCompleted() {
|
void AssertionHandler::setCompleted() {
|
||||||
m_completed = true;
|
m_completed = true;
|
||||||
@@ -107,7 +114,7 @@ namespace Catch {
|
|||||||
|
|
||||||
// This is the overload that takes a string and infers the Equals matcher from it
|
// This is the overload that takes a string and infers the Equals matcher from it
|
||||||
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) {
|
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {
|
||||||
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
|
handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@ namespace Catch {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AssertionHandler
|
AssertionHandler
|
||||||
( StringRef macroName,
|
( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
StringRef capturedExpression,
|
StringRef capturedExpression,
|
||||||
ResultDisposition::Flags resultDisposition );
|
ResultDisposition::Flags resultDisposition );
|
||||||
@@ -81,7 +81,7 @@ namespace Catch {
|
|||||||
auto allowThrows() const -> bool;
|
auto allowThrows() const -> bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
|
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
|
@@ -65,9 +65,9 @@ namespace Catch {
|
|||||||
expr = m_info.capturedExpression;
|
expr = m_info.capturedExpression;
|
||||||
else {
|
else {
|
||||||
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
|
||||||
expr += m_info.macroName.c_str();
|
expr += m_info.macroName;
|
||||||
expr += "( ";
|
expr += "( ";
|
||||||
expr += m_info.capturedExpression.c_str();
|
expr += m_info.capturedExpression;
|
||||||
expr += " )";
|
expr += " )";
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
|
@@ -9,8 +9,9 @@
|
|||||||
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
|
||||||
|
|
||||||
#include "catch_assertionhandler.h"
|
#include "catch_assertionhandler.h"
|
||||||
#include "catch_message.h"
|
|
||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
|
#include "catch_message.h"
|
||||||
|
#include "catch_stringref.h"
|
||||||
|
|
||||||
#if !defined(CATCH_CONFIG_DISABLE)
|
#if !defined(CATCH_CONFIG_DISABLE)
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@
|
|||||||
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
|
#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||||
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
|
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
|
||||||
@@ -77,7 +78,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
@@ -94,7 +95,7 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(expr); \
|
static_cast<void>(expr); \
|
||||||
@@ -115,27 +116,32 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
|
||||||
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
} while( false )
|
} while( false )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
|
||||||
|
auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
|
||||||
|
varName.captureValues( 0, __VA_ARGS__ )
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Although this is matcher-based, it can be used with just a string
|
// Although this is matcher-based, it can be used with just a string
|
||||||
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__); \
|
static_cast<void>(__VA_ARGS__); \
|
||||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||||
} \
|
} \
|
||||||
catch( ... ) { \
|
catch( ... ) { \
|
||||||
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
|
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||||
|
@@ -13,9 +13,9 @@ namespace Catch {
|
|||||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||||
|
|
||||||
// This is the general overload that takes a any string matcher
|
// This is the general overload that takes a any string matcher
|
||||||
// There is another overload, in catch_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)
|
// the Equals matcher (so the header does not mention matchers)
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
|
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
|
||||||
std::string exceptionMessage = Catch::translateActiveException();
|
std::string exceptionMessage = Catch::translateActiveException();
|
||||||
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
||||||
handler.handleExpr( expr );
|
handler.handleExpr( expr );
|
||||||
|
@@ -11,8 +11,10 @@
|
|||||||
#include "catch_capture.hpp"
|
#include "catch_capture.hpp"
|
||||||
#include "catch_matchers.h"
|
#include "catch_matchers.h"
|
||||||
#include "catch_matchers_floating.h"
|
#include "catch_matchers_floating.h"
|
||||||
|
#include "catch_matchers_generic.hpp"
|
||||||
#include "catch_matchers_string.h"
|
#include "catch_matchers_string.h"
|
||||||
#include "catch_matchers_vector.h"
|
#include "catch_matchers_vector.h"
|
||||||
|
#include "catch_stringref.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ namespace Catch {
|
|||||||
MatcherT m_matcher;
|
MatcherT m_matcher;
|
||||||
StringRef m_matcherString;
|
StringRef m_matcherString;
|
||||||
public:
|
public:
|
||||||
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
|
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
|
||||||
: ITransientExpression{ true, matcher.match( arg ) },
|
: ITransientExpression{ true, matcher.match( arg ) },
|
||||||
m_arg( arg ),
|
m_arg( arg ),
|
||||||
m_matcher( matcher ),
|
m_matcher( matcher ),
|
||||||
@@ -41,10 +43,10 @@ namespace Catch {
|
|||||||
|
|
||||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||||
|
|
||||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString );
|
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
|
||||||
|
|
||||||
template<typename ArgT, typename MatcherT>
|
template<typename ArgT, typename MatcherT>
|
||||||
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
|
||||||
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +56,9 @@ namespace Catch {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
INTERNAL_CATCH_TRY { \
|
INTERNAL_CATCH_TRY { \
|
||||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
|
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
|
||||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||||
} while( false )
|
} while( false )
|
||||||
@@ -65,14 +67,14 @@ namespace Catch {
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
|
#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
|
||||||
do { \
|
do { \
|
||||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||||
if( catchAssertionHandler.allowThrows() ) \
|
if( catchAssertionHandler.allowThrows() ) \
|
||||||
try { \
|
try { \
|
||||||
static_cast<void>(__VA_ARGS__ ); \
|
static_cast<void>(__VA_ARGS__ ); \
|
||||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||||
} \
|
} \
|
||||||
catch( exceptionType const& ex ) { \
|
catch( exceptionType const& ex ) { \
|
||||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
|
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
|
||||||
} \
|
} \
|
||||||
catch( ... ) { \
|
catch( ... ) { \
|
||||||
catchAssertionHandler.handleUnexpectedInflightException(); \
|
catchAssertionHandler.handleUnexpectedInflightException(); \
|
||||||
|
@@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
#include "catch_string_manip.h"
|
#include "catch_string_manip.h"
|
||||||
|
|
||||||
|
#include "catch_interfaces_registry_hub.h"
|
||||||
|
#include "catch_interfaces_reporter.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
@@ -20,9 +23,19 @@ namespace Catch {
|
|||||||
using namespace clara;
|
using namespace clara;
|
||||||
|
|
||||||
auto const setWarning = [&]( std::string const& warning ) {
|
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 + "'" );
|
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 );
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
};
|
};
|
||||||
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
|
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
|
||||||
@@ -95,6 +108,18 @@ namespace Catch {
|
|||||||
return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
|
return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
|
||||||
return ParserResult::ok( ParseResultType::Matched );
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
};
|
};
|
||||||
|
auto const setReporter = [&]( std::string const& reporter ) {
|
||||||
|
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
||||||
|
|
||||||
|
auto lcReporter = toLower( reporter );
|
||||||
|
auto result = factories.find( lcReporter );
|
||||||
|
|
||||||
|
if( factories.end() != result )
|
||||||
|
config.reporterName = lcReporter;
|
||||||
|
else
|
||||||
|
return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
|
||||||
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
|
};
|
||||||
|
|
||||||
auto cli
|
auto cli
|
||||||
= ExeName( config.processName )
|
= ExeName( config.processName )
|
||||||
@@ -120,7 +145,7 @@ namespace Catch {
|
|||||||
| Opt( config.outputFilename, "filename" )
|
| Opt( config.outputFilename, "filename" )
|
||||||
["-o"]["--out"]
|
["-o"]["--out"]
|
||||||
( "output filename" )
|
( "output filename" )
|
||||||
| Opt( config.reporterNames, "name" )
|
| Opt( setReporter, "name" )
|
||||||
["-r"]["--reporter"]
|
["-r"]["--reporter"]
|
||||||
( "reporter to use (defaults to console)" )
|
( "reporter to use (defaults to console)" )
|
||||||
| Opt( config.name, "name" )
|
| Opt( config.name, "name" )
|
||||||
|
@@ -22,7 +22,9 @@ namespace Catch {
|
|||||||
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
||||||
}
|
}
|
||||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
|
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
|
||||||
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
|
// We can assume that the same file will usually have the same pointer.
|
||||||
|
// Thus, if the pointers are the same, there is no point in calling the strcmp
|
||||||
|
return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||||
|
@@ -22,6 +22,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
// We need a dummy global operator<< so we can bring it into Catch namespace later
|
||||||
|
struct Catch_global_namespace_dummy {};
|
||||||
|
std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct CaseSensitive { enum Choice {
|
struct CaseSensitive { enum Choice {
|
||||||
@@ -63,6 +67,11 @@ namespace Catch {
|
|||||||
|
|
||||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
||||||
|
|
||||||
|
// Bring in operator<< from global namespace into Catch namespace
|
||||||
|
// This is necessary because the overload of operator<< above makes
|
||||||
|
// lookup stop at namespace Catch
|
||||||
|
using ::operator<<;
|
||||||
|
|
||||||
// Use this in variadic streaming macros to allow
|
// Use this in variadic streaming macros to allow
|
||||||
// >> +StreamEndStop
|
// >> +StreamEndStop
|
||||||
// as well as
|
// as well as
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
||||||
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
|
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
|
||||||
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
|
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
|
||||||
|
// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
|
||||||
// ****************
|
// ****************
|
||||||
// Note to maintainers: if new toggles are added please document them
|
// Note to maintainers: if new toggles are added please document them
|
||||||
// in configuration.md, too
|
// in configuration.md, too
|
||||||
@@ -24,13 +25,22 @@
|
|||||||
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
||||||
// can be combined, en-mass, with the _NO_ forms later.
|
// can be combined, en-mass, with the _NO_ forms later.
|
||||||
|
|
||||||
|
#include "catch_platform.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
# if __cplusplus >= 201402L
|
# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
|
||||||
# define CATCH_CPP14_OR_GREATER
|
# define CATCH_CPP14_OR_GREATER
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
|
# define CATCH_CPP17_OR_GREATER
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@@ -48,17 +58,25 @@
|
|||||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||||
_Pragma( "clang diagnostic pop" )
|
_Pragma( "clang diagnostic pop" )
|
||||||
|
|
||||||
|
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
|
||||||
|
_Pragma( "clang diagnostic push" ) \
|
||||||
|
_Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
|
||||||
|
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
|
||||||
|
_Pragma( "clang diagnostic pop" )
|
||||||
|
|
||||||
#endif // __clang__
|
#endif // __clang__
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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
|
// We know some environments not to support full POSIX signals
|
||||||
#if defined(__CYGWIN__) || defined(__QNX__)
|
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
|
||||||
|
#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
|
||||||
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __OS400__
|
#ifdef __OS400__
|
||||||
@@ -66,6 +84,24 @@
|
|||||||
# define CATCH_CONFIG_COLOUR_NONE
|
# define CATCH_CONFIG_COLOUR_NONE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Android somehow still does not support std::to_string
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Not all Windows environments support SEH properly
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PS4
|
||||||
|
#if defined(__ORBIS__)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Cygwin
|
// Cygwin
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
@@ -73,13 +109,25 @@
|
|||||||
// Required for some versions of Cygwin to declare gettimeofday
|
// Required for some versions of Cygwin to declare gettimeofday
|
||||||
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
|
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
|
||||||
# define _BSD_SOURCE
|
# define _BSD_SOURCE
|
||||||
|
// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
|
||||||
|
// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
|
||||||
|
# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
|
||||||
|
&& !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
|
||||||
|
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
|
||||||
|
|
||||||
|
# endif
|
||||||
#endif // __CYGWIN__
|
#endif // __CYGWIN__
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Visual C++
|
// Visual C++
|
||||||
#ifdef _MSC_VER
|
#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
|
// Universal Windows platform does not support SEH
|
||||||
// Or console colours (or console at all...)
|
// Or console colours (or console at all...)
|
||||||
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||||
@@ -90,6 +138,18 @@
|
|||||||
|
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if we are compiled with -fno-exceptions or equivalent
|
||||||
|
#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DJGPP
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
|
||||||
|
#endif // __DJGPP__
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Use of __COUNTER__ is suppressed during code analysis in
|
// Use of __COUNTER__ is suppressed during code analysis in
|
||||||
@@ -101,16 +161,75 @@
|
|||||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if string_view is available and usable
|
||||||
|
// The check is split apart to work around v140 (VS2015) preprocessor issue...
|
||||||
|
#if defined(__has_include)
|
||||||
|
#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check if variant is available and usable
|
||||||
|
#if defined(__has_include)
|
||||||
|
# if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
# if defined(__clang__) && (__clang_major__ < 8)
|
||||||
|
// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
|
||||||
|
// fix should be in clang 8, workaround in libstdc++ 8.2
|
||||||
|
# include <ciso646>
|
||||||
|
# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||||
|
# define CATCH_CONFIG_NO_CPP17_VARIANT
|
||||||
|
# else
|
||||||
|
# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
|
||||||
|
# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
|
||||||
|
# endif // defined(__clang__) && (__clang_major__ < 8)
|
||||||
|
# endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
|
||||||
|
#endif // __has_include
|
||||||
|
|
||||||
|
|
||||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||||
# define CATCH_CONFIG_COUNTER
|
# define CATCH_CONFIG_COUNTER
|
||||||
#endif
|
#endif
|
||||||
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
|
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
|
||||||
# define CATCH_CONFIG_WINDOWS_SEH
|
# define CATCH_CONFIG_WINDOWS_SEH
|
||||||
#endif
|
#endif
|
||||||
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
||||||
#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
|
# define CATCH_CONFIG_POSIX_SIGNALS
|
||||||
#endif
|
#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_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
|
||||||
|
# define CATCH_CONFIG_CPP17_STRING_VIEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
|
||||||
|
# define CATCH_CONFIG_CPP17_VARIANT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
||||||
|
# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
# define CATCH_CONFIG_NEW_CAPTURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
# define CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||||
@@ -120,6 +239,20 @@
|
|||||||
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
|
||||||
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
|
||||||
|
# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
|
||||||
|
# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
#define CATCH_TRY if ((true))
|
||||||
|
#define CATCH_CATCH_ALL if ((false))
|
||||||
|
#define CATCH_CATCH_ANON(type) if ((false))
|
||||||
|
#else
|
||||||
|
#define CATCH_TRY try
|
||||||
|
#define CATCH_CATCH_ALL catch (...)
|
||||||
|
#define CATCH_CATCH_ANON(type) catch (type)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
|
||||||
|
@@ -15,12 +15,16 @@ namespace Catch {
|
|||||||
: m_data( data ),
|
: m_data( data ),
|
||||||
m_stream( openStream() )
|
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 )
|
for( auto const& testOrTags : data.testsOrTags )
|
||||||
parser.parse( testOrTags );
|
parser.parse( testOrTags );
|
||||||
m_testSpec = parser.testSpec();
|
|
||||||
}
|
}
|
||||||
|
m_testSpec = parser.testSpec();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& Config::getFilename() const {
|
std::string const& Config::getFilename() const {
|
||||||
@@ -33,11 +37,13 @@ namespace Catch {
|
|||||||
bool Config::listReporters() const { return m_data.listReporters; }
|
bool Config::listReporters() const { return m_data.listReporters; }
|
||||||
|
|
||||||
std::string Config::getProcessName() const { return m_data.processName; }
|
std::string Config::getProcessName() const { return m_data.processName; }
|
||||||
|
std::string const& Config::getReporterName() const { return m_data.reporterName; }
|
||||||
|
|
||||||
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
|
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||||
|
|
||||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||||
|
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||||
|
|
||||||
bool Config::showHelp() const { return m_data.showHelp; }
|
bool Config::showHelp() const { return m_data.showHelp; }
|
||||||
|
|
||||||
@@ -46,7 +52,8 @@ namespace Catch {
|
|||||||
std::ostream& Config::stream() const { return m_stream->stream(); }
|
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; }
|
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::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; }
|
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||||
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||||
|
@@ -54,8 +54,12 @@ namespace Catch {
|
|||||||
std::string outputFilename;
|
std::string outputFilename;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string processName;
|
std::string processName;
|
||||||
|
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
|
||||||
|
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
||||||
|
#endif
|
||||||
|
std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
|
||||||
|
#undef CATCH_CONFIG_DEFAULT_REPORTER
|
||||||
|
|
||||||
std::vector<std::string> reporterNames;
|
|
||||||
std::vector<std::string> testsOrTags;
|
std::vector<std::string> testsOrTags;
|
||||||
std::vector<std::string> sectionsToRun;
|
std::vector<std::string> sectionsToRun;
|
||||||
};
|
};
|
||||||
@@ -76,11 +80,13 @@ namespace Catch {
|
|||||||
bool listReporters() const;
|
bool listReporters() const;
|
||||||
|
|
||||||
std::string getProcessName() const;
|
std::string getProcessName() const;
|
||||||
|
std::string const& getReporterName() const;
|
||||||
|
|
||||||
std::vector<std::string> const& getReporterNames() const;
|
std::vector<std::string> const& getTestsOrTags() const;
|
||||||
std::vector<std::string> const& getSectionsToRun() const override;
|
std::vector<std::string> const& getSectionsToRun() const override;
|
||||||
|
|
||||||
virtual TestSpec const& testSpec() const override;
|
virtual TestSpec const& testSpec() const override;
|
||||||
|
bool hasTestFilters() const override;
|
||||||
|
|
||||||
bool showHelp() const;
|
bool showHelp() const;
|
||||||
|
|
||||||
@@ -90,6 +96,7 @@ namespace Catch {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
bool includeSuccessfulResults() const override;
|
bool includeSuccessfulResults() const override;
|
||||||
bool warnAboutMissingAssertions() const override;
|
bool warnAboutMissingAssertions() const override;
|
||||||
|
bool warnAboutNoTests() const override;
|
||||||
ShowDurations::OrNot showDurations() const override;
|
ShowDurations::OrNot showDurations() const override;
|
||||||
RunTests::InWhatOrder runOrder() const override;
|
RunTests::InWhatOrder runOrder() const override;
|
||||||
unsigned int rngSeed() const override;
|
unsigned int rngSeed() const override;
|
||||||
@@ -107,6 +114,7 @@ namespace Catch {
|
|||||||
|
|
||||||
std::unique_ptr<IStream const> m_stream;
|
std::unique_ptr<IStream const> m_stream;
|
||||||
TestSpec m_testSpec;
|
TestSpec m_testSpec;
|
||||||
|
bool m_hasTestFilters = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -11,8 +11,8 @@
|
|||||||
# pragma clang diagnostic push
|
# pragma clang diagnostic push
|
||||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "catch_console_colour.h"
|
#include "catch_console_colour.h"
|
||||||
#include "catch_enforce.h"
|
#include "catch_enforce.h"
|
||||||
#include "catch_errno_guard.h"
|
#include "catch_errno_guard.h"
|
||||||
@@ -84,8 +84,12 @@ namespace {
|
|||||||
case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
|
case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
|
||||||
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
||||||
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
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" );
|
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::BrightRed: return setColour( "[1;31m" );
|
||||||
case Colour::BrightGreen: return setColour( "[1;32m" );
|
case Colour::BrightGreen: return setColour( "[1;32m" );
|
||||||
case Colour::BrightWhite: return setColour( "[1;37m" );
|
case Colour::BrightWhite: return setColour( "[1;37m" );
|
||||||
|
case Colour::BrightYellow: return setColour( "[1;33m" );
|
||||||
|
|
||||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||||
|
default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static IColourImpl* instance() {
|
static IColourImpl* instance() {
|
||||||
@@ -163,7 +169,12 @@ namespace {
|
|||||||
#ifdef CATCH_PLATFORM_MAC
|
#ifdef CATCH_PLATFORM_MAC
|
||||||
!isDebuggerActive() &&
|
!isDebuggerActive() &&
|
||||||
#endif
|
#endif
|
||||||
isatty(STDOUT_FILENO);
|
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
|
||||||
|
isatty(STDOUT_FILENO)
|
||||||
|
#else
|
||||||
|
false
|
||||||
|
#endif
|
||||||
|
;
|
||||||
}
|
}
|
||||||
IColourImpl* platformColourInstance() {
|
IColourImpl* platformColourInstance() {
|
||||||
ErrnoGuard guard;
|
ErrnoGuard guard;
|
||||||
@@ -196,7 +207,7 @@ namespace Catch {
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
||||||
Colour::Colour( Colour&& rhs ) noexcept {
|
Colour::Colour( Colour&& rhs ) noexcept {
|
||||||
m_moved = rhs.m_moved;
|
m_moved = rhs.m_moved;
|
||||||
rhs.m_moved = true;
|
rhs.m_moved = true;
|
||||||
}
|
}
|
||||||
@@ -205,7 +216,7 @@ namespace Catch {
|
|||||||
rhs.m_moved = true;
|
rhs.m_moved = true;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
||||||
|
|
||||||
void Colour::use( Code _colourCode ) {
|
void Colour::use( Code _colourCode ) {
|
||||||
|
@@ -30,10 +30,11 @@ namespace Catch {
|
|||||||
BrightGreen = Bright | Green,
|
BrightGreen = Bright | Green,
|
||||||
LightGrey = Bright | Grey,
|
LightGrey = Bright | Grey,
|
||||||
BrightWhite = Bright | White,
|
BrightWhite = Bright | White,
|
||||||
|
BrightYellow = Bright | Yellow,
|
||||||
|
|
||||||
// By intention
|
// By intention
|
||||||
FileName = LightGrey,
|
FileName = LightGrey,
|
||||||
Warning = Yellow,
|
Warning = BrightYellow,
|
||||||
ResultError = BrightRed,
|
ResultError = BrightRed,
|
||||||
ResultSuccess = BrightGreen,
|
ResultSuccess = BrightGreen,
|
||||||
ResultExpectedFailure = Warning,
|
ResultExpectedFailure = Warning,
|
||||||
@@ -42,7 +43,7 @@ namespace Catch {
|
|||||||
Success = Green,
|
Success = Green,
|
||||||
|
|
||||||
OriginalExpression = Cyan,
|
OriginalExpression = Cyan,
|
||||||
ReconstructedExpression = Yellow,
|
ReconstructedExpression = BrightYellow,
|
||||||
|
|
||||||
SecondaryText = LightGrey,
|
SecondaryText = LightGrey,
|
||||||
Headers = White
|
Headers = White
|
||||||
|
@@ -9,21 +9,23 @@
|
|||||||
#include "catch_debug_console.h"
|
#include "catch_debug_console.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
#include "catch_platform.h"
|
#include "catch_platform.h"
|
||||||
|
#include "catch_windows_h_proxy.h"
|
||||||
|
|
||||||
#ifdef CATCH_PLATFORM_WINDOWS
|
#ifdef CATCH_PLATFORM_WINDOWS
|
||||||
|
|
||||||
#include "catch_windows_h_proxy.h"
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
void writeToDebugConsole( std::string const& text ) {
|
void writeToDebugConsole( std::string const& text ) {
|
||||||
::OutputDebugStringA( text.c_str() );
|
::OutputDebugStringA( text.c_str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
void writeToDebugConsole( std::string const& text ) {
|
void writeToDebugConsole( std::string const& text ) {
|
||||||
// !TBD: Need a version for Mac/ XCode and other IDEs
|
// !TBD: Need a version for Mac/ XCode and other IDEs
|
||||||
Catch::cout() << text;
|
Catch::cout() << text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // Platform
|
#endif // Platform
|
||||||
|
@@ -40,7 +40,10 @@ namespace Catch {
|
|||||||
#ifdef CATCH_TRAP
|
#ifdef CATCH_TRAP
|
||||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
||||||
#else
|
#else
|
||||||
#define CATCH_BREAK_INTO_DEBUGGER() (void)0, 0
|
namespace Catch {
|
||||||
|
inline void doNothing() {}
|
||||||
|
}
|
||||||
|
#define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
#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)
|
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
|
||||||
template<typename LhsT, typename RhsT>
|
template<typename LhsT, typename RhsT>
|
||||||
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; };
|
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
|
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -93,7 +93,7 @@ namespace Catch {
|
|||||||
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
|
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
|
||||||
|
|
||||||
template<typename LhsT, typename RhsT>
|
template<typename LhsT, typename RhsT>
|
||||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
|
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
|
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -128,19 +128,19 @@ namespace Catch {
|
|||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
return { m_lhs > rhs, m_lhs, ">", rhs };
|
return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
|
||||||
}
|
}
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
return { m_lhs < rhs, m_lhs, "<", rhs };
|
return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
|
||||||
}
|
}
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
return { m_lhs >= rhs, m_lhs, ">=", rhs };
|
return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
|
||||||
}
|
}
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||||
return { m_lhs <= rhs, m_lhs, "<=", rhs };
|
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#ifndef __OBJC__
|
#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
|
// Standard C/C++ Win32 Unicode wmain entry point
|
||||||
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||||
#else
|
#else
|
||||||
|
19
include/internal/catch_enforce.cpp
Normal file
19
include/internal/catch_enforce.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 03/09/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const& e) {
|
||||||
|
Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
|
||||||
|
<< "The message was: " << e.what() << '\n';
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Catch;
|
@@ -8,18 +8,35 @@
|
|||||||
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||||
|
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iosfwd>
|
|
||||||
|
namespace Catch {
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
|
template <typename Ex>
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(Ex const& e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||||
|
[[noreturn]]
|
||||||
|
void throw_exception(std::exception const& e);
|
||||||
|
#endif
|
||||||
|
} // namespace Catch;
|
||||||
|
|
||||||
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
||||||
type( static_cast<std::ostringstream&&>( Catch::ReusableStringStream().get() << msg ).str() )
|
type( ( Catch::ReusableStringStream() << msg ).str() )
|
||||||
#define CATCH_INTERNAL_ERROR( msg ) \
|
#define CATCH_INTERNAL_ERROR( msg ) \
|
||||||
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
|
||||||
#define CATCH_ERROR( msg ) \
|
#define CATCH_ERROR( msg ) \
|
||||||
throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg )
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
|
||||||
|
#define CATCH_RUNTIME_ERROR( msg ) \
|
||||||
|
Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
|
||||||
#define CATCH_ENFORCE( condition, msg ) \
|
#define CATCH_ENFORCE( condition, msg ) \
|
||||||
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
|
do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
|
||||||
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||||
|
@@ -6,8 +6,10 @@
|
|||||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_assertionhandler.h"
|
|
||||||
#include "catch_exception_translator_registry.h"
|
#include "catch_exception_translator_registry.h"
|
||||||
|
#include "catch_assertionhandler.h"
|
||||||
|
#include "catch_compiler_capabilities.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
#import "Foundation/Foundation.h"
|
#import "Foundation/Foundation.h"
|
||||||
@@ -22,6 +24,7 @@ namespace Catch {
|
|||||||
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
|
m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||||
try {
|
try {
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
@@ -33,6 +36,17 @@ namespace Catch {
|
|||||||
return Catch::Detail::stringify( [exception description] );
|
return Catch::Detail::stringify( [exception description] );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
// Compiling a mixed mode project with MSVC means that CLR
|
||||||
|
// exceptions will be caught in (...) as well. However, these
|
||||||
|
// do not fill-in std::current_exception and thus lead to crash
|
||||||
|
// when attempting rethrow.
|
||||||
|
// /EHa switch also causes structured exceptions to be caught
|
||||||
|
// here, but they fill-in current_exception properly, so
|
||||||
|
// at worst the output should be a little weird, instead of
|
||||||
|
// causing a crash.
|
||||||
|
if (std::current_exception() == nullptr) {
|
||||||
|
return "Non C++ exception. Possibly a CLR exception.";
|
||||||
|
}
|
||||||
return tryTranslators();
|
return tryTranslators();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -53,6 +67,13 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||||
|
std::string ExceptionTranslatorRegistry::translateActiveException() const {
|
||||||
|
CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
std::string ExceptionTranslatorRegistry::tryTranslators() const {
|
||||||
if( m_translators.empty() )
|
if( m_translators.empty() )
|
||||||
std::rethrow_exception(std::current_exception());
|
std::rethrow_exception(std::current_exception());
|
||||||
|
@@ -17,6 +17,8 @@
|
|||||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Report the error condition
|
// Report the error condition
|
||||||
void reportFatal( char const * const message ) {
|
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 )
|
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
void FatalConditionHandler::reset() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
struct SignalDefs { DWORD id; const char* name; };
|
struct SignalDefs { DWORD id; const char* name; };
|
||||||
@@ -72,7 +68,6 @@ namespace Catch {
|
|||||||
|
|
||||||
void FatalConditionHandler::reset() {
|
void FatalConditionHandler::reset() {
|
||||||
if (isSet) {
|
if (isSet) {
|
||||||
// Unregister handler and restore the old guarantee
|
|
||||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||||
SetThreadStackGuarantee(&guaranteeSize);
|
SetThreadStackGuarantee(&guaranteeSize);
|
||||||
exceptionHandlerHandle = nullptr;
|
exceptionHandlerHandle = nullptr;
|
||||||
@@ -91,20 +86,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
|
|||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||||
|
|
||||||
#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>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -112,6 +94,11 @@ namespace Catch {
|
|||||||
int id;
|
int id;
|
||||||
const char* name;
|
const char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 32kb for the alternate stack seems to be sufficient. However, this value
|
||||||
|
// is experimentally determined, so that's not guaranteed.
|
||||||
|
constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
|
||||||
|
|
||||||
static SignalDefs signalDefs[] = {
|
static SignalDefs signalDefs[] = {
|
||||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||||
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
{ SIGILL, "SIGILL - Illegal instruction signal" },
|
||||||
@@ -139,7 +126,7 @@ namespace Catch {
|
|||||||
isSet = true;
|
isSet = true;
|
||||||
stack_t sigStack;
|
stack_t sigStack;
|
||||||
sigStack.ss_sp = altStackMem;
|
sigStack.ss_sp = altStackMem;
|
||||||
sigStack.ss_size = SIGSTKSZ;
|
sigStack.ss_size = sigStackSize;
|
||||||
sigStack.ss_flags = 0;
|
sigStack.ss_flags = 0;
|
||||||
sigaltstack(&sigStack, &oldSigStack);
|
sigaltstack(&sigStack, &oldSigStack);
|
||||||
struct sigaction sa = { };
|
struct sigaction sa = { };
|
||||||
@@ -171,14 +158,18 @@ namespace Catch {
|
|||||||
bool FatalConditionHandler::isSet = false;
|
bool FatalConditionHandler::isSet = false;
|
||||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||||
stack_t FatalConditionHandler::oldSigStack = {};
|
stack_t FatalConditionHandler::oldSigStack = {};
|
||||||
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
|
char FatalConditionHandler::altStackMem[sigStackSize] = {};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
#else
|
||||||
|
|
||||||
#endif // not Windows
|
namespace Catch {
|
||||||
|
void FatalConditionHandler::reset() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // signals/SEH handling
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# pragma GCC diagnostic pop
|
# pragma GCC diagnostic pop
|
||||||
|
@@ -9,23 +9,12 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "catch_platform.h"
|
#include "catch_platform.h"
|
||||||
#include "catch_compiler_capabilities.h"
|
#include "catch_compiler_capabilities.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
|
||||||
#include "catch_windows_h_proxy.h"
|
#include "catch_windows_h_proxy.h"
|
||||||
|
|
||||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
|
||||||
|
|
||||||
namespace Catch {
|
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||||
struct FatalConditionHandler {
|
|
||||||
void reset();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -44,20 +33,7 @@ namespace Catch {
|
|||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
@@ -66,7 +42,7 @@ namespace Catch {
|
|||||||
struct FatalConditionHandler {
|
struct FatalConditionHandler {
|
||||||
|
|
||||||
static bool isSet;
|
static bool isSet;
|
||||||
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
|
static struct sigaction oldSigActions[];
|
||||||
static stack_t oldSigStack;
|
static stack_t oldSigStack;
|
||||||
static char altStackMem[];
|
static char altStackMem[];
|
||||||
|
|
||||||
@@ -79,8 +55,15 @@ namespace Catch {
|
|||||||
|
|
||||||
} // 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
|
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||||
|
50
include/internal/catch_generators.cpp
Normal file
50
include/internal/catch_generators.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_generators.hpp"
|
||||||
|
#include "catch_random_number_generator.h"
|
||||||
|
#include "catch_interfaces_capture.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
IGeneratorTracker::~IGeneratorTracker() {}
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
GeneratorBase::~GeneratorBase() {}
|
||||||
|
|
||||||
|
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) {
|
||||||
|
|
||||||
|
assert( selectionSize <= sourceSize );
|
||||||
|
std::vector<size_t> indices;
|
||||||
|
indices.reserve( selectionSize );
|
||||||
|
std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 );
|
||||||
|
|
||||||
|
std::set<size_t> seen;
|
||||||
|
// !TBD: improve this algorithm
|
||||||
|
while( indices.size() < selectionSize ) {
|
||||||
|
auto index = uid( rng() );
|
||||||
|
if( seen.insert( index ).second )
|
||||||
|
indices.push_back( index );
|
||||||
|
}
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||||
|
return getResultCapture().acquireGeneratorTracker( lineInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
auto all<int>() -> Generator<int> {
|
||||||
|
return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
253
include/internal/catch_generators.hpp
Normal file
253
include/internal/catch_generators.hpp
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 15/6/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_interfaces_generatortracker.h"
|
||||||
|
#include "catch_common.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Generators {
|
||||||
|
|
||||||
|
// !TBD move this into its own location?
|
||||||
|
namespace pf{
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique( Args&&... args ) {
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct IGenerator {
|
||||||
|
virtual ~IGenerator() {}
|
||||||
|
virtual auto get( size_t index ) const -> T = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class SingleValueGenerator : public IGenerator<T> {
|
||||||
|
T m_value;
|
||||||
|
public:
|
||||||
|
SingleValueGenerator( T const& value ) : m_value( value ) {}
|
||||||
|
|
||||||
|
auto get( size_t ) const -> T override {
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class FixedValuesGenerator : public IGenerator<T> {
|
||||||
|
std::vector<T> m_values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
return m_values[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class RangeGenerator : public IGenerator<T> {
|
||||||
|
T const m_first;
|
||||||
|
T const m_last;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) {
|
||||||
|
assert( m_last > m_first );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
// ToDo:: introduce a safe cast to catch potential overflows
|
||||||
|
return static_cast<T>(m_first+index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct NullGenerator : IGenerator<T> {
|
||||||
|
auto get( size_t ) const -> T override {
|
||||||
|
CATCH_INTERNAL_ERROR("A Null Generator is always empty");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Generator {
|
||||||
|
std::unique_ptr<IGenerator<T>> m_generator;
|
||||||
|
size_t m_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Generator( size_t size, std::unique_ptr<IGenerator<T>> generator )
|
||||||
|
: m_generator( std::move( generator ) ),
|
||||||
|
m_size( size )
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto size() const -> size_t { return m_size; }
|
||||||
|
auto operator[]( size_t index ) const -> T {
|
||||||
|
assert( index < m_size );
|
||||||
|
return m_generator->get( index );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class GeneratorRandomiser : public IGenerator<T> {
|
||||||
|
Generator<T> m_baseGenerator;
|
||||||
|
|
||||||
|
std::vector<size_t> m_indices;
|
||||||
|
public:
|
||||||
|
GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems )
|
||||||
|
: m_baseGenerator( std::move( baseGenerator ) ),
|
||||||
|
m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto get( size_t index ) const -> T override {
|
||||||
|
return m_baseGenerator[m_indices[index]];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RequiresASpecialisationFor;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
auto all<int>() -> Generator<int>;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto range( T const& first, T const& last ) -> Generator<T> {
|
||||||
|
return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto random( T const& first, T const& last ) -> Generator<T> {
|
||||||
|
auto gen = range( first, last );
|
||||||
|
auto size = gen.size();
|
||||||
|
|
||||||
|
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) );
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto random( size_t size ) -> Generator<T> {
|
||||||
|
return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto values( std::initializer_list<T> values ) -> Generator<T> {
|
||||||
|
return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) );
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto value( T const& val ) -> Generator<T> {
|
||||||
|
return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto as() -> Generator<T> {
|
||||||
|
return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> {
|
||||||
|
return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Generators : GeneratorBase {
|
||||||
|
std::vector<Generator<T>> m_generators;
|
||||||
|
|
||||||
|
using type = T;
|
||||||
|
|
||||||
|
Generators() : GeneratorBase( 0 ) {}
|
||||||
|
|
||||||
|
void populate( T&& val ) {
|
||||||
|
m_size += 1;
|
||||||
|
m_generators.emplace_back( value( std::move( val ) ) );
|
||||||
|
}
|
||||||
|
template<typename U>
|
||||||
|
void populate( U&& val ) {
|
||||||
|
populate( T( std::move( val ) ) );
|
||||||
|
}
|
||||||
|
void populate( Generator<T>&& generator ) {
|
||||||
|
m_size += generator.size();
|
||||||
|
m_generators.emplace_back( std::move( generator ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U, typename... Gs>
|
||||||
|
void populate( U&& valueOrGenerator, Gs... moreGenerators ) {
|
||||||
|
populate( std::forward<U>( valueOrGenerator ) );
|
||||||
|
populate( std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator[]( size_t index ) const -> T {
|
||||||
|
size_t sizes = 0;
|
||||||
|
for( auto const& gen : m_generators ) {
|
||||||
|
auto localIndex = index-sizes;
|
||||||
|
sizes += gen.size();
|
||||||
|
if( index < sizes )
|
||||||
|
return gen[localIndex];
|
||||||
|
}
|
||||||
|
CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
Generators<T> generators;
|
||||||
|
generators.m_generators.reserve( 1+sizeof...(Gs) );
|
||||||
|
generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
auto makeGenerators( Generator<T>&& generator ) -> Generators<T> {
|
||||||
|
Generators<T> generators;
|
||||||
|
generators.populate( std::move( generator ) );
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
template<typename T, typename... Gs>
|
||||||
|
auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
template<typename T, typename U, typename... Gs>
|
||||||
|
auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> {
|
||||||
|
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||||
|
// the expression used in the typedef inside, when it is in
|
||||||
|
// return type. Yeah, ¯\_(ツ)_/¯
|
||||||
|
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) {
|
||||||
|
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||||
|
|
||||||
|
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
||||||
|
if( !tracker.hasGenerator() )
|
||||||
|
tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) );
|
||||||
|
|
||||||
|
auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() );
|
||||||
|
return generator[tracker.getIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#define GENERATE( ... ) \
|
||||||
|
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
@@ -24,8 +24,10 @@ namespace Catch {
|
|||||||
struct BenchmarkInfo;
|
struct BenchmarkInfo;
|
||||||
struct BenchmarkStats;
|
struct BenchmarkStats;
|
||||||
struct AssertionReaction;
|
struct AssertionReaction;
|
||||||
|
struct SourceLineInfo;
|
||||||
|
|
||||||
struct ITransientExpression;
|
struct ITransientExpression;
|
||||||
|
struct IGeneratorTracker;
|
||||||
|
|
||||||
struct IResultCapture {
|
struct IResultCapture {
|
||||||
|
|
||||||
@@ -36,6 +38,8 @@ namespace Catch {
|
|||||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
||||||
|
|
||||||
|
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
||||||
|
|
||||||
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||||
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
|
virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
|
||||||
|
|
||||||
|
@@ -25,7 +25,8 @@ namespace Catch {
|
|||||||
|
|
||||||
struct WarnAbout { enum What {
|
struct WarnAbout { enum What {
|
||||||
Nothing = 0x00,
|
Nothing = 0x00,
|
||||||
NoAssertions = 0x01
|
NoAssertions = 0x01,
|
||||||
|
NoTests = 0x02
|
||||||
}; };
|
}; };
|
||||||
|
|
||||||
struct ShowDurations { enum OrNot {
|
struct ShowDurations { enum OrNot {
|
||||||
@@ -62,10 +63,12 @@ namespace Catch {
|
|||||||
virtual bool includeSuccessfulResults() const = 0;
|
virtual bool includeSuccessfulResults() const = 0;
|
||||||
virtual bool shouldDebugBreak() const = 0;
|
virtual bool shouldDebugBreak() const = 0;
|
||||||
virtual bool warnAboutMissingAssertions() const = 0;
|
virtual bool warnAboutMissingAssertions() const = 0;
|
||||||
|
virtual bool warnAboutNoTests() const = 0;
|
||||||
virtual int abortAfter() const = 0;
|
virtual int abortAfter() const = 0;
|
||||||
virtual bool showInvisibles() const = 0;
|
virtual bool showInvisibles() const = 0;
|
||||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||||
virtual TestSpec const& testSpec() const = 0;
|
virtual TestSpec const& testSpec() const = 0;
|
||||||
|
virtual bool hasTestFilters() const = 0;
|
||||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||||
virtual unsigned int rngSeed() const = 0;
|
virtual unsigned int rngSeed() const = 0;
|
||||||
virtual int benchmarkResolutionMultiple() const = 0;
|
virtual int benchmarkResolutionMultiple() const = 0;
|
||||||
|
39
include/internal/catch_interfaces_generatortracker.h
Normal file
39
include/internal/catch_interfaces_generatortracker.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 26/6/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
namespace Generators {
|
||||||
|
class GeneratorBase {
|
||||||
|
protected:
|
||||||
|
size_t m_size = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeneratorBase( size_t size ) : m_size( size ) {}
|
||||||
|
virtual ~GeneratorBase();
|
||||||
|
auto size() const -> size_t { return m_size; }
|
||||||
|
};
|
||||||
|
using GeneratorBasePtr = std::unique_ptr<GeneratorBase>;
|
||||||
|
|
||||||
|
} // namespace Generators
|
||||||
|
|
||||||
|
struct IGeneratorTracker {
|
||||||
|
virtual ~IGeneratorTracker();
|
||||||
|
virtual auto hasGenerator() const -> bool = 0;
|
||||||
|
virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
|
||||||
|
virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
|
||||||
|
virtual auto getIndex() const -> std::size_t = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif //TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
|
@@ -33,7 +33,7 @@ namespace Catch {
|
|||||||
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
||||||
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
||||||
|
|
||||||
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
|
virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
|
||||||
@@ -49,7 +49,7 @@ namespace Catch {
|
|||||||
virtual void registerStartupException() noexcept = 0;
|
virtual void registerStartupException() noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
IRegistryHub& getRegistryHub();
|
IRegistryHub const& getRegistryHub();
|
||||||
IMutableRegistryHub& getMutableRegistryHub();
|
IMutableRegistryHub& getMutableRegistryHub();
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
std::string translateActiveException();
|
std::string translateActiveException();
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_interfaces_reporter.h"
|
#include "catch_interfaces_reporter.h"
|
||||||
#include "../reporters/catch_reporter_multi.h"
|
#include "../reporters/catch_reporter_listening.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
@@ -111,25 +111,4 @@ namespace Catch {
|
|||||||
IReporterFactory::~IReporterFactory() = default;
|
IReporterFactory::~IReporterFactory() = default;
|
||||||
IReporterRegistry::~IReporterRegistry() = default;
|
IReporterRegistry::~IReporterRegistry() = default;
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
|
|
||||||
|
|
||||||
if( !existingReporter ) {
|
|
||||||
existingReporter = std::move( additionalReporter );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultipleReporters* multi = nullptr;
|
|
||||||
|
|
||||||
if( existingReporter->isMulti() ) {
|
|
||||||
multi = static_cast<MultipleReporters*>( existingReporter.get() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
|
|
||||||
newMulti->add( std::move( existingReporter ) );
|
|
||||||
multi = newMulti.get();
|
|
||||||
existingReporter = std::move( newMulti );
|
|
||||||
}
|
|
||||||
multi->add( std::move( additionalReporter ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -42,6 +42,7 @@ namespace Catch {
|
|||||||
|
|
||||||
struct ReporterPreferences {
|
struct ReporterPreferences {
|
||||||
bool shouldRedirectStdOut = false;
|
bool shouldRedirectStdOut = false;
|
||||||
|
bool shouldReportAllAssertions = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -226,8 +227,6 @@ namespace Catch {
|
|||||||
virtual Listeners const& getListeners() const = 0;
|
virtual Listeners const& getListeners() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
|
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_leak_detector.h"
|
#include "catch_leak_detector.h"
|
||||||
|
#include "catch_interfaces_registry_hub.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
||||||
@@ -13,16 +14,16 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
LeakDetector::LeakDetector() {
|
LeakDetector::LeakDetector() {
|
||||||
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||||
flag |= _CRTDBG_LEAK_CHECK_DF;
|
flag |= _CRTDBG_LEAK_CHECK_DF;
|
||||||
flag |= _CRTDBG_ALLOC_MEM_DF;
|
flag |= _CRTDBG_ALLOC_MEM_DF;
|
||||||
_CrtSetDbgFlag(flag);
|
_CrtSetDbgFlag(flag);
|
||||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||||
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
||||||
// Change this to leaking allocation's number to break there
|
// Change this to leaking allocation's number to break there
|
||||||
_CrtSetBreakAlloc(-1);
|
_CrtSetBreakAlloc(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -30,3 +31,7 @@ namespace Catch {
|
|||||||
Catch::LeakDetector::LeakDetector() {}
|
Catch::LeakDetector::LeakDetector() {}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Catch::LeakDetector::~LeakDetector() {
|
||||||
|
Catch::cleanUp();
|
||||||
|
}
|
||||||
|
@@ -11,6 +11,7 @@ namespace Catch {
|
|||||||
|
|
||||||
struct LeakDetector {
|
struct LeakDetector {
|
||||||
LeakDetector();
|
LeakDetector();
|
||||||
|
~LeakDetector();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -28,11 +28,10 @@ namespace Catch {
|
|||||||
|
|
||||||
std::size_t listTests( Config const& config ) {
|
std::size_t listTests( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec testSpec = config.testSpec();
|
||||||
if( config.testSpec().hasFilters() )
|
if( config.hasTestFilters() )
|
||||||
Catch::cout() << "Matching test cases:\n";
|
Catch::cout() << "Matching test cases:\n";
|
||||||
else {
|
else {
|
||||||
Catch::cout() << "All available test cases:\n";
|
Catch::cout() << "All available test cases:\n";
|
||||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||||
@@ -54,7 +53,7 @@ namespace Catch {
|
|||||||
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
|
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;
|
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
|
||||||
else
|
else
|
||||||
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
|
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
|
||||||
@@ -63,8 +62,6 @@ namespace Catch {
|
|||||||
|
|
||||||
std::size_t listTestsNamesOnly( Config const& config ) {
|
std::size_t listTestsNamesOnly( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec testSpec = config.testSpec();
|
||||||
if( !config.testSpec().hasFilters() )
|
|
||||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
||||||
std::size_t matchedTests = 0;
|
std::size_t matchedTests = 0;
|
||||||
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||||
for( auto const& testCaseInfo : matchedTestCases ) {
|
for( auto const& testCaseInfo : matchedTestCases ) {
|
||||||
@@ -94,11 +91,10 @@ namespace Catch {
|
|||||||
|
|
||||||
std::size_t listTags( Config const& config ) {
|
std::size_t listTags( Config const& config ) {
|
||||||
TestSpec testSpec = config.testSpec();
|
TestSpec testSpec = config.testSpec();
|
||||||
if( config.testSpec().hasFilters() )
|
if( config.hasTestFilters() )
|
||||||
Catch::cout() << "Tags for matching test cases:\n";
|
Catch::cout() << "Tags for matching test cases:\n";
|
||||||
else {
|
else {
|
||||||
Catch::cout() << "All available tags:\n";
|
Catch::cout() << "All available tags:\n";
|
||||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, TagInfo> tagCounts;
|
std::map<std::string, TagInfo> tagCounts;
|
||||||
@@ -128,7 +124,7 @@ namespace Catch {
|
|||||||
return tagCounts.size();
|
return tagCounts.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t listReporters( Config const& /*config*/ ) {
|
std::size_t listReporters() {
|
||||||
Catch::cout() << "Available reporters:\n";
|
Catch::cout() << "Available reporters:\n";
|
||||||
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
|
||||||
std::size_t maxNameLen = 0;
|
std::size_t maxNameLen = 0;
|
||||||
@@ -159,7 +155,7 @@ namespace Catch {
|
|||||||
if( config.listTags() )
|
if( config.listTags() )
|
||||||
listedCount = listedCount.valueOr(0) + listTags( config );
|
listedCount = listedCount.valueOr(0) + listTags( config );
|
||||||
if( config.listReporters() )
|
if( config.listReporters() )
|
||||||
listedCount = listedCount.valueOr(0) + listReporters( config );
|
listedCount = listedCount.valueOr(0) + listReporters();
|
||||||
return listedCount;
|
return listedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ namespace Catch {
|
|||||||
|
|
||||||
std::size_t listTags( Config const& config );
|
std::size_t listTags( Config const& config );
|
||||||
|
|
||||||
std::size_t listReporters( Config const& /*config*/ );
|
std::size_t listReporters();
|
||||||
|
|
||||||
Option<std::size_t> list( Config const& config );
|
Option<std::size_t> list( Config const& config );
|
||||||
|
|
||||||
|
@@ -34,6 +34,11 @@ namespace Matchers {
|
|||||||
mutable std::string m_cachedToString;
|
mutable std::string m_cachedToString;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename ObjectT>
|
template<typename ObjectT>
|
||||||
struct MatcherMethod {
|
struct MatcherMethod {
|
||||||
virtual bool match( ObjectT const& arg ) const = 0;
|
virtual bool match( ObjectT const& arg ) const = 0;
|
||||||
@@ -43,6 +48,10 @@ namespace Matchers {
|
|||||||
virtual bool match( PtrT* arg ) const = 0;
|
virtual bool match( PtrT* arg ) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
|
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
|
||||||
|
|
||||||
|
@@ -6,12 +6,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch_matchers_floating.h"
|
#include "catch_matchers_floating.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
#include "catch_to_string.hpp"
|
||||||
#include "catch_tostring.h"
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Matchers {
|
namespace Matchers {
|
||||||
@@ -80,15 +81,14 @@ namespace Matchers {
|
|||||||
namespace Floating {
|
namespace Floating {
|
||||||
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
|
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
|
||||||
:m_target{ target }, m_margin{ margin } {
|
:m_target{ target }, m_margin{ margin } {
|
||||||
if (m_margin < 0) {
|
CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
|
||||||
throw std::domain_error("Allowed margin difference has to be >= 0");
|
<< " Margin has to be non-negative.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||||
// But without the subtraction to allow for INFINITY in comparison
|
// But without the subtraction to allow for INFINITY in comparison
|
||||||
bool WithinAbsMatcher::match(double const& matchee) const {
|
bool WithinAbsMatcher::match(double const& matchee) const {
|
||||||
return (matchee + m_margin >= m_target) && (m_target + m_margin >= m_margin);
|
return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WithinAbsMatcher::describe() const {
|
std::string WithinAbsMatcher::describe() const {
|
||||||
@@ -98,11 +98,16 @@ namespace Floating {
|
|||||||
|
|
||||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
||||||
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||||
if (m_ulps < 0) {
|
CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
|
||||||
throw std::domain_error("Allowed ulp difference has to be >= 0");
|
<< " ULPs have to be non-negative.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
// Clang <3.5 reports on the default branch in the switch below
|
||||||
|
#pragma clang diagnostic ignored "-Wunreachable-code"
|
||||||
|
#endif
|
||||||
|
|
||||||
bool WithinUlpsMatcher::match(double const& matchee) const {
|
bool WithinUlpsMatcher::match(double const& matchee) const {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case FloatingPointKind::Float:
|
case FloatingPointKind::Float:
|
||||||
@@ -110,12 +115,16 @@ namespace Floating {
|
|||||||
case FloatingPointKind::Double:
|
case FloatingPointKind::Double:
|
||||||
return almostEqualUlps<double>(matchee, m_target, m_ulps);
|
return almostEqualUlps<double>(matchee, m_target, m_ulps);
|
||||||
default:
|
default:
|
||||||
throw std::domain_error("Unknown FloatingPointKind value");
|
CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string WithinUlpsMatcher::describe() const {
|
std::string WithinUlpsMatcher::describe() const {
|
||||||
return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
|
return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace Floating
|
}// namespace Floating
|
||||||
|
9
include/internal/catch_matchers_generic.cpp
Normal file
9
include/internal/catch_matchers_generic.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "catch_matchers_generic.hpp"
|
||||||
|
|
||||||
|
std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
|
||||||
|
if (desc.empty()) {
|
||||||
|
return "matches undescribed predicate";
|
||||||
|
} else {
|
||||||
|
return "matches predicate: \"" + desc + '"';
|
||||||
|
}
|
||||||
|
}
|
58
include/internal/catch_matchers_generic.hpp
Normal file
58
include/internal/catch_matchers_generic.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin Hořeňovský on 03/04/2017.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_common.h"
|
||||||
|
#include "catch_matchers.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Matchers {
|
||||||
|
namespace Generic {
|
||||||
|
|
||||||
|
namespace Detail {
|
||||||
|
std::string finalizeDescription(const std::string& desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class PredicateMatcher : public MatcherBase<T> {
|
||||||
|
std::function<bool(T const&)> m_predicate;
|
||||||
|
std::string m_description;
|
||||||
|
public:
|
||||||
|
|
||||||
|
PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
|
||||||
|
:m_predicate(std::move(elem)),
|
||||||
|
m_description(Detail::finalizeDescription(descr))
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool match( T const& item ) const override {
|
||||||
|
return m_predicate(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string describe() const override {
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Generic
|
||||||
|
|
||||||
|
// The following functions create the actual matcher objects.
|
||||||
|
// The user has to explicitly specify type to the function, because
|
||||||
|
// infering std::function<bool(T const&)> is hard (but possible) and
|
||||||
|
// requires a lot of TMP.
|
||||||
|
template<typename T>
|
||||||
|
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
|
||||||
|
return Generic::PredicateMatcher<T>(predicate, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Matchers
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
@@ -124,7 +124,7 @@ namespace Matchers {
|
|||||||
auto lfirst = m_target.begin(), llast = m_target.end();
|
auto lfirst = m_target.begin(), llast = m_target.end();
|
||||||
auto rfirst = vec.begin(), rlast = vec.end();
|
auto rfirst = vec.begin(), rlast = vec.end();
|
||||||
// Cut common prefix to optimize checking of permuted parts
|
// Cut common prefix to optimize checking of permuted parts
|
||||||
while (lfirst != llast && *lfirst != *rfirst) {
|
while (lfirst != llast && *lfirst == *rfirst) {
|
||||||
++lfirst; ++rfirst;
|
++lfirst; ++rfirst;
|
||||||
}
|
}
|
||||||
if (lfirst == llast) {
|
if (lfirst == llast) {
|
||||||
|
@@ -8,10 +8,13 @@
|
|||||||
|
|
||||||
#include "catch_message.h"
|
#include "catch_message.h"
|
||||||
#include "catch_interfaces_capture.h"
|
#include "catch_interfaces_capture.h"
|
||||||
|
#include "catch_uncaught_exceptions.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
MessageInfo::MessageInfo( std::string const& _macroName,
|
MessageInfo::MessageInfo( StringRef const& _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
ResultWas::OfType _type )
|
ResultWas::OfType _type )
|
||||||
: macroName( _macroName ),
|
: macroName( _macroName ),
|
||||||
@@ -34,7 +37,7 @@ namespace Catch {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Catch::MessageBuilder::MessageBuilder( std::string const& macroName,
|
Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
ResultWas::OfType type )
|
ResultWas::OfType type )
|
||||||
:m_info(macroName, lineInfo, type) {}
|
:m_info(macroName, lineInfo, type) {}
|
||||||
@@ -49,18 +52,41 @@ namespace Catch {
|
|||||||
getResultCapture().pushScopedMessage( m_info );
|
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() {
|
ScopedMessage::~ScopedMessage() {
|
||||||
if ( !std::uncaught_exception() ){
|
if ( !uncaught_exceptions() ){
|
||||||
getResultCapture().popScopedMessage(m_info);
|
getResultCapture().popScopedMessage(m_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
|
||||||
|
auto start = std::string::npos;
|
||||||
|
for( size_t pos = 0; pos <= names.size(); ++pos ) {
|
||||||
|
char c = names[pos];
|
||||||
|
if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) {
|
||||||
|
if( start != std::string::npos ) {
|
||||||
|
m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) );
|
||||||
|
m_messages.back().message = names.substr( start, pos-start) + " := ";
|
||||||
|
start = std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( c != '[' && c != ']' && start == std::string::npos )
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Capturer::~Capturer() {
|
||||||
|
if ( !uncaught_exceptions() ){
|
||||||
|
assert( m_captured == m_messages.size() );
|
||||||
|
for( size_t i = 0; i < m_captured; ++i )
|
||||||
|
m_resultCapture.popScopedMessage( m_messages[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Capturer::captureValue( size_t index, StringRef value ) {
|
||||||
|
assert( index < m_messages.size() );
|
||||||
|
m_messages[index].message += value;
|
||||||
|
m_resultCapture.pushScopedMessage( m_messages[index] );
|
||||||
|
m_captured++;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@@ -8,19 +8,23 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "catch_result_type.h"
|
#include "catch_result_type.h"
|
||||||
#include "catch_common.h"
|
#include "catch_common.h"
|
||||||
#include "catch_stream.h"
|
#include "catch_stream.h"
|
||||||
|
#include "catch_interfaces_capture.h"
|
||||||
|
#include "catch_tostring.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct MessageInfo {
|
struct MessageInfo {
|
||||||
MessageInfo( std::string const& _macroName,
|
MessageInfo( StringRef const& _macroName,
|
||||||
SourceLineInfo const& _lineInfo,
|
SourceLineInfo const& _lineInfo,
|
||||||
ResultWas::OfType _type );
|
ResultWas::OfType _type );
|
||||||
|
|
||||||
std::string macroName;
|
StringRef macroName;
|
||||||
std::string message;
|
std::string message;
|
||||||
SourceLineInfo lineInfo;
|
SourceLineInfo lineInfo;
|
||||||
ResultWas::OfType type;
|
ResultWas::OfType type;
|
||||||
@@ -44,7 +48,7 @@ namespace Catch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MessageBuilder : MessageStream {
|
struct MessageBuilder : MessageStream {
|
||||||
MessageBuilder( std::string const& macroName,
|
MessageBuilder( StringRef const& macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
ResultWas::OfType type );
|
ResultWas::OfType type );
|
||||||
|
|
||||||
@@ -65,6 +69,28 @@ namespace Catch {
|
|||||||
MessageInfo m_info;
|
MessageInfo m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Capturer {
|
||||||
|
std::vector<MessageInfo> m_messages;
|
||||||
|
IResultCapture& m_resultCapture = getResultCapture();
|
||||||
|
size_t m_captured = 0;
|
||||||
|
public:
|
||||||
|
Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
|
||||||
|
~Capturer();
|
||||||
|
|
||||||
|
void captureValue( size_t index, StringRef value );
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void captureValues( size_t index, T&& value ) {
|
||||||
|
captureValue( index, Catch::Detail::stringify( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Ts>
|
||||||
|
void captureValues( size_t index, T&& value, Ts&&... values ) {
|
||||||
|
captureValues( index, value );
|
||||||
|
captureValues( index+1, values... );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||||
|
@@ -93,7 +93,7 @@ namespace Catch {
|
|||||||
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
||||||
const char* className = class_getName( cls );
|
const char* className = class_getName( cls );
|
||||||
|
|
||||||
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) );
|
getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
|
||||||
noTestMethods++;
|
noTestMethods++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
138
include/internal/catch_output_redirect.cpp
Normal file
138
include/internal/catch_output_redirect.cpp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 28/04/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch_output_redirect.h"
|
||||||
|
#include "catch_enforce.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <io.h> //_dup and _dup2
|
||||||
|
#define dup _dup
|
||||||
|
#define dup2 _dup2
|
||||||
|
#define fileno _fileno
|
||||||
|
#else
|
||||||
|
#include <unistd.h> // dup and dup2
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
|
||||||
|
: m_originalStream( originalStream ),
|
||||||
|
m_redirectionStream( redirectionStream ),
|
||||||
|
m_prevBuf( m_originalStream.rdbuf() )
|
||||||
|
{
|
||||||
|
m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectedStream::~RedirectedStream() {
|
||||||
|
m_originalStream.rdbuf( m_prevBuf );
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
|
||||||
|
auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
|
||||||
|
|
||||||
|
RedirectedStdErr::RedirectedStdErr()
|
||||||
|
: m_cerr( Catch::cerr(), m_rss.get() ),
|
||||||
|
m_clog( Catch::clog(), m_rss.get() )
|
||||||
|
{}
|
||||||
|
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
TempFile::TempFile() {
|
||||||
|
if (tmpnam_s(m_buffer)) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not get a temp filename");
|
||||||
|
}
|
||||||
|
if (fopen_s(&m_file, m_buffer, "w")) {
|
||||||
|
char buffer[100];
|
||||||
|
if (strerror_s(buffer, errno)) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
|
||||||
|
}
|
||||||
|
CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
TempFile::TempFile() {
|
||||||
|
m_file = std::tmpfile();
|
||||||
|
if (!m_file) {
|
||||||
|
CATCH_RUNTIME_ERROR("Could not create a temp file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TempFile::~TempFile() {
|
||||||
|
// TBD: What to do about errors here?
|
||||||
|
std::fclose(m_file);
|
||||||
|
// We manually create the file on Windows only, on Linux
|
||||||
|
// it will be autodeleted
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
std::remove(m_buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FILE* TempFile::getFile() {
|
||||||
|
return m_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TempFile::getContents() {
|
||||||
|
std::stringstream sstr;
|
||||||
|
char buffer[100] = {};
|
||||||
|
std::rewind(m_file);
|
||||||
|
while (std::fgets(buffer, sizeof(buffer), m_file)) {
|
||||||
|
sstr << buffer;
|
||||||
|
}
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
|
||||||
|
m_originalStdout(dup(1)),
|
||||||
|
m_originalStderr(dup(2)),
|
||||||
|
m_stdoutDest(stdout_dest),
|
||||||
|
m_stderrDest(stderr_dest) {
|
||||||
|
dup2(fileno(m_stdoutFile.getFile()), 1);
|
||||||
|
dup2(fileno(m_stderrFile.getFile()), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputRedirect::~OutputRedirect() {
|
||||||
|
Catch::cout() << std::flush;
|
||||||
|
fflush(stdout);
|
||||||
|
// Since we support overriding these streams, we flush cerr
|
||||||
|
// even though std::cerr is unbuffered
|
||||||
|
Catch::cerr() << std::flush;
|
||||||
|
Catch::clog() << std::flush;
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
dup2(m_originalStdout, 1);
|
||||||
|
dup2(m_originalStderr, 2);
|
||||||
|
|
||||||
|
m_stdoutDest += m_stdoutFile.getContents();
|
||||||
|
m_stderrDest += m_stderrFile.getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CATCH_CONFIG_NEW_CAPTURE
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#undef dup
|
||||||
|
#undef dup2
|
||||||
|
#undef fileno
|
||||||
|
#endif
|
||||||
|
#endif
|
101
include/internal/catch_output_redirect.h
Normal file
101
include/internal/catch_output_redirect.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 28/04/2018.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
||||||
|
#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
||||||
|
|
||||||
|
#include "catch_platform.h"
|
||||||
|
#include "catch_stream.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
class RedirectedStream {
|
||||||
|
std::ostream& m_originalStream;
|
||||||
|
std::ostream& m_redirectionStream;
|
||||||
|
std::streambuf* m_prevBuf;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
|
||||||
|
~RedirectedStream();
|
||||||
|
};
|
||||||
|
|
||||||
|
class RedirectedStdOut {
|
||||||
|
ReusableStringStream m_rss;
|
||||||
|
RedirectedStream m_cout;
|
||||||
|
public:
|
||||||
|
RedirectedStdOut();
|
||||||
|
auto str() const -> std::string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// StdErr has two constituent streams in C++, std::cerr and std::clog
|
||||||
|
// This means that we need to redirect 2 streams into 1 to keep proper
|
||||||
|
// order of writes
|
||||||
|
class RedirectedStdErr {
|
||||||
|
ReusableStringStream m_rss;
|
||||||
|
RedirectedStream m_cerr;
|
||||||
|
RedirectedStream m_clog;
|
||||||
|
public:
|
||||||
|
RedirectedStdErr();
|
||||||
|
auto str() const -> std::string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
||||||
|
|
||||||
|
// Windows's implementation of std::tmpfile is terrible (it tries
|
||||||
|
// to create a file inside system folder, thus requiring elevated
|
||||||
|
// privileges for the binary), so we have to use tmpnam(_s) and
|
||||||
|
// create the file ourselves there.
|
||||||
|
class TempFile {
|
||||||
|
public:
|
||||||
|
TempFile(TempFile const&) = delete;
|
||||||
|
TempFile& operator=(TempFile const&) = delete;
|
||||||
|
TempFile(TempFile&&) = delete;
|
||||||
|
TempFile& operator=(TempFile&&) = delete;
|
||||||
|
|
||||||
|
TempFile();
|
||||||
|
~TempFile();
|
||||||
|
|
||||||
|
std::FILE* getFile();
|
||||||
|
std::string getContents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::FILE* m_file = nullptr;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
char m_buffer[L_tmpnam] = { 0 };
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OutputRedirect {
|
||||||
|
public:
|
||||||
|
OutputRedirect(OutputRedirect const&) = delete;
|
||||||
|
OutputRedirect& operator=(OutputRedirect const&) = delete;
|
||||||
|
OutputRedirect(OutputRedirect&&) = delete;
|
||||||
|
OutputRedirect& operator=(OutputRedirect&&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
|
||||||
|
~OutputRedirect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_originalStdout = -1;
|
||||||
|
int m_originalStderr = -1;
|
||||||
|
TempFile m_stdoutFile;
|
||||||
|
TempFile m_stderrFile;
|
||||||
|
std::string& m_stdoutDest;
|
||||||
|
std::string& m_stderrDest;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
|
@@ -20,7 +20,7 @@
|
|||||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
# define CATCH_PLATFORM_LINUX
|
# define CATCH_PLATFORM_LINUX
|
||||||
|
|
||||||
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
# define CATCH_PLATFORM_WINDOWS
|
# define CATCH_PLATFORM_WINDOWS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user