mirror of
https://github.com/catchorg/Catch2.git
synced 2025-09-12 00:15:39 +02:00
Compare commits
322 Commits
v2.0.0-dev
...
v2.2.2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
cd76f5730c | ||
![]() |
f5910f38ef | ||
![]() |
421ab16062 | ||
![]() |
161dd4ed24 | ||
![]() |
13ea4225e7 | ||
![]() |
2c43620d9b | ||
![]() |
8be1df243e | ||
![]() |
32eb90b9bd | ||
![]() |
702cfdaf6e | ||
![]() |
e41e8e8384 | ||
![]() |
af3f2499bc | ||
![]() |
c3a1143d23 | ||
![]() |
f580591bf8 | ||
![]() |
fc88313d45 | ||
![]() |
3979845d5f | ||
![]() |
88d2bac624 | ||
![]() |
ed33e9787e | ||
![]() |
f466d9a1ed | ||
![]() |
a7a9ee5552 | ||
![]() |
0cf05d54a6 | ||
![]() |
11887fbbab | ||
![]() |
347be87126 | ||
![]() |
4da655c1b0 | ||
![]() |
c4d1aa9033 | ||
![]() |
495d2458e0 | ||
![]() |
3035120dc7 | ||
![]() |
584e04d480 | ||
![]() |
673dcc16a9 | ||
![]() |
0c122c135d | ||
![]() |
d19b7292b3 | ||
![]() |
5e063616df | ||
![]() |
aa9d635014 | ||
![]() |
7c5a21fb7d | ||
![]() |
533cdc6bc1 | ||
![]() |
51e281a684 | ||
![]() |
24851dff99 | ||
![]() |
a4fd96fbaa | ||
![]() |
12c57cedda | ||
![]() |
45a465713e | ||
![]() |
dfa817ae73 | ||
![]() |
57c346a46d | ||
![]() |
67f734c799 | ||
![]() |
b76e80ed3d | ||
![]() |
a3632facf3 | ||
![]() |
7d0db6b8e9 | ||
![]() |
8a7493cd88 | ||
![]() |
b5a5d9a6f8 | ||
![]() |
8c32d0b644 | ||
![]() |
28d1955ea8 | ||
![]() |
20211a33e6 | ||
![]() |
e3941a9ad2 | ||
![]() |
da86ddc620 | ||
![]() |
4b614ee1d1 | ||
![]() |
5461242ffe | ||
![]() |
e344984a1b | ||
![]() |
db44964e27 | ||
![]() |
2800adba25 | ||
![]() |
ae1547e202 | ||
![]() |
73a1623eaf | ||
![]() |
c411c131cb | ||
![]() |
091595780e | ||
![]() |
f417995afc | ||
![]() |
9329d97a43 | ||
![]() |
8141a7836f | ||
![]() |
5323202652 | ||
![]() |
f052762c11 | ||
![]() |
401ad7a189 | ||
![]() |
63c097a077 | ||
![]() |
87c125ecb8 | ||
![]() |
3b965aa501 | ||
![]() |
e54dcdac8b | ||
![]() |
e4a898eaaa | ||
![]() |
c39109dce3 | ||
![]() |
a8a1c379c0 | ||
![]() |
e08a4ed99e | ||
![]() |
fcba30569c | ||
![]() |
4353614df7 | ||
![]() |
f36817ef83 | ||
![]() |
812bf21740 | ||
![]() |
baf3d2f360 | ||
![]() |
b083b04126 | ||
![]() |
505d2f8977 | ||
![]() |
f18366150e | ||
![]() |
fe725648a7 | ||
![]() |
b0c379f621 | ||
![]() |
c443afcca0 | ||
![]() |
502da4b38d | ||
![]() |
8da845810d | ||
![]() |
61e838edf2 | ||
![]() |
516dbc83bc | ||
![]() |
b9339333df | ||
![]() |
61e29b5630 | ||
![]() |
54fb6f2d23 | ||
![]() |
a077ebae4c | ||
![]() |
2bbba4f544 | ||
![]() |
29cdd6c526 | ||
![]() |
dfb7217613 | ||
![]() |
f6ae45122b | ||
![]() |
d5d2bee4c5 | ||
![]() |
85de0727d4 | ||
![]() |
4ecb2e112e | ||
![]() |
97a8640cbf | ||
![]() |
033e078320 | ||
![]() |
9796a77a37 | ||
![]() |
98d4c49d1c | ||
![]() |
a096e4b3f2 | ||
![]() |
4b3730de8a | ||
![]() |
6acdacfde0 | ||
![]() |
a3cba7a0d5 | ||
![]() |
9796846ad0 | ||
![]() |
74d3dfd4cc | ||
![]() |
e34754e433 | ||
![]() |
55b71bebf1 | ||
![]() |
b0857e846f | ||
![]() |
a06b6dc3ea | ||
![]() |
0adb04807a | ||
![]() |
f80f28e09a | ||
![]() |
484eee973c | ||
![]() |
d09fe4459d | ||
![]() |
e484236825 | ||
![]() |
e7c23b73da | ||
![]() |
3537b7858f | ||
![]() |
b74d4ca96d | ||
![]() |
8dbaac61ff | ||
![]() |
a0dbc62955 | ||
![]() |
cecee3459a | ||
![]() |
030321e3e0 | ||
![]() |
5f961af70e | ||
![]() |
0b1f1b1003 | ||
![]() |
24e6d5fa33 | ||
![]() |
13370bddf2 | ||
![]() |
36f02d76d6 | ||
![]() |
07ac9b92e4 | ||
![]() |
0d3fc59f6d | ||
![]() |
56e1075613 | ||
![]() |
868e125d49 | ||
![]() |
c9cdb9a48f | ||
![]() |
5fd1d7174c | ||
![]() |
3a4c765030 | ||
![]() |
a20b286999 | ||
![]() |
e28763ad05 | ||
![]() |
b2dd48f0c0 | ||
![]() |
7a562d39b2 | ||
![]() |
fa9c4207f1 | ||
![]() |
4f9123dc20 | ||
![]() |
19ab2117c5 | ||
![]() |
4acf112c19 | ||
![]() |
53f6d3fc8e | ||
![]() |
cf76a795cc | ||
![]() |
811f4d13d7 | ||
![]() |
7423a481eb | ||
![]() |
46c7c9d3a0 | ||
![]() |
b119ebdde1 | ||
![]() |
1c43fb64c1 | ||
![]() |
8b40c26434 | ||
![]() |
fe05062f9e | ||
![]() |
31cc62e6b7 | ||
![]() |
a49e6fdc27 | ||
![]() |
2d91035404 | ||
![]() |
accf9859b4 | ||
![]() |
22ac9d2184 | ||
![]() |
00af677577 | ||
![]() |
ae21020640 | ||
![]() |
11f716f28d | ||
![]() |
c3ddd4a7e2 | ||
![]() |
c43ce85416 | ||
![]() |
4220f2eef2 | ||
![]() |
c1a91caf00 | ||
![]() |
96c5de678d | ||
![]() |
e68485e196 | ||
![]() |
88e912b4d1 | ||
![]() |
44244713f1 | ||
![]() |
eea9e1efd7 | ||
![]() |
2a3606f8e3 | ||
![]() |
a6cf19abff | ||
![]() |
601b2888ec | ||
![]() |
3049445d78 | ||
![]() |
c672512979 | ||
![]() |
57b4e0b64c | ||
![]() |
06586b7180 | ||
![]() |
93b3d2cb8f | ||
![]() |
a90473df28 | ||
![]() |
75a77b6f8c | ||
![]() |
5af918eefd | ||
![]() |
c9d9699ca8 | ||
![]() |
296955c437 | ||
![]() |
664cbf702c | ||
![]() |
fb6700df54 | ||
![]() |
05b1ca2884 | ||
![]() |
da6c2a6914 | ||
![]() |
c2b7bd15c0 | ||
![]() |
ba6845a865 | ||
![]() |
2eb93f47f7 | ||
![]() |
276393e4e5 | ||
![]() |
c7d9f02d5b | ||
![]() |
9c07718b5f | ||
![]() |
5ca44b6872 | ||
![]() |
a04bd6d436 | ||
![]() |
784f6dfb34 | ||
![]() |
7818e2666d | ||
![]() |
cd30dd1a70 | ||
![]() |
8e8c0c1675 | ||
![]() |
b6e7c9bd7a | ||
![]() |
180d9242f5 | ||
![]() |
b7bd52cc98 | ||
![]() |
b07a2bdf87 | ||
![]() |
c03e8fce92 | ||
![]() |
27640a5a96 | ||
![]() |
dd3867bbcd | ||
![]() |
387f8d254d | ||
![]() |
c65eccd68e | ||
![]() |
61c5675c11 | ||
![]() |
70e4af9d44 | ||
![]() |
8f41bdb92d | ||
![]() |
7fa5d9ca94 | ||
![]() |
feaf355489 | ||
![]() |
2ce6c74f8f | ||
![]() |
9688891868 | ||
![]() |
4f21bb72ff | ||
![]() |
b435e0d7c7 | ||
![]() |
ba0a09fd9e |
13
.gitattributes
vendored
13
.gitattributes
vendored
@@ -8,4 +8,15 @@
|
||||
*.hpp text
|
||||
|
||||
# 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
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@@ -24,6 +24,6 @@ DerivedData
|
||||
*.xccheckout
|
||||
Build
|
||||
.idea
|
||||
cmake-build-debug
|
||||
cmake-build-release
|
||||
.vs
|
||||
.vs
|
||||
cmake-build-*
|
||||
benchmark-dir
|
||||
|
268
.travis.yml
268
.travis.yml
@@ -1,208 +1,218 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /dev-appveyor.*/
|
||||
|
||||
common_sources: &all_sources
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
- llvm-toolchain-trusty-3.9
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- llvm-toolchain-trusty-5.0
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# 1/ Linux Clang Builds
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang35
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.5']
|
||||
env: COMPILER='clang++-3.5' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.5'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang35
|
||||
env: COMPILER='clang++-3.5' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang36
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.6']
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.6'
|
||||
|
||||
# Clang 3.7 is intentionally skipped as we cannot get it easily on
|
||||
# TravisCI container
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang36
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang37
|
||||
addons:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.7']
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Release'
|
||||
sources: *all_sources
|
||||
packages: ['lcov', 'clang-3.8']
|
||||
env: COMPILER='clang++-3.8'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang37
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Debug'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.9']
|
||||
env: COMPILER='clang++-3.9'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.8']
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-4.0']
|
||||
env: COMPILER='clang++-4.0'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-5.0']
|
||||
env: COMPILER='clang++-5.0'
|
||||
|
||||
# 2/ Linux GCC Builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc48
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['g++-4.8']
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-4.8'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc48
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc49
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['g++-4.9']
|
||||
env: COMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-4.9'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc49
|
||||
env: COMPILER='g++-4.9' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc5
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['g++-5']
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc5
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Debug'
|
||||
|
||||
env: COMPILER='g++-5'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
sources: *all_sources
|
||||
packages: ['g++-6']
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-6'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Debug'
|
||||
addons: &gcc7
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['g++-7']
|
||||
env: COMPILER='g++-7'
|
||||
|
||||
# 3a/ Linux C++11 GCC builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc48
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Release' CPP11=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc48
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Debug' CPP11=1
|
||||
|
||||
# 3b/ Linux C++11 Clang builds
|
||||
# 3b/ Linux C++14 Clang builds
|
||||
# Note that we need newer libstdc++ for C++14 support
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP11=1
|
||||
addons:
|
||||
apt:
|
||||
packages: ['clang-3.8', 'libstdc++-6-dev']
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
env: COMPILER='clang++-3.8' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP11=1
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-3.9', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-3.9' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-4.0', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-4.0' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['clang-5.0', 'libstdc++-6-dev']
|
||||
env: COMPILER='clang++-5.0' CPP14=1
|
||||
|
||||
|
||||
# 4a/ Linux C++14 GCC builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Release' CPP14=1
|
||||
env: COMPILER='g++-6' CPP14=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Debug' CPP14=1
|
||||
|
||||
# # 4b/ Linux C++14 Clang builds
|
||||
# - os: linux
|
||||
# compiler: clang
|
||||
# addons: *clang38
|
||||
# env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP14=1
|
||||
#
|
||||
# - os: linux
|
||||
# compiler: clang
|
||||
# addons: *clang38
|
||||
# env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP14=1
|
||||
|
||||
addons: *gcc7
|
||||
env: COMPILER='g++-7' CPP14=1
|
||||
|
||||
# 5/ OSX Clang Builds
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode9
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug' USE_CPP11=1
|
||||
env: COMPILER='clang++'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release' USE_CPP11=1
|
||||
env: COMPILER='clang++' CPP14=1
|
||||
|
||||
# 6/ Special builds -- examples, coverage, valgrind, etc.
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['lcov', 'g++-7']
|
||||
env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
packages: ['clang-3.8', 'lcov']
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages: ['valgrind', 'lcov', 'g++-7']
|
||||
env: COMPILER='g++-7' CPP14=1 VALGRIND=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug' USE_CPP14=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release' USE_CPP14=1
|
||||
|
||||
env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1
|
||||
|
||||
install:
|
||||
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
|
||||
@@ -213,15 +223,33 @@ install:
|
||||
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
which cmake || brew install cmake
|
||||
which cmake || brew install cmake;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- export CXX=${COMPILER}
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -Wdev -DUSE_CPP11=${CPP11} -DUSE_CPP14=${CPP14}
|
||||
- cd Build
|
||||
# Regenerate single header file, so it is tested in the examples...
|
||||
- python scripts/generateSingleHeader.py
|
||||
|
||||
# Use Debug builds for running Valgrind and building examples
|
||||
- cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE}
|
||||
# Don't bother with release build for coverage build
|
||||
- cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
|
||||
|
||||
|
||||
script:
|
||||
- cd Build-Debug
|
||||
- make -j 2
|
||||
- ctest -V -j 2
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||
# Coverage collection does not work for OS X atm
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
|
||||
make gcov
|
||||
make lcov
|
||||
bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
|
||||
fi
|
||||
- # Go to release build
|
||||
- cd ../Build-Release
|
||||
- make -j 2
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
|
||||
|
157
CMake/FindGcov.cmake
Normal file
157
CMake/FindGcov.cmake
Normal file
@@ -0,0 +1,157 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
# Search for gcov binary.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Gcov evaluation is dependend on the used compiler. Check gcov support for
|
||||
# each compiler that is used. If gcov binary was already found for this
|
||||
# compiler, do not try to find it again.
|
||||
if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN)
|
||||
get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH)
|
||||
|
||||
if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU")
|
||||
# Some distributions like OSX (homebrew) ship gcov with the compiler
|
||||
# version appended as gcov-x. To find this binary we'll build the
|
||||
# suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+" GCC_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov
|
||||
HINTS ${COMPILER_PATH})
|
||||
|
||||
elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang")
|
||||
# Some distributions like Debian ship llvm-cov with the compiler
|
||||
# version appended as llvm-cov-x.y. To find this binary we'll build
|
||||
# the suggested binary name with the compiler version.
|
||||
string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION
|
||||
"${CMAKE_${LANG}_COMPILER_VERSION}")
|
||||
|
||||
# llvm-cov prior version 3.5 seems to be not working with coverage
|
||||
# evaluation tools, but these versions are compatible with the gcc
|
||||
# gcov tool.
|
||||
if(LLVM_VERSION VERSION_GREATER 3.4)
|
||||
find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}"
|
||||
"llvm-cov" HINTS ${COMPILER_PATH})
|
||||
mark_as_advanced(LLVM_COV_BIN)
|
||||
|
||||
if (LLVM_COV_BIN)
|
||||
find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS
|
||||
${CMAKE_MODULE_PATH})
|
||||
if (LLVM_COV_WRAPPER)
|
||||
set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "")
|
||||
|
||||
# set additional parameters
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV
|
||||
"LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING
|
||||
"Environment variables for llvm-cov-wrapper.")
|
||||
mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT GCOV_BIN)
|
||||
# Fall back to gcov binary if llvm-cov was not found or is
|
||||
# incompatible. This is the default on OSX, but may crash on
|
||||
# recent Linux versions.
|
||||
find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
if (GCOV_BIN)
|
||||
set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING
|
||||
"${LANG} gcov binary.")
|
||||
|
||||
if (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Found gcov evaluation for "
|
||||
"${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}")
|
||||
endif()
|
||||
|
||||
unset(GCOV_BIN CACHE)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target for all gcov targets. This target could be used to
|
||||
# generate the gcov files for the whole project instead of calling <TARGET>-gcov
|
||||
# for each target.
|
||||
if (NOT TARGET gcov)
|
||||
add_custom_target(gcov)
|
||||
endif (NOT TARGET gcov)
|
||||
|
||||
|
||||
|
||||
# This function will add gcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# Gcov on any source file of <TNAME> once and store the gcov file in the same
|
||||
# directory.
|
||||
function (add_gcov_target TNAME)
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(BUFFER "")
|
||||
foreach(FILE ${SOURCES})
|
||||
get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH)
|
||||
|
||||
# call gcov
|
||||
add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov
|
||||
COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null
|
||||
DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno
|
||||
WORKING_DIRECTORY ${FILE_PATH}
|
||||
)
|
||||
|
||||
list(APPEND BUFFER ${TDIR}/${FILE}.gcov)
|
||||
endforeach()
|
||||
|
||||
|
||||
# add target for gcov evaluation of <TNAME>
|
||||
add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER})
|
||||
|
||||
# add evaluation target to the global gcov target.
|
||||
add_dependencies(gcov ${TNAME}-gcov)
|
||||
endfunction (add_gcov_target)
|
354
CMake/FindLcov.cmake
Normal file
354
CMake/FindLcov.cmake
Normal file
@@ -0,0 +1,354 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# configuration
|
||||
set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data")
|
||||
set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init")
|
||||
set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture")
|
||||
set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html")
|
||||
|
||||
|
||||
|
||||
|
||||
# Search for Gcov which is used by Lcov.
|
||||
find_package(Gcov)
|
||||
|
||||
|
||||
|
||||
|
||||
# This function will add lcov evaluation for target <TNAME>. Only sources of
|
||||
# this target will be evaluated and no dependencies will be added. It will call
|
||||
# geninfo on any source file of <TNAME> once and store the info file in the same
|
||||
# directory.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_lcov_target TNAME)
|
||||
if (LCOV_FOUND)
|
||||
# capture initial coverage data
|
||||
lcov_capture_initial_tgt(${TNAME})
|
||||
|
||||
# capture coverage data after execution
|
||||
lcov_capture_tgt(${TNAME})
|
||||
endif ()
|
||||
endfunction (add_lcov_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# include required Modules
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Search for required lcov binaries.
|
||||
find_program(LCOV_BIN lcov)
|
||||
find_program(GENINFO_BIN geninfo)
|
||||
find_program(GENHTML_BIN genhtml)
|
||||
find_package_handle_standard_args(lcov
|
||||
REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN
|
||||
)
|
||||
|
||||
# enable genhtml C++ demangeling, if c++filt is found.
|
||||
set(GENHTML_CPPFILT_FLAG "")
|
||||
find_program(CPPFILT_BIN c++filt)
|
||||
if (NOT CPPFILT_BIN STREQUAL "")
|
||||
set(GENHTML_CPPFILT_FLAG "--demangle-cpp")
|
||||
endif (NOT CPPFILT_BIN STREQUAL "")
|
||||
|
||||
# enable no-external flag for lcov, if available.
|
||||
if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG)
|
||||
set(FLAG "")
|
||||
execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP)
|
||||
string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}")
|
||||
if (GENINFO_RES)
|
||||
set(FLAG "--no-external")
|
||||
endif ()
|
||||
|
||||
set(GENINFO_EXTERN_FLAG "${FLAG}"
|
||||
CACHE STRING "Geninfo flag to exclude system sources.")
|
||||
endif ()
|
||||
|
||||
# If Lcov was not found, exit module now.
|
||||
if (NOT LCOV_FOUND)
|
||||
return()
|
||||
endif (NOT LCOV_FOUND)
|
||||
|
||||
|
||||
|
||||
|
||||
# Create directories to be used.
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT})
|
||||
file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE})
|
||||
|
||||
set(LCOV_REMOVE_PATTERNS "")
|
||||
|
||||
# This function will merge lcov files to a single target file. Additional lcov
|
||||
# flags may be set with setting LCOV_EXTRA_FLAGS before calling this function.
|
||||
function (lcov_merge_files OUTFILE ...)
|
||||
# Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files.
|
||||
list(REMOVE_AT ARGV 0)
|
||||
|
||||
# Generate merged file.
|
||||
string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}")
|
||||
add_custom_command(OUTPUT "${OUTFILE}.raw"
|
||||
COMMAND cat ${ARGV} > ${OUTFILE}.raw
|
||||
DEPENDS ${ARGV}
|
||||
COMMENT "Generating ${FILE_REL}"
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT "${OUTFILE}"
|
||||
COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE}
|
||||
--base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS}
|
||||
COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS}
|
||||
--output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS}
|
||||
DEPENDS ${OUTFILE}.raw
|
||||
COMMENT "Post-processing ${FILE_REL}"
|
||||
)
|
||||
endfunction ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate initial coverage reports for all targets.
|
||||
# This target will be used to generate the global initial info file, which is
|
||||
# used to gather even empty report data.
|
||||
if (NOT TARGET lcov-capture-init)
|
||||
add_custom_target(lcov-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture-init)
|
||||
|
||||
|
||||
# This function will add initial capture of coverage data for target <TNAME>,
|
||||
# which is needed to get also data for objects, which were not loaded at
|
||||
# execution time. It will call geninfo for every source file of <TNAME> once and
|
||||
# store the info file in the same directory.
|
||||
function (lcov_capture_initial_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# generate empty coverage files
|
||||
set(OUTFILE "${TDIR}/${FILE}.info.init")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN}
|
||||
--quiet --base-directory ${PROJECT_SOURCE_DIR} --initial
|
||||
--gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE}
|
||||
${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno
|
||||
DEPENDS ${TNAME}
|
||||
COMMENT "Capturing initial coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info")
|
||||
set(LCOV_EXTRA_FLAGS "--initial")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-geninfo target
|
||||
add_dependencies(lcov-capture-init ${TNAME}-capture-init)
|
||||
set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}"
|
||||
"${OUTFILE}" CACHE INTERNAL ""
|
||||
)
|
||||
endfunction (lcov_capture_initial_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture_initial)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES})
|
||||
add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE}
|
||||
lcov-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_initial)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate coverage reports for all targets. This
|
||||
# target will be used to generate the global info file.
|
||||
if (NOT TARGET lcov-capture)
|
||||
add_custom_target(lcov-capture)
|
||||
set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "")
|
||||
endif (NOT TARGET lcov-capture)
|
||||
|
||||
|
||||
# This function will add capture of coverage data for target <TNAME>, which is
|
||||
# needed to get also data for objects, which were not loaded at execution time.
|
||||
# It will call geninfo for every source file of <TNAME> once and store the info
|
||||
# file in the same directory.
|
||||
function (lcov_capture_tgt TNAME)
|
||||
# We don't have to check, if the target has support for coverage, thus this
|
||||
# will be checked by add_coverage_target in Findcoverage.cmake. Instead we
|
||||
# have to determine which gcov binary to use.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(SOURCES "")
|
||||
set(TCOMPILER "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
if (NOT "${FILE}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (NOT "${LANG}" STREQUAL "")
|
||||
list(APPEND SOURCES "${FILE}")
|
||||
set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# If no gcov binary was found, coverage data can't be evaluated.
|
||||
if (NOT GCOV_${TCOMPILER}_BIN)
|
||||
message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}")
|
||||
set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}")
|
||||
|
||||
|
||||
set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir)
|
||||
set(GENINFO_FILES "")
|
||||
foreach(FILE ${SOURCES})
|
||||
# Generate coverage files. If no .gcda file was generated during
|
||||
# execution, the empty coverage file will be used instead.
|
||||
set(OUTFILE "${TDIR}/${FILE}.info")
|
||||
list(APPEND GENINFO_FILES ${OUTFILE})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTFILE}
|
||||
COMMAND test -f "${TDIR}/${FILE}.gcda"
|
||||
&& ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory
|
||||
${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN}
|
||||
--output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG}
|
||||
${TDIR}/${FILE}.gcda
|
||||
|| cp ${OUTFILE}.init ${OUTFILE}
|
||||
DEPENDS ${TNAME} ${TNAME}-capture-init
|
||||
COMMENT "Capturing coverage data for ${FILE}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Concatenate all files generated by geninfo to a single file per target.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info")
|
||||
lcov_merge_files("${OUTFILE}" ${GENINFO_FILES})
|
||||
add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE})
|
||||
|
||||
# add geninfo file generation to global lcov-capture target
|
||||
add_dependencies(lcov-capture ${TNAME}-geninfo)
|
||||
set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL
|
||||
""
|
||||
)
|
||||
|
||||
# Add target for generating html output for this target only.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME})
|
||||
add_custom_target(${TNAME}-genhtml
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR}
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info
|
||||
--output-directory ${LCOV_HTML_PATH}/${TNAME}
|
||||
--title "${CMAKE_PROJECT_NAME} - target ${TNAME}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init
|
||||
)
|
||||
endfunction (lcov_capture_tgt)
|
||||
|
||||
|
||||
# This function will generate the global info file for all targets. It has to be
|
||||
# called after all other CMake functions in the root CMakeLists.txt file, to get
|
||||
# a full list of all targets that generate coverage data.
|
||||
function (lcov_capture)
|
||||
# Skip this function (and do not create the following targets), if there are
|
||||
# no input files.
|
||||
if ("${LCOV_CAPTURE_FILES}" STREQUAL "")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
# Add a new target to merge the files of all targets.
|
||||
set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info")
|
||||
lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES})
|
||||
add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture)
|
||||
|
||||
# Add a new global target for all lcov targets. This target could be used to
|
||||
# generate the lcov html output for the whole project instead of calling
|
||||
# <TARGET>-geninfo and <TARGET>-genhtml for each target. It will also be
|
||||
# used to generate a html site for all project data together instead of one
|
||||
# for each target.
|
||||
if (NOT TARGET lcov)
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets)
|
||||
add_custom_target(lcov
|
||||
COMMAND ${GENHTML_BIN} --quiet --sort
|
||||
--baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info
|
||||
--output-directory ${LCOV_HTML_PATH}/all_targets
|
||||
--title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}"
|
||||
${GENHTML_CPPFILT_FLAG} ${OUTFILE}
|
||||
DEPENDS lcov-geninfo-init lcov-geninfo
|
||||
)
|
||||
endif ()
|
||||
endfunction (lcov_capture)
|
||||
|
||||
|
||||
|
||||
|
||||
# Add a new global target to generate the lcov html report for the whole project
|
||||
# instead of calling <TARGET>-genhtml for each target (to create an own report
|
||||
# for each target). Instead of the lcov target it does not require geninfo for
|
||||
# all targets, so you have to call <TARGET>-geninfo to generate the info files
|
||||
# the targets you'd like to have in your report or lcov-geninfo for generating
|
||||
# info files for all targets before calling lcov-genhtml.
|
||||
file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets)
|
||||
if (NOT TARGET lcov-genhtml)
|
||||
add_custom_target(lcov-genhtml
|
||||
COMMAND ${GENHTML_BIN}
|
||||
--quiet
|
||||
--output-directory ${LCOV_HTML_PATH}/selected_targets
|
||||
--title \"${CMAKE_PROJECT_NAME} - targets `find
|
||||
${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\" -exec basename {} .info \\\;`\"
|
||||
--prefix ${PROJECT_SOURCE_DIR}
|
||||
--sort
|
||||
${GENHTML_CPPFILT_FLAG}
|
||||
`find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name
|
||||
\"all_targets.info\"`
|
||||
)
|
||||
endif (NOT TARGET lcov-genhtml)
|
258
CMake/Findcodecov.cmake
Normal file
258
CMake/Findcodecov.cmake
Normal file
@@ -0,0 +1,258 @@
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
|
||||
# Add an option to choose, if coverage should be enabled or not. If enabled
|
||||
# marked targets will be build with coverage support and appropriate targets
|
||||
# will be added. If disabled coverage will be ignored for *ALL* targets.
|
||||
option(ENABLE_COVERAGE "Enable coverage build." OFF)
|
||||
|
||||
set(COVERAGE_FLAG_CANDIDATES
|
||||
# gcc and clang
|
||||
"-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
|
||||
# gcc and clang fallback
|
||||
"-O0 -g --coverage"
|
||||
)
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation. If coverage is disabled or not supported, this function will
|
||||
# simply do nothing.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (add_coverage TNAME)
|
||||
# only add coverage for target, if coverage is support and enabled.
|
||||
if (ENABLE_COVERAGE)
|
||||
foreach (TNAME ${ARGV})
|
||||
add_coverage_target(${TNAME})
|
||||
endforeach ()
|
||||
endif ()
|
||||
endfunction (add_coverage)
|
||||
|
||||
|
||||
# Add global target to gather coverage information after all targets have been
|
||||
# added. Other evaluation functions could be added here, after checks for the
|
||||
# specific module have been passed.
|
||||
#
|
||||
# Note: This function is only a wrapper to define this function always, even if
|
||||
# coverage is not supported by the compiler or disabled. This function must
|
||||
# be defined here, because the module will be exited, if there is no coverage
|
||||
# support by the compiler or it is disabled by the user.
|
||||
function (coverage_evaluate)
|
||||
# add lcov evaluation
|
||||
if (LCOV_FOUND)
|
||||
lcov_capture_initial()
|
||||
lcov_capture()
|
||||
endif (LCOV_FOUND)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Exit this module, if coverage is disabled. add_coverage is defined before this
|
||||
# return, so this module can be exited now safely without breaking any build-
|
||||
# scripts.
|
||||
if (NOT ENABLE_COVERAGE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
|
||||
|
||||
# Find the reuired flags foreach language.
|
||||
set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET})
|
||||
set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY})
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
# Coverage flags are not dependend on language, but the used compiler. So
|
||||
# instead of searching flags foreach language, search flags foreach compiler
|
||||
# used.
|
||||
set(COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
if (NOT COVERAGE_${COMPILER}_FLAGS)
|
||||
foreach (FLAG ${COVERAGE_FLAG_CANDIDATES})
|
||||
if(NOT CMAKE_REQUIRED_QUIET)
|
||||
message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${FLAG}")
|
||||
unset(COVERAGE_FLAG_DETECTED CACHE)
|
||||
|
||||
if (${LANG} STREQUAL "C")
|
||||
include(CheckCCompilerFlag)
|
||||
check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "CXX")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED)
|
||||
|
||||
elseif (${LANG} STREQUAL "Fortran")
|
||||
# CheckFortranCompilerFlag was introduced in CMake 3.x. To be
|
||||
# compatible with older Cmake versions, we will check if this
|
||||
# module is present before we use it. Otherwise we will define
|
||||
# Fortran coverage support as not available.
|
||||
include(CheckFortranCompilerFlag OPTIONAL
|
||||
RESULT_VARIABLE INCLUDED)
|
||||
if (INCLUDED)
|
||||
check_fortran_compiler_flag("${FLAG}"
|
||||
COVERAGE_FLAG_DETECTED)
|
||||
elseif (NOT CMAKE_REQUIRED_QUIET)
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED")
|
||||
message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed"
|
||||
" (Check not supported)")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (COVERAGE_FLAG_DETECTED)
|
||||
set(COVERAGE_${COMPILER}_FLAGS "${FLAG}"
|
||||
CACHE STRING "${COMPILER} flags for code coverage.")
|
||||
mark_as_advanced(COVERAGE_${COMPILER}_FLAGS)
|
||||
break()
|
||||
else ()
|
||||
message(WARNING "Code coverage is not available for ${COMPILER}"
|
||||
" compiler. Targets using this compiler will be "
|
||||
"compiled without it.")
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
|
||||
|
||||
|
||||
|
||||
|
||||
# Helper function to get the language of a source file.
|
||||
function (codecov_lang_of_source FILE RETURN_VAR)
|
||||
get_filename_component(FILE_EXT "${FILE}" EXT)
|
||||
string(TOLOWER "${FILE_EXT}" FILE_EXT)
|
||||
string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT)
|
||||
|
||||
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
foreach (LANG ${ENABLED_LANGUAGES})
|
||||
list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP)
|
||||
if (NOT ${TEMP} EQUAL -1)
|
||||
set(${RETURN_VAR} "${LANG}" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
endfunction ()
|
||||
|
||||
|
||||
# Helper function to get the relative path of the source file destination path.
|
||||
# This path is needed by FindGcov and FindLcov cmake files to locate the
|
||||
# captured data.
|
||||
function (codecov_path_of_source FILE RETURN_VAR)
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE})
|
||||
|
||||
# If expression was found, SOURCEFILE is a generator-expression for an
|
||||
# object library. Currently we found no way to call this function automatic
|
||||
# for the referenced target, so it must be called in the directoryso of the
|
||||
# object library definition.
|
||||
if (NOT "${_source}" STREQUAL "")
|
||||
set(${RETURN_VAR} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif ()
|
||||
|
||||
|
||||
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}")
|
||||
if(IS_ABSOLUTE ${FILE})
|
||||
file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE})
|
||||
endif()
|
||||
|
||||
# get the right path for file
|
||||
string(REPLACE ".." "__" PATH "${FILE}")
|
||||
|
||||
set(${RETURN_VAR} "${PATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
|
||||
|
||||
# Add coverage support for target ${TNAME} and register target for coverage
|
||||
# evaluation.
|
||||
function(add_coverage_target TNAME)
|
||||
# Check if all sources for target use the same compiler. If a target uses
|
||||
# e.g. C and Fortran mixed and uses different compilers (e.g. clang and
|
||||
# gfortran) this can trigger huge problems, because different compilers may
|
||||
# use different implementations for code coverage.
|
||||
get_target_property(TSOURCES ${TNAME} SOURCES)
|
||||
set(TARGET_COMPILER "")
|
||||
set(ADDITIONAL_FILES "")
|
||||
foreach (FILE ${TSOURCES})
|
||||
# If expression was found, FILE is a generator-expression for an object
|
||||
# library. Object libraries will be ignored.
|
||||
string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE})
|
||||
if ("${_file}" STREQUAL "")
|
||||
codecov_lang_of_source(${FILE} LANG)
|
||||
if (LANG)
|
||||
list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID})
|
||||
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcno")
|
||||
list(APPEND ADDITIONAL_FILES "${FILE}.gcda")
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
list(REMOVE_DUPLICATES TARGET_COMPILER)
|
||||
list(LENGTH TARGET_COMPILER NUM_COMPILERS)
|
||||
|
||||
if (NUM_COMPILERS GREATER 1)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it will be compiled by incompatible compilers. Target will be "
|
||||
"compiled without code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NUM_COMPILERS EQUAL 0)
|
||||
message(WARNING "Can't use code coverage for target ${TNAME}, because "
|
||||
"it uses an unknown compiler. Target will be compiled without "
|
||||
"code coverage.")
|
||||
return()
|
||||
|
||||
elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS")
|
||||
# A warning has been printed before, so just return if flags for this
|
||||
# compiler aren't available.
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
# enable coverage for target
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
set_property(TARGET ${TNAME} APPEND_STRING
|
||||
PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}")
|
||||
|
||||
|
||||
# Add gcov files generated by compiler to clean target.
|
||||
set(CLEAN_FILES "")
|
||||
foreach (FILE ${ADDITIONAL_FILES})
|
||||
codecov_path_of_source(${FILE} FILE)
|
||||
list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}")
|
||||
endforeach()
|
||||
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${CLEAN_FILES}")
|
||||
|
||||
|
||||
add_gcov_target(${TNAME})
|
||||
add_lcov_target(${TNAME})
|
||||
endfunction(add_coverage_target)
|
||||
|
||||
|
||||
|
||||
|
||||
# Include modules for parsing the collected data and output it in a readable
|
||||
# format (like gcov and lcov).
|
||||
find_package(Gcov)
|
||||
find_package(Lcov)
|
56
CMake/llvm-cov-wrapper
Executable file
56
CMake/llvm-cov-wrapper
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This file is part of CMake-codecov.
|
||||
#
|
||||
# Copyright (c)
|
||||
# 2015-2017 RWTH Aachen University, Federal Republic of Germany
|
||||
#
|
||||
# See the LICENSE file in the package base directory for details
|
||||
#
|
||||
# Written by Alexander Haase, alexander.haase@rwth-aachen.de
|
||||
#
|
||||
|
||||
if [ -z "$LLVM_COV_BIN" ]
|
||||
then
|
||||
echo "LLVM_COV_BIN not set!" >& 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Get LLVM version to find out.
|
||||
LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \
|
||||
| sed "s/^\([A-Za-z ]*\)\([0-9]\).\([0-9]\).*$/\2.\3/g")
|
||||
|
||||
if [ "$1" = "-v" ]
|
||||
then
|
||||
echo "llvm-cov-wrapper $LLVM_VERSION"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$LLVM_VERSION" ]
|
||||
then
|
||||
MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1)
|
||||
MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2)
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ]
|
||||
then
|
||||
if [ -f "$1" ]
|
||||
then
|
||||
filename=$(basename "$1")
|
||||
extension="${filename##*.}"
|
||||
|
||||
case "$extension" in
|
||||
"gcno") exec $LLVM_COV_BIN --gcno="$1" ;;
|
||||
"gcda") exec $LLVM_COV_BIN --gcda="$1" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ]
|
||||
then
|
||||
exec $LLVM_COV_BIN $@
|
||||
fi
|
||||
fi
|
||||
|
||||
exec $LLVM_COV_BIN gcov $@
|
257
CMakeLists.txt
257
CMakeLists.txt
@@ -1,6 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
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.2.2)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
|
||||
option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
|
||||
option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
|
||||
option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
@@ -10,15 +23,6 @@ set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
||||
set(HEADER_DIR ${CATCH_DIR}/include)
|
||||
|
||||
if(USE_CPP14)
|
||||
message(STATUS "Enabling C++14")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
message(STATUS "Enabling C++11")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
endif()
|
||||
|
||||
if(USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
@@ -53,31 +57,32 @@ endfunction()
|
||||
# define the sources of the self test
|
||||
# Please keep these ordered alphabetically
|
||||
set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/ApproxTests.cpp
|
||||
${SELF_TEST_DIR}/BDDTests.cpp
|
||||
${SELF_TEST_DIR}/Benchmark.tests.cpp
|
||||
${SELF_TEST_DIR}/ClassTests.cpp
|
||||
${SELF_TEST_DIR}/CmdLineTests.cpp
|
||||
${SELF_TEST_DIR}/CompilationTests.cpp
|
||||
${SELF_TEST_DIR}/ConditionTests.cpp
|
||||
${SELF_TEST_DIR}/DecompositionTests.cpp
|
||||
${SELF_TEST_DIR}/EnumToString.cpp
|
||||
${SELF_TEST_DIR}/ExceptionTests.cpp
|
||||
${SELF_TEST_DIR}/MessageTests.cpp
|
||||
${SELF_TEST_DIR}/MiscTests.cpp
|
||||
${SELF_TEST_DIR}/PartTrackerTests.cpp
|
||||
${SELF_TEST_DIR}/TagAliasTests.cpp
|
||||
${SELF_TEST_DIR}/TestMain.cpp
|
||||
${SELF_TEST_DIR}/ToStringChrono.cpp
|
||||
${SELF_TEST_DIR}/ToStringGeneralTests.cpp
|
||||
${SELF_TEST_DIR}/ToStringPair.cpp
|
||||
${SELF_TEST_DIR}/ToStringTuple.cpp
|
||||
${SELF_TEST_DIR}/ToStringVector.cpp
|
||||
${SELF_TEST_DIR}/ToStringWhich.cpp
|
||||
${SELF_TEST_DIR}/TrickyTests.cpp
|
||||
${SELF_TEST_DIR}/VariadicMacrosTests.cpp
|
||||
${SELF_TEST_DIR}/MatchersTests.cpp
|
||||
${SELF_TEST_DIR}/StringRef.tests.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})
|
||||
|
||||
@@ -146,6 +151,8 @@ set(INTERNAL_HEADERS
|
||||
${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_generic.hpp
|
||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
||||
${HEADER_DIR}/internal/catch_message.h
|
||||
@@ -165,7 +172,6 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_session.h
|
||||
${HEADER_DIR}/internal/catch_startup_exception_registry.h
|
||||
${HEADER_DIR}/internal/catch_stream.h
|
||||
${HEADER_DIR}/internal/catch_streambuf.h
|
||||
${HEADER_DIR}/internal/catch_stringref.h
|
||||
${HEADER_DIR}/internal/catch_string_manip.h
|
||||
${HEADER_DIR}/internal/catch_suppress_warnings.h
|
||||
@@ -182,6 +188,8 @@ set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_timer.h
|
||||
${HEADER_DIR}/internal/catch_tostring.h
|
||||
${HEADER_DIR}/internal/catch_totals.h
|
||||
${HEADER_DIR}/internal/catch_uncaught_exceptions.h
|
||||
${HEADER_DIR}/internal/catch_user_interfaces.h
|
||||
${HEADER_DIR}/internal/catch_version.h
|
||||
${HEADER_DIR}/internal/catch_wildcard_pattern.h
|
||||
${HEADER_DIR}/internal/catch_windows_h_proxy.h
|
||||
@@ -213,6 +221,8 @@ set(IMPL_SOURCES
|
||||
${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_generic.cpp
|
||||
${HEADER_DIR}/internal/catch_matchers_string.cpp
|
||||
${HEADER_DIR}/internal/catch_message.cpp
|
||||
${HEADER_DIR}/internal/catch_registry_hub.cpp
|
||||
@@ -226,7 +236,6 @@ set(IMPL_SOURCES
|
||||
${HEADER_DIR}/internal/catch_session.cpp
|
||||
${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
|
||||
${HEADER_DIR}/internal/catch_stream.cpp
|
||||
${HEADER_DIR}/internal/catch_streambuf.cpp
|
||||
${HEADER_DIR}/internal/catch_stringref.cpp
|
||||
${HEADER_DIR}/internal/catch_string_manip.cpp
|
||||
${HEADER_DIR}/internal/catch_tag_alias.cpp
|
||||
@@ -241,6 +250,7 @@ set(IMPL_SOURCES
|
||||
${HEADER_DIR}/internal/catch_timer.cpp
|
||||
${HEADER_DIR}/internal/catch_tostring.cpp
|
||||
${HEADER_DIR}/internal/catch_totals.cpp
|
||||
${HEADER_DIR}/internal/catch_uncaught_exceptions.cpp
|
||||
${HEADER_DIR}/internal/catch_version.cpp
|
||||
${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
|
||||
${HEADER_DIR}/internal/catch_xmlwriter.cpp
|
||||
@@ -252,9 +262,13 @@ CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
|
||||
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
|
||||
@@ -275,59 +289,168 @@ set(HEADERS
|
||||
${REPORTER_HEADERS}
|
||||
)
|
||||
|
||||
|
||||
set(BENCH_SOURCES
|
||||
${BENCHMARK_DIR}/BenchMain.cpp
|
||||
${BENCHMARK_DIR}/StringificationBench.cpp
|
||||
)
|
||||
CheckFileList(BENCH_SOURCES ${BENCHMARK_DIR})
|
||||
|
||||
# Provide some groupings for IDEs
|
||||
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
||||
SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
|
||||
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
|
||||
|
||||
# configure the executable
|
||||
include_directories(${HEADER_DIR})
|
||||
|
||||
add_definitions( -DCATCH_CONFIG_FULL_PROJECT )
|
||||
|
||||
# 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})
|
||||
add_executable(Benchmark ${BENCH_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${HEADERS})
|
||||
|
||||
# Add desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code )
|
||||
target_compile_options( Benchmark PRIVATE -Wall -Wextra -Wunreachable-code )
|
||||
if(DEFINED NO_SELFTEST)
|
||||
message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead")
|
||||
if (NO_SELFTEST)
|
||||
set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
|
||||
else()
|
||||
set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
|
||||
endif()
|
||||
# Clang specific warning go here
|
||||
endif()
|
||||
|
||||
include(CTest)
|
||||
|
||||
if (BUILD_TESTING AND NOT_SUBPROJECT)
|
||||
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
|
||||
target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
|
||||
|
||||
if(USE_CPP14)
|
||||
message(STATUS "Enabling C++14")
|
||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 14)
|
||||
else()
|
||||
message(STATUS "Enabling C++11")
|
||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
|
||||
|
||||
if (CATCH_ENABLE_COVERAGE)
|
||||
set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
|
||||
find_package(codecov)
|
||||
add_coverage(SelfTest)
|
||||
list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'")
|
||||
coverage_evaluate()
|
||||
endif()
|
||||
|
||||
# Add per compiler options
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic)
|
||||
if (CATCH_ENABLE_WERROR)
|
||||
target_compile_options( SelfTest PRIVATE -Werror)
|
||||
endif()
|
||||
endif()
|
||||
# Clang specific options go here
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
# 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" )
|
||||
target_compile_options( SelfTest PRIVATE /W4 /w44265 /WX )
|
||||
target_compile_options( Benchmark PRIVATE /W4 )
|
||||
STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
|
||||
target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 )
|
||||
if (CATCH_ENABLE_WERROR)
|
||||
target_compile_options( SelfTest PRIVATE /WX)
|
||||
endif()
|
||||
# Force MSVC to consider everything as encoded in utf-8
|
||||
target_compile_options( SelfTest PRIVATE /utf-8 )
|
||||
endif()
|
||||
|
||||
|
||||
# configure unit tests via CTest
|
||||
enable_testing()
|
||||
add_test(NAME RunTests COMMAND SelfTest)
|
||||
include(CTest)
|
||||
add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest>)
|
||||
|
||||
add_test(NAME ListTests COMMAND SelfTest --list-tests)
|
||||
set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases")
|
||||
add_test(NAME ListTests COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
set_tests_properties(ListTests PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[0-9]+ test cases"
|
||||
FAIL_REGULAR_EXPRESSION "Hidden Test"
|
||||
)
|
||||
|
||||
add_test(NAME ListTags COMMAND SelfTest --list-tags)
|
||||
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
|
||||
add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
|
||||
set_tests_properties(ListTags PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
|
||||
FAIL_REGULAR_EXPRESSION "[.]")
|
||||
|
||||
add_test(NAME ListReporters COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
|
||||
set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
|
||||
|
||||
add_test(NAME ListTestNamesOnly COMMAND $<TARGET_FILE:SelfTest> --list-test-names-only)
|
||||
set_tests_properties(ListTestNamesOnly PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Regex string matcher"
|
||||
FAIL_REGULAR_EXPRESSION "Hidden Test")
|
||||
|
||||
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions)
|
||||
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
|
||||
|
||||
add_test(NAME NoTest COMMAND $<TARGET_FILE:SelfTest> -w NoTests "___nonexistent_test___")
|
||||
set_tests_properties(NoTest PROPERTIES PASS_REGULAR_EXPRESSION "No test cases matched")
|
||||
|
||||
# AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
|
||||
add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
|
||||
set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
|
||||
|
||||
if (CATCH_USE_VALGRIND)
|
||||
add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
|
||||
add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
|
||||
set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
|
||||
add_test(NAME ValgrindListTags COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tags)
|
||||
set_tests_properties(ValgrindListTags PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
|
||||
endif()
|
||||
|
||||
endif() # !NO_SELFTEST
|
||||
|
||||
|
||||
install(DIRECTORY "single_include/" DESTINATION "include/catch")
|
||||
if(CATCH_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
|
||||
|
||||
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
||||
|
||||
## Provide some pkg-config integration
|
||||
# Don't bother on Windows
|
||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
|
||||
set(PKGCONFIG_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||
CACHE PATH "Path where catch.pc is installed"
|
||||
)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/catch.pc.in ${CMAKE_CURRENT_BINARY_DIR}/catch.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/catch.pc DESTINATION ${PKGCONFIG_INSTALL_DIR})
|
||||
|
||||
endif()
|
||||
|
||||
# add catch as a 'linkable' target
|
||||
add_library(Catch INTERFACE)
|
||||
|
||||
# depend on some obvious c++11 features so the dependency is transitively added dependants
|
||||
target_compile_features(Catch INTERFACE cxx_auto_type cxx_constexpr cxx_noexcept)
|
||||
|
||||
target_include_directories(Catch
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/single_include>
|
||||
$<INSTALL_INTERFACE:include/catch>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
|
||||
add_library(Catch2::Catch ALIAS Catch)
|
||||
|
||||
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
|
||||
|
||||
# create and install an export set for catch target as Catch2::Catch
|
||||
install(TARGETS Catch EXPORT Catch2Config DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(EXPORT Catch2Config
|
||||
NAMESPACE Catch2::
|
||||
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})
|
||||
|
||||
# install Catch2ConfigVersion.cmake file to handle versions in find_package
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
|
||||
DESTINATION ${CATCH_CMAKE_CONFIG_DESTINATION})
|
||||
|
26
README.md
26
README.md
@@ -1,17 +1,25 @@
|
||||
<a id="top"></a>
|
||||

|
||||

|
||||
|
||||
[](https://github.com/philsquared/catch/releases)
|
||||
[](https://travis-ci.org/philsquared/Catch?branch=catch2)
|
||||
[](https://ci.appveyor.com/project/philsquared/catch/branch/catch2)
|
||||
[](https://github.com/catchorg/catch2/releases)
|
||||
[](https://travis-ci.org/catchorg/Catch2)
|
||||
[](https://ci.appveyor.com/project/catchorg/catch2)
|
||||
[](https://codecov.io/gh/catchorg/Catch2)
|
||||
[](https://wandbox.org/permlink/fRDMfYjUnrbOFwLn)
|
||||
|
||||
<a href="https://github.com/philsquared/Catch/releases/download/v2.0.0-develop.4/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.2.2/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
|
||||
|
||||
## Catch2 is released!
|
||||
|
||||
If you've been using an earlier version of Catch, please see the
|
||||
Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1)
|
||||
before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details.
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
Catch stands for C++ Automated Test Cases in Headers and is a
|
||||
Catch2 stands for C++ Automated Test Cases in a Header and is a
|
||||
multi-paradigm test framework for C++. which also supports Objective-C
|
||||
and, maybe, C.
|
||||
(and maybe C).
|
||||
It is primarily distributed as a single header file, although certain
|
||||
extensions may require additional headers.
|
||||
|
||||
@@ -23,6 +31,6 @@ This documentation comprises these three parts:
|
||||
* [Reference section](docs/Readme.md#top) - all the details
|
||||
|
||||
## More
|
||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/philsquared/Catch/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)
|
||||
* See [who else is using Catch](docs/opensource-users.md#top)
|
||||
* See [who else is using Catch2](docs/opensource-users.md#top)
|
||||
|
70
appveyor.yml
70
appveyor.yml
@@ -1,6 +1,10 @@
|
||||
# version string format -- This will be overwritten later anyway
|
||||
version: "{build}"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- /dev-travis.+/
|
||||
|
||||
os:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2015
|
||||
@@ -15,23 +19,53 @@ environment:
|
||||
|
||||
- additional_flags: "/D_UNICODE /DUNICODE"
|
||||
wmain: 1
|
||||
coverage: 0
|
||||
|
||||
# Have a coverage dimension
|
||||
- additional_flags: ""
|
||||
wmain: 0
|
||||
coverage: 1
|
||||
|
||||
# Have an examples dimension
|
||||
- additional_flags: ""
|
||||
wmain: 0
|
||||
examples: 1
|
||||
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- os: Visual Studio 2017
|
||||
exclude:
|
||||
-
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
os: Visual Studio 2015
|
||||
-
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
os: Visual Studio 2013
|
||||
- os: Visual Studio 2015
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
# Set build version to git commit-hash
|
||||
- ps: Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_BRANCH) - $($env:APPVEYOR_REPO_COMMIT)"
|
||||
- os: Visual Studio 2015
|
||||
additional_flags: "/D_UNICODE /DUNICODE"
|
||||
|
||||
# fetch repository as zip archive
|
||||
shallow_clone: true
|
||||
# Exclude unwanted coverage configurations
|
||||
- coverage: 1
|
||||
platform: Win32
|
||||
|
||||
- coverage: 1
|
||||
os: Visual Studio 2015
|
||||
|
||||
- coverage: 1
|
||||
configuration: Release
|
||||
|
||||
# Exclude unwanted examples configurations
|
||||
- examples: 1
|
||||
platform: Win32
|
||||
|
||||
- examples: 1
|
||||
os: Visual Studio 2015
|
||||
|
||||
- examples: 1
|
||||
configuration: Release
|
||||
|
||||
|
||||
install:
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
|
||||
- ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
|
||||
|
||||
# Win32 and x64 are CMake-compatible solution platform names.
|
||||
# This allows us to pass %PLATFORM% to CMake -A.
|
||||
@@ -47,14 +81,18 @@ configuration:
|
||||
#Cmake will autodetect the compiler, but we set the arch
|
||||
before_build:
|
||||
- set CXXFLAGS=%additional_flags%
|
||||
- cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
|
||||
# Indirection because appveyor doesn't handle multiline batch scripts properly
|
||||
# https://stackoverflow.com/questions/37627248/how-to-split-a-command-over-multiple-lines-in-appveyor-yml/37647169#37647169
|
||||
# https://help.appveyor.com/discussions/questions/3888-multi-line-cmd-or-powershell-warning-ignore
|
||||
- cmd: .\misc\appveyorBuildConfigurationScript.bat
|
||||
|
||||
|
||||
# build with MSBuild
|
||||
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
|
||||
verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed}
|
||||
|
||||
test_script:
|
||||
- cd Build
|
||||
- ctest -V -j 2 -C %CONFIGURATION%
|
||||
- set CTEST_OUTPUT_ON_FAILURE=1
|
||||
- cmd: .\misc\appveyorTestRunScript.bat
|
||||
|
BIN
artwork/catch2-c-logo.png
Normal file
BIN
artwork/catch2-c-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
artwork/catch2-hand-logo.png
Normal file
BIN
artwork/catch2-hand-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
artwork/catch2-logo-small.png
Normal file
BIN
artwork/catch2-logo-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Before Width: | Height: | Size: 52 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
6
catch.pc.in
Normal file
6
catch.pc.in
Normal file
@@ -0,0 +1,6 @@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
|
||||
Name: Catch
|
||||
Description: Testing library for C++
|
||||
Version: @Catch2_VERSION@
|
||||
Cflags: -I${includedir} -I${includedir}/catch
|
26
codecov.yml
Normal file
26
codecov.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
coverage:
|
||||
precision: 2
|
||||
round: nearest
|
||||
range: "60...90"
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
target: 80%
|
||||
|
||||
|
||||
codecov:
|
||||
branch: master
|
||||
|
||||
comment:
|
||||
layout: "diff"
|
||||
|
||||
coverage:
|
||||
ignore:
|
||||
- "projects/SelfTest"
|
||||
- "**/catch_reporter_tap.hpp"
|
||||
- "**/catch_reporter_automake.hpp"
|
||||
- "**/catch_reporter_teamcity.hpp"
|
||||
- "**/external/clara.hpp"
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
||||
|
||||
class CatchConan(ConanFile):
|
||||
name = "Catch"
|
||||
version = "2.0.0-develop.5"
|
||||
version = "2.2.2"
|
||||
description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
|
||||
author = "philsquared"
|
||||
generators = "cmake"
|
||||
@@ -14,3 +14,6 @@ class CatchConan(ConanFile):
|
||||
|
||||
def package(self):
|
||||
self.copy(pattern="catch.hpp", src="single_include", dst="include")
|
||||
|
||||
def package_id(self):
|
||||
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
|
||||
)
|
77
contrib/CatchAddTests.cmake
Normal file
77
contrib/CatchAddTests.cmake
Normal file
@@ -0,0 +1,77 @@
|
||||
# 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})
|
||||
# Test name; strip spaces to get just the name...
|
||||
string(REGEX REPLACE " +" "" test "${line}")
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"${test}"
|
||||
${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}")
|
@@ -36,6 +36,8 @@
|
||||
# -- adds fixture class name to the test name #
|
||||
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
||||
# -- adds cmake target name to the test name #
|
||||
# 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 #
|
||||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
@@ -45,6 +47,7 @@ option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OF
|
||||
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
||||
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
|
||||
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
||||
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
||||
|
||||
function(PrintDebugMessage)
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
@@ -85,6 +88,15 @@ function(ParseFile SourceFile TestTarget)
|
||||
# Find definition of test names
|
||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||
|
||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(TestName ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<a id="top"></a>
|
||||
# Reference
|
||||
|
||||
To get the most out of Catch, start with the [tutorial](tutorial.md#top).
|
||||
To get the most out of Catch2, start with the [tutorial](tutorial.md#top).
|
||||
Once you're up and running consider the following reference material.
|
||||
|
||||
Writing tests:
|
||||
|
@@ -1,15 +1,15 @@
|
||||
<a id="top"></a>
|
||||
# Assertion Macros
|
||||
|
||||
**Contents**
|
||||
[Natural Expressions](#natural-expressions)
|
||||
[Exceptions](#exceptions)
|
||||
[Matcher expressions](#matcher-expressions)
|
||||
[Thread Safety](#thread-safety)
|
||||
**Contents**<br>
|
||||
[Natural Expressions](#natural-expressions)<br>
|
||||
[Exceptions](#exceptions)<br>
|
||||
[Matcher expressions](#matcher-expressions)<br>
|
||||
[Thread Safety](#thread-safety)<br>
|
||||
|
||||
Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
|
||||
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxilliary macros as well. We'll describe all of these here.
|
||||
Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
|
||||
|
||||
Most of these macros come in two forms:
|
||||
|
||||
@@ -21,7 +21,7 @@ The ```CHECK``` family are equivalent but execution continues in the same test c
|
||||
* **REQUIRE(** _expression_ **)** and
|
||||
* **CHECK(** _expression_ **)**
|
||||
|
||||
Evaluates the expression and records the result. If an exception is thrown it is caught, reported, and counted as a failure. These are the macros you will use most of the time
|
||||
Evaluates the expression and records the result. If an exception is thrown, it is caught, reported, and counted as a failure. These are the macros you will use most of the time.
|
||||
|
||||
Examples:
|
||||
```
|
||||
@@ -64,7 +64,7 @@ This way `Approx` is constructed with reasonable defaults, covering most simple
|
||||
|
||||
* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
|
||||
* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
|
||||
* __scale__ - scale serves to adjust the base for comparison used by epsilon, can be used when By default set to `1.0`.
|
||||
* __scale__ - scale serves to adjust the epsilon's multiplicator. By default set to `0.0`.
|
||||
|
||||
#### epsilon example
|
||||
```cpp
|
||||
@@ -84,7 +84,12 @@ Approx target = Approx(100).margin(5);
|
||||
```
|
||||
|
||||
#### scale
|
||||
Scale can be useful if the computation leading to the result worked on different scale, than is used by the results (and thus expected errors are on a different scale than would be expected based on the results alone).
|
||||
Scale can be useful if the computation leading to the result worked
|
||||
on different scale than is used by the results. Since allowed difference
|
||||
between Approx's value and compared value is based primarily on Approx's value
|
||||
(the allowed difference is computed as
|
||||
`(Approx::scale + Approx::value) * epsilon`), the resulting comparison could
|
||||
need rescaling to be correct.
|
||||
|
||||
|
||||
## Exceptions
|
||||
|
@@ -16,7 +16,7 @@ The XML Reporter writes in an XML format that is specific to Catch.
|
||||
|
||||
The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
|
||||
|
||||
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could covert it to, say, HTML - although this loses the streaming advantage, of course.
|
||||
The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could convert it to, say, HTML - although this loses the streaming advantage, of course.
|
||||
|
||||
### JUnit Reporter
|
||||
```-r junit```
|
||||
@@ -28,9 +28,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.
|
||||
|
||||
## 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
|
||||
#include "catch.hpp"
|
||||
#include "catch_reporter_teamcity.hpp"
|
||||
@@ -55,6 +60,17 @@ Because of the incremental nature of Catch's test suites and ability to run spec
|
||||
|
||||
## Low-level tools
|
||||
|
||||
### Precompiled headers (PCHs)
|
||||
|
||||
Catch offers prototypal support for being included in precompiled headers, but because of its single-header nature it does need some actions by the user:
|
||||
* The precompiled header needs to define `CATCH_CONFIG_ALL_PARTS`
|
||||
* The implementation file needs to
|
||||
* undefine `TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED`
|
||||
* define `CATCH_CONFIG_IMPL_ONLY`
|
||||
* define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`
|
||||
* 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:
|
||||
@@ -113,7 +129,15 @@ The advantage of this approach is that you can always automatically update Catch
|
||||
|
||||
|
||||
### 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
|
||||
We provide 2 CMake scripts that can automatically register Catch-based
|
||||
tests with CTest,
|
||||
* `contrib/ParseAndAddCatchTests.cmake`
|
||||
* `contrib/CatchAddTests.cmake`
|
||||
|
||||
The first is based on parsing the test implementation files, and attempts
|
||||
to register all `TEST_CASE`s using their tags as labels. This means that
|
||||
these:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Test1", "[unit]") {
|
||||
int a = 1;
|
||||
@@ -133,7 +157,14 @@ TEST_CASE("Test3", "[a][b][c]") {
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
```
|
||||
would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and ctest 4 labels would be created, `a`, `b`, `c` and `unit`.
|
||||
would be registered as 3 tests, `Test1`, `Test2` and `Test3`,
|
||||
and 4 CTest labels would be created, `a`, `b`, `c` and `unit`.
|
||||
|
||||
|
||||
The second is based on parsing the output of a Catch binary given
|
||||
`--list-test-names-only`. This means that it deals with inactive
|
||||
(e.g. commented-out) tests better, but requires CMake 3.10 for full
|
||||
functionality.
|
||||
|
||||
### CodeCoverage module (GCOV, LCOV...)
|
||||
|
||||
|
@@ -1,29 +1,29 @@
|
||||
<a id="top"></a>
|
||||
# Command line
|
||||
|
||||
**Contents**
|
||||
[Specifying which tests to run](#specifying-which-tests-to-run)
|
||||
[Choosing a reporter to use](#choosing-a-reporter-to-use)
|
||||
[Breaking into the debugger](#breaking-into-the-debugger)
|
||||
[Showing results for successful tests](#showing-results-for-successful-tests)
|
||||
[Aborting after a certain number of failures](#aborting-after-a-certain-number-of-failures)
|
||||
[Listing available tests, tags or reporters](#listing-available-tests-tags-or-reporters)
|
||||
[Sending output to a file](#sending-output-to-a-file)
|
||||
[Naming a test run](#naming-a-test-run)
|
||||
[Eliding assertions expected to throw](#eliding-assertions-expected-to-throw)
|
||||
[Make whitespace visible](#make-whitespace-visible)
|
||||
[Warnings](#warnings)
|
||||
[Reporting timings](#reporting-timings)
|
||||
[Load test names to run from a file](#load-test-names-to-run-from-a-file)
|
||||
[Just test names](#just-test-names)
|
||||
[Specify the order test cases are run](#specify-the-order-test-cases-are-run)
|
||||
[Specify a seed for the Random Number Generator](#specify-a-seed-for-the-random-number-generator)
|
||||
[Identify framework and version according to the libIdentify standard](#identify-framework-and-version-according-to-the-libidentify-standard)
|
||||
[Wait for key before continuing](#wait-for-key-before-continuing)
|
||||
[Specify multiples of clock resolution to run benchmarks for](#specify-multiples-of-clock-resolution-to-run-benchmarks-for)
|
||||
[Usage](#usage)
|
||||
[Specify the section to run](#specify-the-section-to-run)
|
||||
[Filenames as tags](#filenames-as-tags)
|
||||
**Contents**<br>
|
||||
[Specifying which tests to run](#specifying-which-tests-to-run)<br>
|
||||
[Choosing a reporter to use](#choosing-a-reporter-to-use)<br>
|
||||
[Breaking into the debugger](#breaking-into-the-debugger)<br>
|
||||
[Showing results for successful tests](#showing-results-for-successful-tests)<br>
|
||||
[Aborting after a certain number of failures](#aborting-after-a-certain-number-of-failures)<br>
|
||||
[Listing available tests, tags or reporters](#listing-available-tests-tags-or-reporters)<br>
|
||||
[Sending output to a file](#sending-output-to-a-file)<br>
|
||||
[Naming a test run](#naming-a-test-run)<br>
|
||||
[Eliding assertions expected to throw](#eliding-assertions-expected-to-throw)<br>
|
||||
[Make whitespace visible](#make-whitespace-visible)<br>
|
||||
[Warnings](#warnings)<br>
|
||||
[Reporting timings](#reporting-timings)<br>
|
||||
[Load test names to run from a file](#load-test-names-to-run-from-a-file)<br>
|
||||
[Just test names](#just-test-names)<br>
|
||||
[Specify the order test cases are run](#specify-the-order-test-cases-are-run)<br>
|
||||
[Specify a seed for the Random Number Generator](#specify-a-seed-for-the-random-number-generator)<br>
|
||||
[Identify framework and version according to the libIdentify standard](#identify-framework-and-version-according-to-the-libidentify-standard)<br>
|
||||
[Wait for key before continuing](#wait-for-key-before-continuing)<br>
|
||||
[Specify multiples of clock resolution to run benchmarks for](#specify-multiples-of-clock-resolution-to-run-benchmarks-for)<br>
|
||||
[Usage](#usage)<br>
|
||||
[Specify the section to run](#specify-the-section-to-run)<br>
|
||||
[Filenames as tags](#filenames-as-tags)<br>
|
||||
|
||||
Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
|
||||
Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
|
||||
@@ -78,7 +78,7 @@ Wildcards consist of the `*` character at the beginning and/or end of test case
|
||||
|
||||
Test specs are case insensitive.
|
||||
|
||||
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precendence, however.
|
||||
If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however.
|
||||
Inclusions and exclusions are evaluated in left-to-right order.
|
||||
|
||||
Test case examples:
|
||||
@@ -94,7 +94,7 @@ a* ~ab* abc Matches all tests that start with 'a', except those that
|
||||
</pre>
|
||||
|
||||
Names within square brackets are interpreted as tags.
|
||||
A series of tags form an AND expression wheras a comma-separated sequence forms an OR expression. e.g.:
|
||||
A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.:
|
||||
|
||||
<pre>[one][two],[three]</pre>
|
||||
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
|
||||
@@ -192,9 +192,16 @@ This option transforms tabs and newline characters into ```\t``` and ```\n``` re
|
||||
## Warnings
|
||||
<pre>-w, --warn <warning name></pre>
|
||||
|
||||
Enables reporting of warnings (only one, at time of this writing). If a warning is issued it fails the test.
|
||||
Enables reporting of suspicious test states. There are currently two
|
||||
available warnings
|
||||
|
||||
```
|
||||
NoAssertions // Fail test case / leaf section if no assertions
|
||||
// (e.g. `REQUIRE`) is encountered.
|
||||
NoTests // Return non-zero exit code when no test cases were run
|
||||
// Also calls reporter's noMatchingTestCases method
|
||||
```
|
||||
|
||||
The ony available warning, presently, is ```NoAssertions```. This warning fails a test case, or (leaf) section if no assertions (```REQUIRE```/ ```CHECK``` etc) are encountered.
|
||||
|
||||
<a id="reporting-timings"></a>
|
||||
## Reporting timings
|
||||
@@ -262,7 +269,7 @@ either before running any tests, after running all tests - or both, depending on
|
||||
|
||||
When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
|
||||
numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but
|
||||
it can be overriden here.
|
||||
it can be overridden here.
|
||||
|
||||
<a id="usage"></a>
|
||||
## Usage
|
||||
|
@@ -1,15 +1,17 @@
|
||||
<a id="top"></a>
|
||||
# Compile-time configuration
|
||||
|
||||
**Contents**
|
||||
[main()/ implementation](#main-implementation)
|
||||
[Prefixing Catch macros](#prefixing-catch-macros)
|
||||
[Terminal colour](#terminal-colour)
|
||||
[Console width](#console-width)
|
||||
[stdout](#stdout)
|
||||
[Other toggles](#other-toggles)
|
||||
[Windows header clutter](#windows-header-clutter)
|
||||
[Enabling stringification](#enabling-stringification)
|
||||
**Contents**<br>
|
||||
[main()/ implementation](#main-implementation)<br>
|
||||
[Prefixing Catch macros](#prefixing-catch-macros)<br>
|
||||
[Terminal colour](#terminal-colour)<br>
|
||||
[Console width](#console-width)<br>
|
||||
[stdout](#stdout)<br>
|
||||
[Fallback stringifier](#fallback-stringifier)<br>
|
||||
[Default reporter](#default-reporter)<br>
|
||||
[Other toggles](#other-toggles)<br>
|
||||
[Windows header clutter](#windows-header-clutter)<br>
|
||||
[Enabling stringification](#enabling-stringification)<br>
|
||||
|
||||
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```).
|
||||
|
||||
@@ -24,7 +26,7 @@ Although Catch is header only it still, internally, maintains a distinction betw
|
||||
|
||||
# Reporter / Listener interfaces
|
||||
|
||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in neccessary headers for Reporter/Listener implementation
|
||||
CATCH_CONFIG_EXTERNAL_INTERFACES // Brings in necessary headers for Reporter/Listener implementation
|
||||
|
||||
Brings in various parts of Catch that are required for user defined Reporters and Listeners. This means that new Reporters and Listeners can be defined in this file as well as in the main file.
|
||||
|
||||
@@ -73,6 +75,40 @@ Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly
|
||||
This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
|
||||
|
||||
|
||||
## Fallback stringifier
|
||||
|
||||
By default Catch's stringification machinery falls back to a "{?}". To
|
||||
let projects reuse their own existing stringification machinery, this
|
||||
fallback can be overridden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER`
|
||||
to a name of a function that should perform the stringification instead.
|
||||
|
||||
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++17 toggles
|
||||
|
||||
CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS // Use std::uncaught_exceptions instead of std::uncaught_exception
|
||||
|
||||
Catch contains basic compiler/standard detection and attempts to use
|
||||
some C++17 features whenever appropriate. This automatic detection
|
||||
can be manually overridden in both directions, that is, a feature
|
||||
can be enabled by defining the macro in the table above, and disabled
|
||||
by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
|
||||
|
||||
|
||||
## Other toggles
|
||||
|
||||
@@ -84,6 +120,7 @@ This can be useful on certain platforms that do not provide the standard iostrea
|
||||
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
|
||||
CATCH_CONFIG_DISABLE_STRINGIFICATION // Disable stringifying the original expression
|
||||
CATCH_CONFIG_DISABLE // Disables assertions and test case registration
|
||||
CATCH_CONFIG_WCHAR // Enables use of wchart_t
|
||||
|
||||
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,12 +128,15 @@ 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_WCHAR` is on by default, but can be disabled. Currently
|
||||
it is only used in support for DJGPP cross-compiler.
|
||||
|
||||
These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
|
||||
|
||||
### `CATCH_CONFIG_FAST_COMPILE`
|
||||
Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
|
||||
* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
|
||||
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives.
|
||||
* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_THAT`}, no longer use local try-catch block. This disables exception translation, but should not lead to false negatives.
|
||||
|
||||
`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.
|
||||
|
||||
@@ -106,7 +146,7 @@ When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matcher
|
||||
_Note: If you define `CATCH_CONFIG_DISABLE_MATCHERS` in the same file as Catch's main is implemented, your test executable will fail to link if you use Matchers anywhere._
|
||||
|
||||
### `CATCH_CONFIG_DISABLE_STRINGIFICATION`
|
||||
This toggle enables a workaround for VS 2017 bug. For details see [known limitations](limitations.md#Visual Studio 2017 -- raw string literal in assert fails to compile)
|
||||
This toggle enables a workaround for VS 2017 bug. For details see [known limitations](limitations.md#visual-studio-2017----raw-string-literal-in-assert-fails-to-compile).
|
||||
|
||||
### `CATCH_CONFIG_DISABLE`
|
||||
This toggle removes most of Catch from given file. This means that `TEST_CASE`s are not registered and assertions are turned into no-ops. Useful for keeping tests within implementation files (ie for functions with internal linkage), instead of in external files.
|
||||
|
@@ -19,7 +19,7 @@ file that defines `CATCH_CONFIG_EXTERNAL_INTERFACES`.
|
||||
|
||||
Then register it using `CATCH_REGISTER_LISTENER`.
|
||||
|
||||
For example:
|
||||
For example ([complete source code](../examples/210-Evt-EventListeners.cpp)):
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_MAIN
|
||||
@@ -44,7 +44,7 @@ _Note that you should not use any assertion macros within a Listener!_
|
||||
|
||||
## Events that can be hooked
|
||||
|
||||
The following are the methods that can be overriden in the Listener:
|
||||
The following are the methods that can be overridden in the Listener:
|
||||
|
||||
```c++
|
||||
// The whole test run, starting and ending
|
||||
|
@@ -96,34 +96,20 @@ with expansion:
|
||||
""\" == ""\"
|
||||
```
|
||||
|
||||
### Visual Studio 2015 -- Alignment compilation error (C2718)
|
||||
|
||||
### Visual Studio 2013 -- do-while loop withing range based for fails to compile (C2059)
|
||||
There is a known bug in Visual Studio 2013 (VC 12), that causes compilation error if range based for is followed by an assertion macro, without enclosing the block in braces. This snippet is sufficient to trigger the error
|
||||
```cpp
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
VS 2015 has a known bug, where `declval<T>` can cause compilation error
|
||||
if `T` has alignment requirements that it cannot meet.
|
||||
|
||||
TEST_CASE("Syntax error with VC12") {
|
||||
for ( auto x : { 1 , 2, 3 } )
|
||||
REQUIRE( x < 3.14 );
|
||||
}
|
||||
```
|
||||
An easy workaround is possible, use braces:
|
||||
```cpp
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE("No longer a syntax error with VC12") {
|
||||
for ( auto x : { 1 , 2, 3 } ) {
|
||||
REQUIRE( x < 3.14 );
|
||||
}
|
||||
}
|
||||
```
|
||||
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 2003 -- Syntax error caused by improperly expanded `__LINE__` macro
|
||||
Older version of Visual Studio can have trouble compiling Catch, not expanding the `__LINE__` macro properly when recompiling the test binary. This is caused by Edit and Continue being on.
|
||||
|
||||
A workaround is to turn off Edit and Continue when compiling the test binary.
|
||||
### Visual Studio 2015 -- Wrong line number reported in debug mode
|
||||
VS 2015 has a known bug where `__LINE__` macro can be improperly expanded under certain circumstances, while compiling multi-file project in Debug mode.
|
||||
|
||||
A workaround is to compile the binary in Release mode.
|
||||
|
||||
### Clang/G++ -- skipping leaf sections after an exception
|
||||
Some versions of `libc++` and `libstdc++` (or their runtimes) have a bug with `std::uncaught_exception()` getting stuck returning `true` after rethrow, even if there are no active exceptions. One such case is this snippet, which skipped the sections "a" and "b", when compiled against `libcxxrt` from master
|
||||
@@ -144,3 +130,8 @@ TEST_CASE("b") {
|
||||
```
|
||||
|
||||
If you are seeing a problem like this, i.e. a weird test paths that trigger only under Clang with `libc++`, or only under very specific version of `libstdc++`, it is very likely you are seeing this. The only known workaround is to use a fixed version of your standard library.
|
||||
|
||||
### Clang/G++ -- `Matches` string matcher always returns false
|
||||
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++`.
|
||||
|
31
docs/list-of-examples.md
Normal file
31
docs/list-of-examples.md
Normal file
@@ -0,0 +1,31 @@
|
||||
<a id="top"></a>
|
||||
# List of examples
|
||||
|
||||
- Test Case: [Single-file](../examples/010-TestCase.cpp)
|
||||
- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-1.cpp)
|
||||
- Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
|
||||
- Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
|
||||
- Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
|
||||
- Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
|
||||
- Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
|
||||
- Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
|
||||
- Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
|
||||
- Fixture: [Sections](../examples/100-Fix-Section.cpp)
|
||||
- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
|
||||
- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
|
||||
- Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
|
||||
- Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
|
||||
- Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
|
||||
- Logging: [WARN - Issue warning](../examples/160-Log-Warn.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)
|
||||
- Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
|
||||
- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
|
||||
- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
|
||||
- Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
|
||||
- Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
|
||||
- Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md#top)
|
@@ -36,10 +36,41 @@ REQUIRE_THAT( str,
|
||||
```
|
||||
|
||||
## Built in matchers
|
||||
Currently Catch has some string matchers and some vector matchers. They are in the `Catch::Matchers` and `Catch` namespaces.
|
||||
The string matchers are `StartsWith`, `EndsWith`, `Contains` and `Equals`. Each of them also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
|
||||
Catch currently provides some matchers, they are in the `Catch::Matchers` and `Catch` namespaces.
|
||||
|
||||
### String matchers
|
||||
The string matchers are `StartsWith`, `EndsWith`, `Contains`, `Equals` and `Matches`. The first four match a literal (sub)string against a result, while `Matches` takes and matches an ECMAScript regex. Do note that `Matches` matches the string as a whole, meaning that "abc" will not match against "abcd", but "abc.*" will.
|
||||
|
||||
Each of the provided `std::string` matchers also takes an optional second argument, that decides case sensitivity (by-default, they are case sensitive).
|
||||
|
||||
|
||||
### Vector matchers
|
||||
The vector matchers are `Contains`, `VectorContains` and `Equals`. `VectorContains` looks for a single element in the matched vector, `Contains` looks for a set (vector) of elements inside the matched vector.
|
||||
|
||||
### Floating point matchers
|
||||
The floating point matchers are `WithinULP` and `WithinAbs`. `WithinAbs` accepts floating point numbers that are within a certain margin of target. `WithinULP` performs an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place)-based comparison of two floating point numbers and accepts them if they are less than certain number of ULPs apart.
|
||||
|
||||
Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
|
||||
|
||||
|
||||
### Generic matchers
|
||||
Catch also aims to provide a set of generic matchers. Currently this set
|
||||
contains only a matcher that takes arbitrary callable predicate and applies
|
||||
it onto the provided object.
|
||||
|
||||
Because of type inference limitations, the argument type of the predicate
|
||||
has to be provided explicitly. Example:
|
||||
```cpp
|
||||
REQUIRE_THAT("Hello olleH",
|
||||
Predicate<std::string>(
|
||||
[] (std::string const& str) -> bool { return str.front() == str.back(); },
|
||||
"First and last character should be equal")
|
||||
);
|
||||
```
|
||||
|
||||
The second argument is an optional description of the predicate, and is
|
||||
used only during reporting of the result.
|
||||
|
||||
|
||||
## Custom matchers
|
||||
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
||||
|
@@ -1,18 +1,18 @@
|
||||
<a id="top"></a>
|
||||
# Open Source projects using Catch
|
||||
|
||||
Catch is great for open source. With it's [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
|
||||
Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
|
||||
it's easy to just drop the header into your project and start writing tests - what's not to like?
|
||||
|
||||
As a result Catch is now being used in many Open Source projects, including some quite well known ones.
|
||||
This page is an attempt to track those projects. Obviously it can never be complete.
|
||||
This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR
|
||||
(or, if you prefer contact one of the maintainers of Catch directly, use the
|
||||
(or, if you prefer contact one of the maintainers of Catch directly, use the
|
||||
[forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)), or raise an [issue](https://github.com/philsquared/Catch/issues) to let us know).
|
||||
Of course users of those projects might want to update this page too. That's fine - as long you're confident the project maintainers won't mind.
|
||||
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
|
||||
If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
|
||||
just let us know via any of the previously mentioned means - although I'm sure there won't be many who feel that way.
|
||||
|
||||
|
||||
Listing a project here does not imply endorsement and the plan is to keep these ordered alphabetically to avoid an implication of relative importance.
|
||||
|
||||
## Libraries & Frameworks
|
||||
@@ -21,7 +21,7 @@ Listing a project here does not imply endorsement and the plan is to keep these
|
||||
Boost Asio style bindings for ZeroMQ
|
||||
|
||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||
The core part of the Chakra Javascript engine that powers Microsoft Edge
|
||||
The core part of the Chakra JavaScript engine that powers Microsoft Edge
|
||||
|
||||
### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
|
||||
A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
|
||||
@@ -30,13 +30,25 @@ A, header-only, embedded scripting language designed from the ground up to direc
|
||||
A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
|
||||
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
The next-generation core storage and query engine for Couchbase Lite/
|
||||
The next-generation core storage and query engine for Couchbase Lite
|
||||
|
||||
### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
|
||||
A High-performance Cluster Computing Engine
|
||||
|
||||
### [forest](https://github.com/xorz57/forest)
|
||||
Forest is an open-source, template library of tree data structures written in C++11.
|
||||
|
||||
### [Fuxedo](https://github.com/fuxedo/fuxedo)
|
||||
Open source Oracle Tuxedo-like XATMI middleware for C and C++.
|
||||
|
||||
### [Inja](https://github.com/pantor/inja)
|
||||
A header-only template engine for modern C++.
|
||||
|
||||
### [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||
A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
|
||||
|
||||
### [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.
|
||||
|
||||
### [nanodbc](https://github.com/lexicalunit/nanodbc/)
|
||||
A small C++ library wrapper for the native C ODBC API.
|
||||
@@ -79,6 +91,9 @@ MAME originally stood for Multiple Arcade Machine Emulator
|
||||
### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
|
||||
Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
|
||||
|
||||
### [SpECTRE](https://github.com/sxs-collaboration/spectre)
|
||||
SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
|
||||
|
@@ -30,7 +30,7 @@ int main( int argc, char* argv[] ) {
|
||||
|
||||
## Amending the config
|
||||
|
||||
If you still want Catch to process the command line, but you want to programatically tweak the config, you can do so in one of two ways:
|
||||
If you still want Catch to process the command line, but you want to programmatically tweak the config, you can do so in one of two ways:
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
@@ -39,34 +39,20 @@ If you still want Catch to process the command line, but you want to programatic
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
Catch::Session session; // There must be exactly one instance
|
||||
|
||||
|
||||
// writing to session.configData() here sets defaults
|
||||
// this is the preferred way to set them
|
||||
|
||||
// Verify that all tests, aliases, etc registered properly
|
||||
const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
|
||||
if ( !exceptions.empty() ) {
|
||||
// iterate over all exceptions and notify user
|
||||
for ( const auto& ex_ptr : exceptions ) {
|
||||
try {
|
||||
std::rethrow_exception(ex_ptr);
|
||||
} catch (std::exception const& ex) {
|
||||
Catch::cerr() << ex.what();
|
||||
}
|
||||
}
|
||||
// Indicate that an error occured before main
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int returnCode = session.applyCommandLine( argc, argv );
|
||||
if( returnCode != 0 ) // Indicates a command line error
|
||||
return returnCode;
|
||||
|
||||
return returnCode;
|
||||
|
||||
// writing to session.configData() or session.Config() here
|
||||
// overrides command line args
|
||||
// only do this if you know you need to
|
||||
|
||||
int numFailed = session.run();
|
||||
|
||||
// numFailed is clamped to 255 as some unices only use the lower 8 bits.
|
||||
// This clamping has already been applied, so just return it here
|
||||
// You can also do any post run clean-up here
|
||||
@@ -80,7 +66,59 @@ To take full control of the config simply omit the call to ```applyCommandLine()
|
||||
|
||||
## Adding your own command line options
|
||||
|
||||
Catch embeds a powerful command line parser which you can also use to parse your own options out. This capability is still in active development but will be documented here when it is ready.
|
||||
Catch embeds a powerful command line parser called [Clara](https://github.com/philsquared/Clara).
|
||||
As of Catch2 (and Clara 1.0) Clara allows you to write _composable_ option and argument parsers,
|
||||
so extending Catch's own command line options is now easy.
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch.hpp"
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
Catch::Session session; // There must be exactly one instance
|
||||
|
||||
int height = 0; // Some user variable you want to be able to set
|
||||
|
||||
// Build a new parser on top of Catch's
|
||||
using namespace Catch::clara;
|
||||
auto cli
|
||||
= session.cli() // Get Catch's composite command line parser
|
||||
| Opt( height, "height" ) // bind variable to a new option, with a hint string
|
||||
["-g"]["--height"] // the option names it will respond to
|
||||
("how high?"); // description string for the help output
|
||||
|
||||
// Now pass the new composite back to Catch so it uses that
|
||||
session.cli( cli );
|
||||
|
||||
// Let Catch (using Clara) parse the command line
|
||||
int returnCode = session.applyCommandLine( argc, argv );
|
||||
if( returnCode != 0 ) // Indicates a command line error
|
||||
return returnCode;
|
||||
|
||||
// if set on the command line then 'height' is now set at this point
|
||||
if( height > 0 )
|
||||
std::cout << "height: " << height << std::endl;
|
||||
|
||||
return session.run();
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
@@ -1,5 +1,139 @@
|
||||
<a id="top"></a>
|
||||
# 2.0.0 (in progress)
|
||||
|
||||
# 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
|
||||
* On top of the performance regression fixes
|
||||
* Experimental support for PCH was added (#1061)
|
||||
* `CATCH_CONFIG_EXTERNAL_INTERFACES` now brings in declarations of Console, Compact, XML and JUnit reporters
|
||||
* `MatcherBase` no longer has a pointless second template argument
|
||||
* Reduced the number of warning suppressions that leak into user's code
|
||||
* Bugs in g++ 4.x and 5.x mean that some of them have to be left in
|
||||
|
||||
|
||||
## Fixes
|
||||
* Fixed performance regression from Catch classic
|
||||
* One of the performance improvement patches for Catch classic was not applied to Catch2
|
||||
* Fixed platform detection for iOS (#1084)
|
||||
* Fixed compilation when `g++` is used together with `libc++` (#1110)
|
||||
* Fixed TeamCity reporter compilation with the single header version
|
||||
* To fix the underlying issue we will be versioning reporters in single_include folder per release
|
||||
* The XML reporter will now report `WARN` messages even when not used with `-s`
|
||||
* Fixed compilation when `VectorContains` matcher was combined using `&&` (#1092)
|
||||
* Fixed test duration overflowing after 10 seconds (#1125, #1129)
|
||||
* Fixed `std::uncaught_exception` deprecation warning (#1124)
|
||||
|
||||
|
||||
## New features
|
||||
* New Matchers
|
||||
* Regex matcher for strings, `Matches`.
|
||||
* Set-equal matcher for vectors, `UnorderedEquals`
|
||||
* Floating point matchers, `WithinAbs` and `WithinULP`.
|
||||
* Stringification now attempts to decompose all containers (#606)
|
||||
* Containers are objects that respond to ADL `begin(T)` and `end(T)`.
|
||||
|
||||
|
||||
## Other changes
|
||||
* Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
|
||||
|
||||
|
||||
|
||||
|
||||
# 2.0.1
|
||||
|
||||
## Breaking changes
|
||||
* Removed C++98 support
|
||||
@@ -25,13 +159,18 @@
|
||||
* `std::pair` and `std::tuple` are no longer stringified by default
|
||||
* This is done to avoid dragging in `<tuple>` and `<utility>` headers in common path
|
||||
* Their stringification can be enabled per-file via new configuration macros
|
||||
* `Approx` is subtly different and hopefully behaves more as users would expect
|
||||
* `Approx::scale` defaults to `0.0`
|
||||
* `Approx::epsilon` no longer applies to the larger of the two compared values, but only to the `Approx`'s value
|
||||
* `INFINITY == Approx(INFINITY)` returns true
|
||||
|
||||
|
||||
## Improvements
|
||||
* 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.
|
||||
* Errors that happen during set up before main are now caught and properly reported once main is entered
|
||||
* If you are providing your own main, you can access and use these as well.
|
||||
* New assertion macros, *_THROWS_WITH(expr, exception_type, matcher) are provided
|
||||
* New assertion macros, *_THROWS_MATCHES(expr, exception_type, matcher) are provided
|
||||
* As the arguments suggest, these allow you to assert that an expression throws desired type of exception and pass the exception to a matcher.
|
||||
* JUnit reporter no longer has significantly different output for test cases with and without sections
|
||||
* Most assertions now support expressions containing commas (ie `REQUIRE(foo() == std::vector<int>{1, 2, 3});`)
|
||||
@@ -57,6 +196,8 @@
|
||||
* The Reporter/Listener interface provides default, empty, implementation to preserve backward compatibility
|
||||
* Stringification of `std::chrono::duration` and `std::chrono::time_point` is now supported
|
||||
* Needs to be enabled by a per-file compile time configuration option
|
||||
* Add `pkg-config` support to CMake install command
|
||||
|
||||
|
||||
## Fixes
|
||||
* Don't use console colour if running in XCode
|
||||
@@ -67,6 +208,8 @@
|
||||
* Implemented a workaround for `std::uncaught_exception` issues in libcxxrt
|
||||
* These issues caused incorrect section traversals
|
||||
* The workaround is only partial, user's test can still trigger the issue by using `throw;` to rethrow an exception
|
||||
* Suppressed C4061 warning under MSVC
|
||||
|
||||
|
||||
## Internal changes
|
||||
* The development version now uses .cpp files instead of header files containing implementation.
|
||||
@@ -78,6 +221,41 @@
|
||||
|
||||
# Older versions
|
||||
|
||||
## 1.11.x
|
||||
|
||||
### 1.11.0
|
||||
|
||||
#### Fixes
|
||||
* 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`
|
||||
* `Approx::Margin` is now inclusive (#952)
|
||||
* Previously it was meant and documented as inclusive, but the check itself wasn't
|
||||
* This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
|
||||
* `RandomNumberGenerator::result_type` is now unsigned (#1050)
|
||||
|
||||
#### Improvements
|
||||
* `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
|
||||
* When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
|
||||
* TeamCity reporter now explicitly flushes output stream after each report (#1057)
|
||||
* On some platforms, output from redirected streams would show up only after the tests finished running
|
||||
* `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
|
||||
|
||||
## 1.10.x
|
||||
|
||||
### 1.10.0
|
||||
|
||||
#### Fixes
|
||||
* Evaluation layer has been rewritten (backported from Catch 2)
|
||||
* The new layer is much simpler and fixes some issues (#981)
|
||||
* Implemented workaround for VS 2017 raw string literal stringification bug (#995)
|
||||
* Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
|
||||
* Previously sections with failing assertions would be marked as failed, not failed-but-ok
|
||||
|
||||
#### Improvements
|
||||
* Added [libidentify](https://github.com/janwilmans/LibIdentify) support
|
||||
* Added "wait-for-keypress" option
|
||||
|
||||
## 1.9.x
|
||||
|
||||
### 1.9.6
|
||||
@@ -255,8 +433,8 @@ Cygwin issue with `gettimeofday` - `#define` was not early enough
|
||||
* Cygwin compatibility fixes
|
||||
* Signal handling is no longer compiled by default.
|
||||
* Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
|
||||
* Improved `-Wparentheses` supression for gcc (#674)
|
||||
* When compiled with gcc 4.8 or newer, the supression is localized to assertions only
|
||||
* Improved `-Wparentheses` suppression for gcc (#674)
|
||||
* When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
|
||||
* Otherwise it is supressed for the whole TU
|
||||
* Fixed test spec parser issue (with escapes in multiple names)
|
||||
|
||||
@@ -275,7 +453,7 @@ Xml:
|
||||
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
|
||||
* Revert XML output to XML 1.0
|
||||
* Can provide stylesheet references by extending the XML reporter
|
||||
* Added description and tags attribites to XML Reporter
|
||||
* Added description and tags attributes to XML Reporter
|
||||
* Tags are closed and the stream flushed more eagerly to avoid stdout interpolation
|
||||
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<a id="top"></a>
|
||||
# How to release
|
||||
|
||||
When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
|
||||
When enough changes have accumulated, it is time to release new version of Catch. This document describes the process in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
|
||||
|
||||
## Neccessary steps
|
||||
## Necessary steps
|
||||
|
||||
These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
|
||||
These steps are necessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
|
||||
|
||||
|
||||
### Approval testing
|
||||
@@ -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.
|
||||
|
||||
|
||||
### Generate updated single-include header
|
||||
|
||||
After updating version number, regenerate single-include header using `generateSingleHeader.py`.
|
||||
This will take care of generating the single include header, updating
|
||||
version numbers everywhere and pushing the new version to Wandbox.
|
||||
|
||||
|
||||
### Release notes
|
||||
@@ -39,16 +37,24 @@ After version number is incremented, single-include header is regenerated and re
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
|
||||
|
||||
|
||||
### vcpkg update
|
||||
|
||||
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
|
||||
Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of necessary work for you, it creates a branch and commits necessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
|
||||
|
||||
Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
|
||||
```
|
||||
@@ -57,8 +63,3 @@ GitHub
|
||||
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.
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<a id="top"></a>
|
||||
# Why do my tests take so long to compile?
|
||||
|
||||
**Contents**
|
||||
[Short answer](#short-answer)
|
||||
[Long answer](#long-answer)
|
||||
[Practical example](#practical-example)
|
||||
[Other possible solutions](#other-possible-solutions)
|
||||
**Contents**<br>
|
||||
[Short answer](#short-answer)<br>
|
||||
[Long answer](#long-answer)<br>
|
||||
[Practical example](#practical-example)<br>
|
||||
[Other possible solutions](#other-possible-solutions)<br>
|
||||
|
||||
Several people have reported that test code written with Catch takes much longer to compile than they would expect. Why is that?
|
||||
|
||||
|
@@ -39,13 +39,13 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
||||
|
||||
* `[!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 the 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.
|
||||
|
||||
* `[!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.
|
||||
|
||||
* `[!nonportable]` - Indicates that behaviour may vary between platforms or compilers.
|
||||
|
||||
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped) as a tag. e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
|
||||
* `[#<filename>]` - running with `-#` or `--filenames-as-tags` causes Catch to add the filename, prefixed with `#` (and with any extension stripped), as a tag to all contained tests, e.g. tests in testfile.cpp would all be tagged `[#testfile]`.
|
||||
|
||||
* `[@<alias>]` - tag aliases all begin with `@` (see below).
|
||||
|
||||
@@ -53,7 +53,7 @@ All tag names beginning with non-alphanumeric characters are reserved by Catch.
|
||||
|
||||
## Tag aliases
|
||||
|
||||
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> )
|
||||
|
||||
|
@@ -33,6 +33,23 @@ namespace Catch {
|
||||
}
|
||||
```
|
||||
|
||||
## Catch::is_range<T> specialisation
|
||||
As a fallback, Catch attempts to detect if the type can be iterated
|
||||
(`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
|
||||
as a range. For certain types this can lead to infinite recursion, so
|
||||
it can be disabled by specializing `Catch::is_range` like so:
|
||||
|
||||
```cpp
|
||||
namespace Catch {
|
||||
template<>
|
||||
struct is_range<T> {
|
||||
static const bool value = false;
|
||||
};
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Exceptions
|
||||
|
||||
By default all exceptions deriving from `std::exception` will be translated to strings by calling the `what()` method. For exception types that do not derive from `std::exception` - or if `what()` does not return a suitable string - use `CATCH_TRANSLATE_EXCEPTION`. This defines a function that takes your exception type, by reference, and returns a string. It can appear anywhere in the code - it doesn't have to be in the same translation unit. For example:
|
||||
|
@@ -1,31 +1,31 @@
|
||||
<a id="top"></a>
|
||||
# Tutorial
|
||||
|
||||
**Contents**
|
||||
[Getting Catch](#getting-catch)
|
||||
[Where to put it?](#where-to-put-it)
|
||||
[Writing tests](#writing-tests)
|
||||
[Test cases and sections](#test-cases-and-sections)
|
||||
[BDD-Style](#bdd-style)
|
||||
[Scaling up](#scaling-up)
|
||||
[Next steps](#next-steps)
|
||||
**Contents**<br>
|
||||
[Getting Catch2](#getting-catch2)<br>
|
||||
[Where to put it?](#where-to-put-it)<br>
|
||||
[Writing tests](#writing-tests)<br>
|
||||
[Test cases and sections](#test-cases-and-sections)<br>
|
||||
[BDD-Style](#bdd-style)<br>
|
||||
[Scaling up](#scaling-up)<br>
|
||||
[Next steps](#next-steps)<br>
|
||||
|
||||
## Getting Catch
|
||||
## Getting Catch2
|
||||
|
||||
The simplest way to get Catch is to download the latest [single header version](https://raw.githubusercontent.com/philsquared/Catch/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/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 full source for Catch, 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.
|
||||
|
||||
|
||||
## Where to put it?
|
||||
|
||||
Catch is header only. All you need to do is drop the file(s) somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
|
||||
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
|
||||
|
||||
The rest of this tutorial will assume that the Catch 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.
|
||||
|
||||
## Writing tests
|
||||
|
||||
Let's start with a really simple example. 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).
|
||||
|
||||
```c++
|
||||
unsigned int Factorial( unsigned int number ) {
|
||||
@@ -33,7 +33,7 @@ unsigned int Factorial( unsigned int number ) {
|
||||
}
|
||||
```
|
||||
|
||||
To keep things simple we'll put everything in a single file (<a href="#scaling-up">see later for more on how to structure your test files</a>)
|
||||
To keep things simple we'll put everything in a single file (<a href="#scaling-up">see later for more on how to structure your test files</a>).
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||
@@ -110,7 +110,7 @@ Most test frameworks have a class-based fixture mechanism. That is, test cases m
|
||||
|
||||
While Catch fully supports this way of working there are a few problems with the approach. In particular the way your code must be split up, and the blunt granularity of it, may cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>).
|
||||
|
||||
Catch takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages. This is best explained through an example:
|
||||
Catch takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages. This is best explained through an example ([code](../examples/100-Fix-Section.cpp)):
|
||||
|
||||
```c++
|
||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||
@@ -175,7 +175,7 @@ Sections can be nested to an arbitrary depth (limited only by your stack size).
|
||||
|
||||
If you name your test cases and sections appropriately you can achieve a BDD-style specification structure. This became such a useful way of working that first class support has been added to Catch. Scenarios can be specified using ```SCENARIO```, ```GIVEN```, ```WHEN``` and ```THEN``` macros, which map on to ```TEST_CASE```s and ```SECTION```s, respectively. For more details see [Test cases and sections](test-cases-and-sections.md#top).
|
||||
|
||||
The vector example can be adjusted to use these macros like so:
|
||||
The vector example can be adjusted to use these macros like so ([example code](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)):
|
||||
|
||||
```c++
|
||||
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
||||
@@ -245,7 +245,7 @@ The requirement is that the following block of code ([or equivalent](own-main.md
|
||||
|
||||
appears in _exactly one_ source file. Use as many additional cpp files (or whatever you call your implementation files) as you need for your tests, partitioned however makes most sense for your way of working. Each additional file need only ```#include "catch.hpp"``` - do not repeat the ```#define```!
|
||||
|
||||
In fact it is usually a good idea to put the block with the ```#define``` [in its own source file](slow-compiles.md#top).
|
||||
In fact it is usually a good idea to put the block with the ```#define``` [in its own source file](slow-compiles.md#top) (code example [main](../examples/020-TestCase-1.cpp), [tests](../examples/020-TestCase-2.cpp)).
|
||||
|
||||
Do not write your tests in header files!
|
||||
|
||||
|
15
examples/000-CatchMain.cpp
Normal file
15
examples/000-CatchMain.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 000-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 "catch.hpp"
|
||||
|
||||
// That's it
|
||||
|
||||
// Compile implementation of Catch for use with files that do contain tests:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -c 000-CatchMain.cpp
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -c 000-CatchMain.cpp
|
36
examples/010-TestCase.cpp
Normal file
36
examples/010-TestCase.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// 010-TestCase.cpp
|
||||
|
||||
// Let Catch provide main():
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
int Factorial( int number ) {
|
||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||
// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) {
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 010-TestCase 010-TestCase.cpp && 010-TestCase --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 010-TestCase.cpp && 010-TestCase --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 010-TestCase --reporter compact --success
|
||||
// 010-TestCase.cpp:14: failed: Factorial(0) == 1 for: 0 == 1
|
||||
// 010-TestCase.cpp:18: passed: Factorial(1) == 1 for: 1 == 1
|
||||
// 010-TestCase.cpp:19: passed: Factorial(2) == 2 for: 2 == 2
|
||||
// 010-TestCase.cpp:20: passed: Factorial(3) == 6 for: 6 == 6
|
||||
// 010-TestCase.cpp:21: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00)
|
||||
// Failed 1 test case, failed 1 assertion.
|
35
examples/020-TestCase-1.cpp
Normal file
35
examples/020-TestCase-1.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// 020-TestCase-1.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 "catch.hpp"
|
||||
|
||||
TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
|
||||
}
|
||||
|
||||
// ^^^
|
||||
// Normally no TEST_CASEs in this file.
|
||||
// Here just to show there are two source files via option --list-tests.
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -c 020-TestCase-1.cpp
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 020-TestCase TestCase-1.o 020-TestCase-2.cpp && 020-TestCase --success
|
||||
//
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -c 020-TestCase-1.cpp
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% -Fe020-TestCase.exe 020-TestCase-1.obj 020-TestCase-2.cpp && 020-TestCase --success
|
||||
|
||||
// Expected test case listing:
|
||||
//
|
||||
// prompt> 020-TestCase --list-tests *
|
||||
// Matching test cases:
|
||||
// 1: All test cases reside in other .cpp files (empty)
|
||||
// [multi-file:1]
|
||||
// 2: Factorial of 0 is computed (fail)
|
||||
// [multi-file:2]
|
||||
// 2: Factorials of 1 and higher are computed (pass)
|
||||
// [multi-file:2]
|
||||
// 3 matching test cases
|
33
examples/020-TestCase-2.cpp
Normal file
33
examples/020-TestCase-2.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// 020-TestCase-2.cpp
|
||||
|
||||
// main() provided by Catch in file 020-TestCase-1.cpp.
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
int Factorial( int number ) {
|
||||
return number <= 1 ? number : Factorial( number - 1 ) * number; // fail
|
||||
// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass
|
||||
}
|
||||
|
||||
TEST_CASE( "2: Factorial of 0 is 1 (fail)", "[multi-file:2]" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
}
|
||||
|
||||
TEST_CASE( "2: Factorials of 1 and higher are computed (pass)", "[multi-file:2]" ) {
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
||||
|
||||
// Compile: see 020-TestCase-1.cpp
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 020-TestCase --reporter compact --success
|
||||
// 020-TestCase-2.cpp:13: failed: Factorial(0) == 1 for: 0 == 1
|
||||
// 020-TestCase-2.cpp:17: passed: Factorial(1) == 1 for: 1 == 1
|
||||
// 020-TestCase-2.cpp:18: passed: Factorial(2) == 2 for: 2 == 2
|
||||
// 020-TestCase-2.cpp:19: passed: Factorial(3) == 6 for: 6 == 6
|
||||
// 020-TestCase-2.cpp:20: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00)
|
||||
// Failed 1 test case, failed 1 assertion.
|
74
examples/030-Asn-Require-Check.cpp
Normal file
74
examples/030-Asn-Require-Check.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// 030-Asn-Require-Check.cpp
|
||||
|
||||
// Catch has two natural expression assertion macro's:
|
||||
// - REQUIRE() stops at first failure.
|
||||
// - CHECK() continues after failure.
|
||||
|
||||
// There are two variants to support decomposing negated expressions:
|
||||
// - REQUIRE_FALSE() stops at first failure.
|
||||
// - CHECK_FALSE() continues after failure.
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
std::string one() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is true (pass)", "[require]" ) {
|
||||
REQUIRE( one() == "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is true (fail)", "[require]" ) {
|
||||
REQUIRE( one() == "x" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is true (stop at first failure)", "[require]" ) {
|
||||
WARN( "REQUIRE stops at first failure:" );
|
||||
|
||||
REQUIRE( one() == "x" );
|
||||
REQUIRE( one() == "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is true (continue after failure)", "[check]" ) {
|
||||
WARN( "CHECK continues after failure:" );
|
||||
|
||||
CHECK( one() == "x" );
|
||||
REQUIRE( one() == "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is false (stops at first failure)", "[require-false]" ) {
|
||||
WARN( "REQUIRE_FALSE stops at first failure:" );
|
||||
|
||||
REQUIRE_FALSE( one() == "1" );
|
||||
REQUIRE_FALSE( one() != "1" );
|
||||
}
|
||||
|
||||
TEST_CASE( "Assert that something is false (continue after failure)", "[check-false]" ) {
|
||||
WARN( "CHECK_FALSE continues after failure:" );
|
||||
|
||||
CHECK_FALSE( one() == "1" );
|
||||
REQUIRE_FALSE( one() != "1" );
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 030-Asn-Require-Check 030-Asn-Require-Check.cpp 000-CatchMain.o && 030-Asn-Require-Check --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 030-Asn-Require-Check.cpp 000-CatchMain.obj && 030-Asn-Require-Check --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 030-Asn-Require-Check.exe --reporter compact --success
|
||||
// 030-Asn-Require-Check.cpp:20: passed: one() == "1" for: "1" == "1"
|
||||
// 030-Asn-Require-Check.cpp:24: failed: one() == "x" for: "1" == "x"
|
||||
// 030-Asn-Require-Check.cpp:28: warning: 'REQUIRE stops at first failure:'
|
||||
// 030-Asn-Require-Check.cpp:30: failed: one() == "x" for: "1" == "x"
|
||||
// 030-Asn-Require-Check.cpp:35: warning: 'CHECK continues after failure:'
|
||||
// 030-Asn-Require-Check.cpp:37: failed: one() == "x" for: "1" == "x"
|
||||
// 030-Asn-Require-Check.cpp:38: passed: one() == "1" for: "1" == "1"
|
||||
// 030-Asn-Require-Check.cpp:42: warning: 'REQUIRE_FALSE stops at first failure:'
|
||||
// 030-Asn-Require-Check.cpp:44: failed: !(one() == "1") for: !("1" == "1")
|
||||
// 030-Asn-Require-Check.cpp:49: warning: 'CHECK_FALSE continues after failure:'
|
||||
// 030-Asn-Require-Check.cpp:51: failed: !(one() == "1") for: !("1" == "1")
|
||||
// 030-Asn-Require-Check.cpp:52: passed: !(one() != "1") for: !("1" != "1")
|
||||
// Failed 5 test cases, failed 5 assertions.
|
69
examples/100-Fix-Section.cpp
Normal file
69
examples/100-Fix-Section.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// 100-Fix-Section.cpp
|
||||
|
||||
// Catch has two ways to express fixtures:
|
||||
// - Sections (this file)
|
||||
// - Traditional class-based fixtures
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
// For each section, vector v is anew:
|
||||
|
||||
std::vector<int> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
SECTION( "resizing bigger changes size and capacity" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "resizing smaller changes size but not capacity" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
SECTION( "reserving bigger changes capacity but not size" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
SECTION( "reserving smaller does not change size or capacity" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 100-Fix-Section 100-Fix-Section.cpp 000-CatchMain.o && 100-Fix-Section --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 100-Fix-Section.cpp 000-CatchMain.obj && 100-Fix-Section --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 100-Fix-Section.exe --reporter compact --success
|
||||
// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 100-Fix-Section.cpp:23: passed: v.size() == 10 for: 10 == 10
|
||||
// 100-Fix-Section.cpp:24: passed: v.capacity() >= 10 for: 10 >= 10
|
||||
// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 100-Fix-Section.cpp:29: passed: v.size() == 0 for: 0 == 0
|
||||
// 100-Fix-Section.cpp:30: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 100-Fix-Section.cpp:35: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:36: passed: v.capacity() >= 10 for: 10 >= 10
|
||||
// 100-Fix-Section.cpp:17: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:18: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 100-Fix-Section.cpp:41: passed: v.size() == 5 for: 5 == 5
|
||||
// 100-Fix-Section.cpp:42: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// Passed 1 test case with 16 assertions.
|
63
examples/110-Fix-ClassFixture.cpp
Normal file
63
examples/110-Fix-ClassFixture.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// 110-Fix-ClassFixture.cpp
|
||||
|
||||
// Catch has two ways to express fixtures:
|
||||
// - Sections
|
||||
// - Traditional class-based fixtures (this file)
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
class DBConnection
|
||||
{
|
||||
public:
|
||||
static DBConnection createConnection( std::string const & /*dbName*/ ) {
|
||||
return DBConnection();
|
||||
}
|
||||
|
||||
bool executeSQL( std::string const & /*query*/, int const /*id*/, std::string const & arg ) {
|
||||
if ( arg.length() == 0 ) {
|
||||
throw std::logic_error("empty SQL query argument");
|
||||
}
|
||||
return true; // ok
|
||||
}
|
||||
};
|
||||
|
||||
class UniqueTestsFixture
|
||||
{
|
||||
protected:
|
||||
UniqueTestsFixture()
|
||||
: conn( DBConnection::createConnection( "myDB" ) )
|
||||
{}
|
||||
|
||||
int getID() {
|
||||
return ++uniqueID;
|
||||
}
|
||||
|
||||
protected:
|
||||
DBConnection conn;
|
||||
|
||||
private:
|
||||
static int uniqueID;
|
||||
};
|
||||
|
||||
int UniqueTestsFixture::uniqueID = 0;
|
||||
|
||||
TEST_CASE_METHOD( UniqueTestsFixture, "Create Employee/No Name", "[create]" ) {
|
||||
REQUIRE_THROWS( conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "") );
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD( UniqueTestsFixture, "Create Employee/Normal", "[create]" ) {
|
||||
REQUIRE( conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "Joe Bloggs" ) );
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 110-Fix-ClassFixture 110-Fix-ClassFixture.cpp 000-CatchMain.o && 110-Fix-ClassFixture --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 110-Fix-ClassFixture.cpp 000-CatchMain.obj && 110-Fix-ClassFixture --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 110-Fix-ClassFixture.exe --reporter compact --success
|
||||
// 110-Fix-ClassFixture.cpp:47: passed: conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "")
|
||||
// 110-Fix-ClassFixture.cpp:51: passed: conn.executeSQL( "INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "Joe Bloggs" ) for: true
|
||||
// Passed both 2 test cases with 2 assertions.
|
73
examples/120-Bdd-ScenarioGivenWhenThen.cpp
Normal file
73
examples/120-Bdd-ScenarioGivenWhenThen.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
SCENARIO( "vectors can be sized and resized", "[vector]" ) {
|
||||
|
||||
GIVEN( "A vector with some items" ) {
|
||||
std::vector<int> v( 5 );
|
||||
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
|
||||
WHEN( "the size is increased" ) {
|
||||
v.resize( 10 );
|
||||
|
||||
THEN( "the size and capacity change" ) {
|
||||
REQUIRE( v.size() == 10 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
}
|
||||
WHEN( "the size is reduced" ) {
|
||||
v.resize( 0 );
|
||||
|
||||
THEN( "the size changes but not capacity" ) {
|
||||
REQUIRE( v.size() == 0 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
WHEN( "more capacity is reserved" ) {
|
||||
v.reserve( 10 );
|
||||
|
||||
THEN( "the capacity changes but not the size" ) {
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 10 );
|
||||
}
|
||||
}
|
||||
WHEN( "less capacity is reserved" ) {
|
||||
v.reserve( 0 );
|
||||
|
||||
THEN( "neither size nor capacity are changed" ) {
|
||||
REQUIRE( v.size() == 5 );
|
||||
REQUIRE( v.capacity() >= 5 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 120-Bdd-ScenarioGivenWhenThen 120-Bdd-ScenarioGivenWhenThen.cpp 000-CatchMain.o && 120-Bdd-ScenarioGivenWhenThen --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 120-Bdd-ScenarioGivenWhenThen.cpp 000-CatchMain.obj && 120-Bdd-ScenarioGivenWhenThen --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 120-Bdd-ScenarioGivenWhenThen.exe --reporter compact --success
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:19: passed: v.size() == 10 for: 10 == 10
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:20: passed: v.capacity() >= 10 for: 10 >= 10
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:27: passed: v.size() == 0 for: 0 == 0
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:28: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:35: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:36: passed: v.capacity() >= 10 for: 10 >= 10
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:12: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:13: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:43: passed: v.size() == 5 for: 5 == 5
|
||||
// 120-Bdd-ScenarioGivenWhenThen.cpp:44: passed: v.capacity() >= 5 for: 5 >= 5
|
||||
// Passed 1 test case with 16 assertions.
|
423
examples/210-Evt-EventListeners.cpp
Normal file
423
examples/210-Evt-EventListeners.cpp
Normal file
@@ -0,0 +1,423 @@
|
||||
// 210-Evt-EventListeners.cpp
|
||||
|
||||
// Contents:
|
||||
// 1. Printing of listener data
|
||||
// 2. My listener and registration
|
||||
// 3. Test cases
|
||||
|
||||
// main() provided in 000-CatchMain.cpp
|
||||
|
||||
// Let Catch provide the required interfaces:
|
||||
#define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <iostream>
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 1. Printing of listener data:
|
||||
//
|
||||
|
||||
std::string ws(int const level) {
|
||||
return std::string( 2 * level, ' ' );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
std::ostream& operator<<( std::ostream& os, std::vector<T> const& v ) {
|
||||
os << "{ ";
|
||||
for ( auto x : v )
|
||||
os << x << ", ";
|
||||
return os << "}";
|
||||
}
|
||||
|
||||
// struct SourceLineInfo {
|
||||
// char const* file;
|
||||
// std::size_t line;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::SourceLineInfo const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- file: " << info.file << "\n"
|
||||
<< ws(level+1) << "- line: " << info.line << "\n";
|
||||
}
|
||||
|
||||
//struct MessageInfo {
|
||||
// std::string macroName;
|
||||
// std::string message;
|
||||
// SourceLineInfo lineInfo;
|
||||
// ResultWas::OfType type;
|
||||
// unsigned int sequence;
|
||||
//};
|
||||
|
||||
void print( std::ostream& os, int const level, Catch::MessageInfo const& info ) {
|
||||
os << ws(level+1) << "- macroName: '" << info.macroName << "'\n"
|
||||
<< ws(level+1) << "- message '" << info.message << "'\n";
|
||||
print( os,level+1 , "- lineInfo", info.lineInfo );
|
||||
os << ws(level+1) << "- sequence " << info.sequence << "\n";
|
||||
}
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, std::vector<Catch::MessageInfo> const& v ) {
|
||||
os << ws(level ) << title << ":\n";
|
||||
for ( auto x : v )
|
||||
{
|
||||
os << ws(level+1) << "{\n";
|
||||
print( os, level+2, x );
|
||||
os << ws(level+1) << "}\n";
|
||||
}
|
||||
// os << ws(level+1) << "\n";
|
||||
}
|
||||
|
||||
// struct TestRunInfo {
|
||||
// std::string name;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunInfo const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- name: " << info.name << "\n";
|
||||
}
|
||||
|
||||
// struct Counts {
|
||||
// std::size_t total() const;
|
||||
// bool allPassed() const;
|
||||
// bool allOk() const;
|
||||
//
|
||||
// std::size_t passed = 0;
|
||||
// std::size_t failed = 0;
|
||||
// std::size_t failedButOk = 0;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::Counts const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- total(): " << info.total() << "\n"
|
||||
<< ws(level+1) << "- allPassed(): " << info.allPassed() << "\n"
|
||||
<< ws(level+1) << "- allOk(): " << info.allOk() << "\n"
|
||||
<< ws(level+1) << "- passed: " << info.passed << "\n"
|
||||
<< ws(level+1) << "- failed: " << info.failed << "\n"
|
||||
<< ws(level+1) << "- failedButOk: " << info.failedButOk << "\n";
|
||||
}
|
||||
|
||||
// struct Totals {
|
||||
// Counts assertions;
|
||||
// Counts testCases;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::Totals const& info ) {
|
||||
os << ws(level) << title << ":\n";
|
||||
print( os, level+1, "- assertions", info.assertions );
|
||||
print( os, level+1, "- testCases" , info.testCases );
|
||||
}
|
||||
|
||||
// struct TestRunStats {
|
||||
// TestRunInfo runInfo;
|
||||
// Totals totals;
|
||||
// bool aborting;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::TestRunStats const& info ) {
|
||||
os << ws(level) << title << ":\n";
|
||||
print( os, level+1 , "- runInfo", info.runInfo );
|
||||
print( os, level+1 , "- totals" , info.totals );
|
||||
os << ws(level+1) << "- aborting: " << info.aborting << "\n";
|
||||
}
|
||||
|
||||
// struct TestCaseInfo {
|
||||
// enum SpecialProperties{
|
||||
// None = 0,
|
||||
// IsHidden = 1 << 1,
|
||||
// ShouldFail = 1 << 2,
|
||||
// MayFail = 1 << 3,
|
||||
// Throws = 1 << 4,
|
||||
// NonPortable = 1 << 5,
|
||||
// Benchmark = 1 << 6
|
||||
// };
|
||||
//
|
||||
// bool isHidden() const;
|
||||
// bool throws() const;
|
||||
// bool okToFail() const;
|
||||
// bool expectedToFail() const;
|
||||
//
|
||||
// std::string tagsAsString() const;
|
||||
//
|
||||
// std::string name;
|
||||
// std::string className;
|
||||
// std::string description;
|
||||
// std::vector<std::string> tags;
|
||||
// std::vector<std::string> lcaseTags;
|
||||
// SourceLineInfo lineInfo;
|
||||
// SpecialProperties properties;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseInfo const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- isHidden(): " << info.isHidden() << "\n"
|
||||
<< ws(level+1) << "- throws(): " << info.throws() << "\n"
|
||||
<< ws(level+1) << "- okToFail(): " << info.okToFail() << "\n"
|
||||
<< ws(level+1) << "- expectedToFail(): " << info.expectedToFail() << "\n"
|
||||
<< ws(level+1) << "- tagsAsString(): '" << info.tagsAsString() << "'\n"
|
||||
<< ws(level+1) << "- name: '" << info.name << "'\n"
|
||||
<< ws(level+1) << "- className: '" << info.className << "'\n"
|
||||
<< ws(level+1) << "- description: '" << info.description << "'\n"
|
||||
<< ws(level+1) << "- tags: " << info.tags << "\n"
|
||||
<< ws(level+1) << "- lcaseTags: " << info.lcaseTags << "\n";
|
||||
print( os, level+1 , "- lineInfo", info.lineInfo );
|
||||
os << ws(level+1) << "- properties (flags): 0x" << std::hex << info.properties << std::dec << "\n";
|
||||
}
|
||||
|
||||
// struct TestCaseStats {
|
||||
// TestCaseInfo testInfo;
|
||||
// Totals totals;
|
||||
// std::string stdOut;
|
||||
// std::string stdErr;
|
||||
// bool aborting;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::TestCaseStats const& info ) {
|
||||
os << ws(level ) << title << ":\n";
|
||||
print( os, level+1 , "- testInfo", info.testInfo );
|
||||
print( os, level+1 , "- totals" , info.totals );
|
||||
os << ws(level+1) << "- stdOut: " << info.stdOut << "\n"
|
||||
<< ws(level+1) << "- stdErr: " << info.stdErr << "\n"
|
||||
<< ws(level+1) << "- aborting: " << info.aborting << "\n";
|
||||
}
|
||||
|
||||
// struct SectionInfo {
|
||||
// std::string name;
|
||||
// std::string description;
|
||||
// SourceLineInfo lineInfo;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- name: " << info.name << "\n"
|
||||
<< ws(level+1) << "- description: '" << info.description << "'\n";
|
||||
print( os, level+1 , "- lineInfo", info.lineInfo );
|
||||
}
|
||||
|
||||
// struct SectionStats {
|
||||
// SectionInfo sectionInfo;
|
||||
// Counts assertions;
|
||||
// double durationInSeconds;
|
||||
// bool missingAssertions;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::SectionStats const& info ) {
|
||||
os << ws(level ) << title << ":\n";
|
||||
print( os, level+1 , "- sectionInfo", info.sectionInfo );
|
||||
print( os, level+1 , "- assertions" , info.assertions );
|
||||
os << ws(level+1) << "- durationInSeconds: " << info.durationInSeconds << "\n"
|
||||
<< ws(level+1) << "- missingAssertions: " << info.missingAssertions << "\n";
|
||||
}
|
||||
|
||||
// struct AssertionInfo
|
||||
// {
|
||||
// StringRef macroName;
|
||||
// SourceLineInfo lineInfo;
|
||||
// StringRef capturedExpression;
|
||||
// ResultDisposition::Flags resultDisposition;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionInfo const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- macroName: '" << info.macroName << "'\n";
|
||||
print( os, level+1 , "- lineInfo" , info.lineInfo );
|
||||
os << ws(level+1) << "- capturedExpression: '" << info.capturedExpression << "'\n"
|
||||
<< ws(level+1) << "- resultDisposition (flags): 0x" << std::hex << info.resultDisposition << std::dec << "\n";
|
||||
}
|
||||
|
||||
//struct AssertionResultData
|
||||
//{
|
||||
// std::string reconstructExpression() const;
|
||||
//
|
||||
// std::string message;
|
||||
// mutable std::string reconstructedExpression;
|
||||
// LazyExpression lazyExpression;
|
||||
// ResultWas::OfType resultType;
|
||||
//};
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResultData const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- reconstructExpression(): '" << info.reconstructExpression() << "'\n"
|
||||
<< ws(level+1) << "- message: '" << info.message << "'\n"
|
||||
<< ws(level+1) << "- lazyExpression: '" << "(info.lazyExpression)" << "'\n"
|
||||
<< ws(level+1) << "- resultType: '" << info.resultType << "'\n";
|
||||
}
|
||||
|
||||
//class AssertionResult {
|
||||
// bool isOk() const;
|
||||
// bool succeeded() const;
|
||||
// ResultWas::OfType getResultType() const;
|
||||
// bool hasExpression() const;
|
||||
// bool hasMessage() const;
|
||||
// std::string getExpression() const;
|
||||
// std::string getExpressionInMacro() const;
|
||||
// bool hasExpandedExpression() const;
|
||||
// std::string getExpandedExpression() const;
|
||||
// std::string getMessage() const;
|
||||
// SourceLineInfo getSourceInfo() const;
|
||||
// std::string getTestMacroName() const;
|
||||
//
|
||||
// AssertionInfo m_info;
|
||||
// AssertionResultData m_resultData;
|
||||
//};
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionResult const& info ) {
|
||||
os << ws(level ) << title << ":\n"
|
||||
<< ws(level+1) << "- isOk(): " << info.isOk() << "\n"
|
||||
<< ws(level+1) << "- succeeded(): " << info.succeeded() << "\n"
|
||||
<< ws(level+1) << "- getResultType(): " << info.getResultType() << "\n"
|
||||
<< ws(level+1) << "- hasExpression(): " << info.hasExpression() << "\n"
|
||||
<< ws(level+1) << "- hasMessage(): " << info.hasMessage() << "\n"
|
||||
<< ws(level+1) << "- getExpression(): '" << info.getExpression() << "'\n"
|
||||
<< ws(level+1) << "- getExpressionInMacro(): '" << info.getExpressionInMacro() << "'\n"
|
||||
<< ws(level+1) << "- hasExpandedExpression(): " << info.hasExpandedExpression() << "\n"
|
||||
<< ws(level+1) << "- getExpandedExpression(): " << info.getExpandedExpression() << "'\n"
|
||||
<< ws(level+1) << "- getMessage(): '" << info.getMessage() << "'\n";
|
||||
print( os, level+1 , "- getSourceInfo(): ", info.getSourceInfo() );
|
||||
os << ws(level+1) << "- getTestMacroName(): '" << info.getTestMacroName() << "'\n";
|
||||
|
||||
// print( os, level+1 , "- *** m_info (AssertionInfo)", info.m_info );
|
||||
// print( os, level+1 , "- *** m_resultData (AssertionResultData)", info.m_resultData );
|
||||
}
|
||||
|
||||
// struct AssertionStats {
|
||||
// AssertionResult assertionResult;
|
||||
// std::vector<MessageInfo> infoMessages;
|
||||
// Totals totals;
|
||||
// };
|
||||
|
||||
void print( std::ostream& os, int const level, std::string const& title, Catch::AssertionStats const& info ) {
|
||||
os << ws(level ) << title << ":\n";
|
||||
print( os, level+1 , "- assertionResult", info.assertionResult );
|
||||
print( os, level+1 , "- infoMessages", info.infoMessages );
|
||||
print( os, level+1 , "- totals", info.totals );
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 2. My listener and registration:
|
||||
//
|
||||
|
||||
char const * dashed_line =
|
||||
"--------------------------------------------------------------------------";
|
||||
|
||||
struct MyListener : Catch::TestEventListenerBase {
|
||||
|
||||
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
|
||||
|
||||
// Get rid of Wweak-tables
|
||||
~MyListener();
|
||||
|
||||
// The whole test run starting
|
||||
virtual void testRunStarting( Catch::TestRunInfo const& testRunInfo ) override {
|
||||
std::cout
|
||||
<< std::boolalpha
|
||||
<< "\nEvent: testRunStarting:\n";
|
||||
print( std::cout, 1, "- testRunInfo", testRunInfo );
|
||||
}
|
||||
|
||||
// The whole test run ending
|
||||
virtual void testRunEnded( Catch::TestRunStats const& testRunStats ) override {
|
||||
std::cout
|
||||
<< dashed_line
|
||||
<< "\nEvent: testRunEnded:\n";
|
||||
print( std::cout, 1, "- testRunStats", testRunStats );
|
||||
}
|
||||
|
||||
// A test is being skipped (because it is "hidden")
|
||||
virtual void skipTest( Catch::TestCaseInfo const& testInfo ) override {
|
||||
std::cout
|
||||
<< dashed_line
|
||||
<< "\nEvent: skipTest:\n";
|
||||
print( std::cout, 1, "- testInfo", testInfo );
|
||||
}
|
||||
|
||||
// Test cases starting
|
||||
virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
|
||||
std::cout
|
||||
<< dashed_line
|
||||
<< "\nEvent: testCaseStarting:\n";
|
||||
print( std::cout, 1, "- testInfo", testInfo );
|
||||
}
|
||||
|
||||
// Test cases ending
|
||||
virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
|
||||
std::cout << "\nEvent: testCaseEnded:\n";
|
||||
print( std::cout, 1, "testCaseStats", testCaseStats );
|
||||
}
|
||||
|
||||
// Sections starting
|
||||
virtual void sectionStarting( Catch::SectionInfo const& sectionInfo ) override {
|
||||
std::cout << "\nEvent: sectionStarting:\n";
|
||||
print( std::cout, 1, "- sectionInfo", sectionInfo );
|
||||
}
|
||||
|
||||
// Sections ending
|
||||
virtual void sectionEnded( Catch::SectionStats const& sectionStats ) override {
|
||||
std::cout << "\nEvent: sectionEnded:\n";
|
||||
print( std::cout, 1, "- sectionStats", sectionStats );
|
||||
}
|
||||
|
||||
// Assertions before/ after
|
||||
virtual void assertionStarting( Catch::AssertionInfo const& assertionInfo ) override {
|
||||
std::cout << "\nEvent: assertionStarting:\n";
|
||||
print( std::cout, 1, "- assertionInfo", assertionInfo );
|
||||
}
|
||||
|
||||
virtual bool assertionEnded( Catch::AssertionStats const& assertionStats ) override {
|
||||
std::cout << "\nEvent: assertionEnded:\n";
|
||||
print( std::cout, 1, "- assertionStats", assertionStats );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CATCH_REGISTER_LISTENER( MyListener )
|
||||
|
||||
// Get rid of Wweak-tables
|
||||
MyListener::~MyListener() {}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// 3. Test cases:
|
||||
//
|
||||
|
||||
TEST_CASE( "1: Hidden testcase", "[.hidden]" ) {
|
||||
}
|
||||
|
||||
TEST_CASE( "2: Testcase with sections", "[tag-A][tag-B]" ) {
|
||||
|
||||
int i = 42;
|
||||
|
||||
REQUIRE( i == 42 );
|
||||
|
||||
SECTION("Section 1") {
|
||||
INFO("Section 1")
|
||||
i = 7;
|
||||
SECTION("Section 1.1") {
|
||||
INFO("Section 1.1")
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Section 2") {
|
||||
INFO("Section 2")
|
||||
REQUIRE( i == 42 );
|
||||
}
|
||||
WARN("At end of test case");
|
||||
}
|
||||
|
||||
struct Fixture {
|
||||
int fortytwo() const {
|
||||
return 42;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD( Fixture, "3: Testcase with class-based fixture", "[tag-C][tag-D]" ) {
|
||||
REQUIRE( fortytwo() == 42 );
|
||||
}
|
||||
|
||||
// Compile & run:
|
||||
// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 210-Evt-EventListeners 210-Evt-EventListeners.cpp 000-CatchMain.o && 210-Evt-EventListeners --success
|
||||
// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 210-Evt-EventListeners.cpp 000-CatchMain.obj && 210-Evt-EventListeners --success
|
||||
|
||||
// Expected compact output (all assertions):
|
||||
//
|
||||
// prompt> 210-Evt-EventListeners --reporter compact --success
|
||||
// result omitted for brevity.
|
100
examples/CMakeLists.txt
Normal file
100
examples/CMakeLists.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# Build examples.
|
||||
#
|
||||
# Requires CATCH_BUILD_EXAMPLES to be defined 'true', see ../CMakeLists.txt.
|
||||
#
|
||||
|
||||
cmake_minimum_required( VERSION 3.0 )
|
||||
|
||||
project( CatchExamples CXX )
|
||||
|
||||
# define folders used:
|
||||
|
||||
set( EXAMPLES_DIR ${CATCH_DIR}/examples )
|
||||
set( HEADER_DIR ${CATCH_DIR}/single_include )
|
||||
|
||||
# single-file sources:
|
||||
|
||||
set( SOURCES_SINGLE_FILE
|
||||
010-TestCase.cpp
|
||||
)
|
||||
|
||||
# multiple-file modules:
|
||||
|
||||
set( SOURCES_020
|
||||
020-TestCase-1.cpp
|
||||
020-TestCase-2.cpp
|
||||
)
|
||||
|
||||
# main for idiomatic test sources:
|
||||
|
||||
set( SOURCES_IDIOMATIC_MAIN
|
||||
000-CatchMain.cpp
|
||||
)
|
||||
|
||||
# sources to combine with 000-CatchMain.cpp:
|
||||
|
||||
set( SOURCES_IDIOMATIC_TESTS
|
||||
030-Asn-Require-Check.cpp
|
||||
100-Fix-Section.cpp
|
||||
110-Fix-ClassFixture.cpp
|
||||
120-Bdd-ScenarioGivenWhenThen.cpp
|
||||
210-Evt-EventListeners.cpp
|
||||
)
|
||||
|
||||
# check if all sources are listed, warn if not:
|
||||
|
||||
set( SOURCES_ALL
|
||||
${SOURCES_020}
|
||||
${SOURCES_SINGLE_FILE}
|
||||
${SOURCES_IDIOMATIC_MAIN}
|
||||
${SOURCES_IDIOMATIC_TESTS}
|
||||
)
|
||||
|
||||
foreach( name ${SOURCES_ALL} )
|
||||
list( APPEND SOURCES_ALL_PATH ${EXAMPLES_DIR}/${name} )
|
||||
endforeach()
|
||||
|
||||
CheckFileList( SOURCES_ALL_PATH ${EXAMPLES_DIR} )
|
||||
|
||||
# create target names:
|
||||
|
||||
string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE "${SOURCES_SINGLE_FILE}" )
|
||||
string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
|
||||
|
||||
set( TARGETS_SINGLE_FILE ${BASENAMES_SINGLE_FILE} )
|
||||
set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
|
||||
set( TARGETS_ALL ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 020-TestCase CatchMain )
|
||||
|
||||
# define program targets:
|
||||
|
||||
add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch.hpp )
|
||||
|
||||
add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch.hpp )
|
||||
|
||||
foreach( name ${TARGETS_SINGLE_FILE} )
|
||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch.hpp )
|
||||
endforeach()
|
||||
|
||||
foreach( name ${TARGETS_IDIOMATIC_TESTS} )
|
||||
add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch.hpp )
|
||||
endforeach()
|
||||
|
||||
foreach( name ${TARGETS_ALL} )
|
||||
target_include_directories( ${name} PRIVATE ${HEADER_DIR} )
|
||||
|
||||
set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
|
||||
|
||||
# Add desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( ${name} PRIVATE -Wall -Wextra -Wunreachable-code )
|
||||
endif()
|
||||
# Clang specific warning go here
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||
# Actually keep these
|
||||
target_compile_options( ${name} PRIVATE -Wweak-vtables -Wexit-time-destructors -Wglobal-constructors -Wmissing-noreturn )
|
||||
endif()
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
|
||||
target_compile_options( ${name} PRIVATE /W4 /w44265 /WX )
|
||||
endif()
|
||||
endforeach()
|
@@ -9,6 +9,10 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
||||
#define CATCH_VERSION_MAJOR 2
|
||||
#define CATCH_VERSION_MINOR 2
|
||||
#define CATCH_VERSION_PATCH 2
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang system_header
|
||||
#elif defined __GNUC__
|
||||
@@ -19,12 +23,20 @@
|
||||
|
||||
#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
|
||||
# define CATCH_IMPL
|
||||
# define CATCH_CONFIG_ALL_PARTS
|
||||
#endif
|
||||
|
||||
// In the impl file, we want to have access to all parts of the headers
|
||||
// Can also be used to sanely support PCHs
|
||||
#if defined(CATCH_CONFIG_ALL_PARTS)
|
||||
# define CATCH_CONFIG_EXTERNAL_INTERFACES
|
||||
# if defined(CATCH_CONFIG_DISABLE_MATCHERS)
|
||||
# undef CATCH_CONFIG_DISABLE_MATCHERS
|
||||
# endif
|
||||
# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||
#include "internal/catch_platform.h"
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
@@ -34,6 +46,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "internal/catch_user_interfaces.h"
|
||||
#include "internal/catch_tag_alias_autoregistrar.h"
|
||||
#include "internal/catch_test_registry.h"
|
||||
#include "internal/catch_capture.hpp"
|
||||
@@ -61,6 +74,8 @@
|
||||
#include "internal/catch_external_interfaces.h"
|
||||
#endif
|
||||
|
||||
#endif // ! CATCH_CONFIG_IMPL_ONLY
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
#include "internal/catch_impl.hpp"
|
||||
#endif
|
||||
@@ -69,6 +84,7 @@
|
||||
#include "internal/catch_default_main.hpp"
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_CONFIG_IMPL_ONLY)
|
||||
|
||||
#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
|
||||
# undef CLARA_CONFIG_MAIN
|
||||
@@ -327,6 +343,8 @@ using Catch::Detail::Approx;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ! CATCH_CONFIG_IMPL_ONLY
|
||||
|
||||
#include "internal/catch_reenable_warnings.h"
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_HPP_INCLUDED
|
||||
|
173
include/external/clara.hpp
vendored
173
include/external/clara.hpp
vendored
@@ -1,5 +1,11 @@
|
||||
// v1.0
|
||||
// See https://github.com/philsquared/Clara
|
||||
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||
//
|
||||
// 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.4
|
||||
|
||||
#ifndef CATCH_CLARA_HPP_INCLUDED
|
||||
#define CATCH_CLARA_HPP_INCLUDED
|
||||
@@ -12,6 +18,16 @@
|
||||
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
||||
#endif
|
||||
|
||||
#ifndef CLARA_CONFIG_OPTIONAL_TYPE
|
||||
#ifdef __has_include
|
||||
#if __has_include(<optional>) && __cplusplus >= 201703L
|
||||
#include <optional>
|
||||
#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// ----------- #included from clara_textflow.hpp -----------
|
||||
|
||||
// TextFlowCpp
|
||||
@@ -370,7 +386,7 @@ namespace detail {
|
||||
template<typename ClassT, typename ReturnT, typename ArgT>
|
||||
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -383,11 +399,9 @@ namespace detail {
|
||||
std::vector<std::string> m_args;
|
||||
|
||||
public:
|
||||
Args( int argc, char *argv[] ) {
|
||||
m_exeName = argv[0];
|
||||
for( int i = 1; i < argc; ++i )
|
||||
m_args.push_back( argv[i] );
|
||||
}
|
||||
Args( int argc, char const* const* argv )
|
||||
: m_exeName(argv[0]),
|
||||
m_args(argv + 1, argv + argc) {}
|
||||
|
||||
Args( std::initializer_list<std::string> args )
|
||||
: m_exeName( *args.begin() ),
|
||||
@@ -409,6 +423,14 @@ namespace detail {
|
||||
std::string token;
|
||||
};
|
||||
|
||||
inline auto isOptPrefix( char c ) -> bool {
|
||||
return c == '-'
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
|| c == '/'
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
|
||||
class TokenStream {
|
||||
using Iterator = std::vector<std::string>::const_iterator;
|
||||
@@ -425,7 +447,7 @@ namespace detail {
|
||||
|
||||
if( it != itEnd ) {
|
||||
auto const &next = *it;
|
||||
if( next[0] == '-' || next[0] == '/' ) {
|
||||
if( isOptPrefix( next[0] ) ) {
|
||||
auto delimiterPos = next.find_first_of( " :=" );
|
||||
if( delimiterPos != std::string::npos ) {
|
||||
m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
|
||||
@@ -527,7 +549,7 @@ namespace detail {
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ResultValueBase() {
|
||||
~ResultValueBase() override {
|
||||
if( m_type == Ok )
|
||||
m_value.~T();
|
||||
}
|
||||
@@ -565,16 +587,14 @@ namespace detail {
|
||||
auto errorMessage() const -> std::string { return m_errorMessage; }
|
||||
|
||||
protected:
|
||||
virtual void enforceOk() const {
|
||||
// !TBD: If no exceptions, std::terminate here or something
|
||||
switch( m_type ) {
|
||||
case ResultBase::LogicError:
|
||||
throw std::logic_error( m_errorMessage );
|
||||
case ResultBase::RuntimeError:
|
||||
throw std::runtime_error( m_errorMessage );
|
||||
case ResultBase::Ok:
|
||||
break;
|
||||
}
|
||||
void enforceOk() const override {
|
||||
|
||||
// Errors shouldn't reach this point, but if they do
|
||||
// the actual error message will be in m_errorMessage
|
||||
assert( m_type != ResultBase::LogicError );
|
||||
assert( m_type != ResultBase::RuntimeError );
|
||||
if( m_type != ResultBase::Ok )
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::string m_errorMessage; // Only populated if resultType is an error
|
||||
@@ -644,47 +664,43 @@ namespace detail {
|
||||
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
}
|
||||
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
|
||||
template<typename T>
|
||||
inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
|
||||
T temp;
|
||||
auto result = convertInto( source, temp );
|
||||
if( result )
|
||||
target = std::move(temp);
|
||||
return result;
|
||||
}
|
||||
#endif // CLARA_CONFIG_OPTIONAL_TYPE
|
||||
|
||||
struct BoundRefBase {
|
||||
BoundRefBase() = default;
|
||||
BoundRefBase( BoundRefBase const & ) = delete;
|
||||
BoundRefBase( BoundRefBase && ) = delete;
|
||||
BoundRefBase &operator=( BoundRefBase const & ) = delete;
|
||||
BoundRefBase &operator=( BoundRefBase && ) = delete;
|
||||
struct NonCopyable {
|
||||
NonCopyable() = default;
|
||||
NonCopyable( NonCopyable const & ) = delete;
|
||||
NonCopyable( NonCopyable && ) = delete;
|
||||
NonCopyable &operator=( NonCopyable const & ) = delete;
|
||||
NonCopyable &operator=( NonCopyable && ) = delete;
|
||||
};
|
||||
|
||||
virtual ~BoundRefBase() = default;
|
||||
|
||||
virtual auto isFlag() const -> bool = 0;
|
||||
struct BoundRef : NonCopyable {
|
||||
virtual ~BoundRef() = default;
|
||||
virtual auto isContainer() const -> bool { return false; }
|
||||
virtual auto isFlag() const -> bool { return false; }
|
||||
};
|
||||
struct BoundValueRefBase : BoundRef {
|
||||
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
|
||||
};
|
||||
struct BoundFlagRefBase : BoundRef {
|
||||
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
virtual auto isFlag() const -> bool { return true; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BoundRef : BoundValueRefBase {
|
||||
struct BoundValueRef : BoundValueRefBase {
|
||||
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 {
|
||||
return convertInto( arg, m_ref );
|
||||
@@ -692,10 +708,10 @@ namespace detail {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
||||
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
|
||||
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; }
|
||||
|
||||
@@ -740,12 +756,12 @@ namespace detail {
|
||||
|
||||
template<typename ArgType, typename L>
|
||||
inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
|
||||
ArgType temp;
|
||||
ArgType temp{};
|
||||
auto result = convertInto( arg, temp );
|
||||
return !result
|
||||
? result
|
||||
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template<typename L>
|
||||
@@ -795,6 +811,9 @@ namespace detail {
|
||||
public:
|
||||
template<typename T>
|
||||
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
|
||||
@@ -802,16 +821,16 @@ namespace detail {
|
||||
class ParserRefImpl : public ComposableParserImpl<DerivedT> {
|
||||
protected:
|
||||
Optionality m_optionality = Optionality::Optional;
|
||||
std::shared_ptr<BoundRefBase> m_ref;
|
||||
std::shared_ptr<BoundRef> m_ref;
|
||||
std::string m_hint;
|
||||
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:
|
||||
template<typename T>
|
||||
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 )
|
||||
{}
|
||||
|
||||
@@ -852,10 +871,10 @@ namespace detail {
|
||||
|
||||
class ExeName : public ComposableParserImpl<ExeName> {
|
||||
std::shared_ptr<std::string> m_name;
|
||||
std::shared_ptr<BoundRefBase> m_ref;
|
||||
std::shared_ptr<BoundValueRefBase> m_ref;
|
||||
|
||||
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) ;
|
||||
}
|
||||
|
||||
@@ -863,7 +882,7 @@ namespace detail {
|
||||
ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
|
||||
|
||||
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>
|
||||
@@ -906,7 +925,10 @@ namespace detail {
|
||||
if( token.type != TokenType::Argument )
|
||||
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 )
|
||||
return InternalParseResult( result );
|
||||
else
|
||||
@@ -915,9 +937,11 @@ namespace detail {
|
||||
};
|
||||
|
||||
inline auto normaliseOpt( std::string const &optName ) -> std::string {
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
if( optName[0] == '/' )
|
||||
return "-" + optName.substr( 1 );
|
||||
else
|
||||
#endif
|
||||
return optName;
|
||||
}
|
||||
|
||||
@@ -958,11 +982,7 @@ namespace detail {
|
||||
}
|
||||
|
||||
auto isMatch( std::string const &optToken ) const -> bool {
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
auto normalisedToken = normaliseOpt( optToken );
|
||||
#else
|
||||
auto const &normalisedToken = optToken;
|
||||
#endif
|
||||
for( auto const &name : m_optNames ) {
|
||||
if( normaliseOpt( name ) == normalisedToken )
|
||||
return true;
|
||||
@@ -982,19 +1002,21 @@ namespace detail {
|
||||
auto const &token = *remainingTokens;
|
||||
if( isMatch(token.token ) ) {
|
||||
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 )
|
||||
return InternalParseResult( result );
|
||||
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
||||
} else {
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
|
||||
++remainingTokens;
|
||||
if( !remainingTokens )
|
||||
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||
auto const &argToken = *remainingTokens;
|
||||
if( argToken.type != TokenType::Argument )
|
||||
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||
auto result = m_ref->setValue( argToken.token );
|
||||
auto result = valueRef->setValue( argToken.token );
|
||||
if( !result )
|
||||
return InternalParseResult( result );
|
||||
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||
@@ -1012,8 +1034,13 @@ namespace detail {
|
||||
for( auto const &name : m_optNames ) {
|
||||
if( name.empty() )
|
||||
return Result::logicError( "Option name cannot be empty" );
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
if( name[0] != '-' && name[0] != '/' )
|
||||
return Result::logicError( "Option name must begin with '-' or '/'" );
|
||||
#else
|
||||
if( name[0] != '-' )
|
||||
return Result::logicError( "Option name must begin with '-'" );
|
||||
#endif
|
||||
}
|
||||
return ParserRefImpl::validate();
|
||||
}
|
||||
@@ -1066,6 +1093,12 @@ namespace detail {
|
||||
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> {
|
||||
std::vector<HelpColumns> cols;
|
||||
for (auto const &o : m_options) {
|
||||
@@ -1103,7 +1136,9 @@ namespace detail {
|
||||
size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
|
||||
size_t optWidth = 0;
|
||||
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 ) {
|
||||
auto row =
|
||||
|
@@ -8,22 +8,26 @@
|
||||
|
||||
#include "catch_approx.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool marginComparison(double lhs, double rhs, double margin) {
|
||||
return (lhs + margin >= rhs) && (rhs + margin >= lhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double max(double lhs, double rhs) {
|
||||
if (lhs < rhs) {
|
||||
return rhs;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Approx::Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_margin( 0.0 ),
|
||||
m_scale( 1.0 ),
|
||||
m_scale( 0.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
|
||||
@@ -32,9 +36,15 @@ namespace Detail {
|
||||
}
|
||||
|
||||
std::string Approx::toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
return oss.str();
|
||||
ReusableStringStream rss;
|
||||
rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
|
||||
return rss.str();
|
||||
}
|
||||
|
||||
bool Approx::equalityComparisonImpl(const double other) const {
|
||||
// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
|
||||
// Thanks to Richard Harris for his help refining the scaled margin value
|
||||
return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
|
||||
}
|
||||
|
||||
} // end namespace Detail
|
||||
|
@@ -10,16 +10,16 @@
|
||||
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
double max(double lhs, double rhs);
|
||||
|
||||
class Approx {
|
||||
private:
|
||||
bool equalityComparisonImpl(double other) const;
|
||||
|
||||
public:
|
||||
explicit Approx ( double value );
|
||||
|
||||
@@ -41,13 +41,8 @@ namespace Detail {
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
||||
// Thanks to Richard Harris for his help refining this formula
|
||||
auto lhs_v = static_cast<double>(lhs);
|
||||
bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
|
||||
if (relativeOK) {
|
||||
return true;
|
||||
}
|
||||
return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin;
|
||||
return rhs.equalityComparisonImpl(lhs_v);
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
@@ -87,13 +82,28 @@ namespace Detail {
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& epsilon( T const& newEpsilon ) {
|
||||
m_epsilon = static_cast<double>(newEpsilon);
|
||||
double epsilonAsDouble = static_cast<double>(newEpsilon);
|
||||
if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& margin( T const& newMargin ) {
|
||||
m_margin = static_cast<double>(newMargin);
|
||||
double marginAsDouble = static_cast<double>(newMargin);
|
||||
if( marginAsDouble < 0 ) {
|
||||
throw std::domain_error
|
||||
( "Invalid Approx::margin: " +
|
||||
Catch::Detail::stringify( marginAsDouble ) +
|
||||
", Approx::Margin has to be non-negative." );
|
||||
|
||||
}
|
||||
m_margin = marginAsDouble;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -8,15 +8,13 @@
|
||||
|
||||
#include "catch_assertionhandler.h"
|
||||
#include "catch_assertionresult.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_interfaces_runner.h"
|
||||
#include "catch_interfaces_config.h"
|
||||
#include "catch_context.h"
|
||||
#include "catch_debugger.h"
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
#include "catch_capture_matchers.h"
|
||||
|
||||
#include <cassert>
|
||||
#include "catch_run_context.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -56,86 +54,55 @@ namespace Catch {
|
||||
SourceLineInfo const& lineInfo,
|
||||
StringRef capturedExpression,
|
||||
ResultDisposition::Flags resultDisposition )
|
||||
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }
|
||||
{
|
||||
getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo );
|
||||
: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
|
||||
m_resultCapture( getResultCapture() )
|
||||
{}
|
||||
|
||||
void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
|
||||
m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
|
||||
}
|
||||
AssertionHandler::~AssertionHandler() {
|
||||
if ( m_inExceptionGuard ) {
|
||||
handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" );
|
||||
getCurrentContext().getResultCapture()->exceptionEarlyReported();
|
||||
}
|
||||
}
|
||||
|
||||
void AssertionHandler::handle( ITransientExpression const& expr ) {
|
||||
|
||||
bool negated = isFalseTest( m_assertionInfo.resultDisposition );
|
||||
bool result = expr.getResult() != negated;
|
||||
|
||||
handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType ) {
|
||||
handle( resultType, nullptr, false );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) {
|
||||
AssertionResultData data( resultType, LazyExpression( false ) );
|
||||
data.message = message;
|
||||
handle( data, nullptr );
|
||||
}
|
||||
void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) {
|
||||
AssertionResultData data( resultType, LazyExpression( negated ) );
|
||||
handle( data, expr );
|
||||
}
|
||||
void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) {
|
||||
|
||||
getResultCapture().assertionRun();
|
||||
|
||||
AssertionResult assertionResult{ m_assertionInfo, resultData };
|
||||
assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
|
||||
|
||||
getResultCapture().assertionEnded( assertionResult );
|
||||
|
||||
if( !assertionResult.isOk() ) {
|
||||
m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak();
|
||||
m_shouldThrow =
|
||||
getCurrentContext().getRunner()->aborting() ||
|
||||
(m_assertionInfo.resultDisposition & ResultDisposition::Normal);
|
||||
}
|
||||
void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {
|
||||
m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
|
||||
}
|
||||
|
||||
auto AssertionHandler::allowThrows() const -> bool {
|
||||
return getCurrentContext().getConfig()->allowThrows();
|
||||
}
|
||||
|
||||
auto AssertionHandler::shouldDebugBreak() const -> bool {
|
||||
return m_shouldDebugBreak;
|
||||
}
|
||||
void AssertionHandler::reactWithDebugBreak() const {
|
||||
if (m_shouldDebugBreak) {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// To inspect the state during test, you need to go one level up the callstack
|
||||
// To go back to the test and change execution, jump over the reactWithoutDebugBreak() call
|
||||
///////////////////////////////////////////////////////////////////
|
||||
void AssertionHandler::complete() {
|
||||
setCompleted();
|
||||
if( m_reaction.shouldDebugBreak ) {
|
||||
|
||||
// If you find your debugger stopping you here then go one level up on the
|
||||
// call-stack for the code that caused it (typically a failed assertion)
|
||||
|
||||
// (To go back to the test and change execution, jump over the throw, next)
|
||||
CATCH_BREAK_INTO_DEBUGGER();
|
||||
}
|
||||
reactWithoutDebugBreak();
|
||||
}
|
||||
void AssertionHandler::reactWithoutDebugBreak() const {
|
||||
if( m_shouldThrow )
|
||||
if( m_reaction.shouldThrow )
|
||||
throw Catch::TestFailureException();
|
||||
}
|
||||
|
||||
void AssertionHandler::useActiveException() {
|
||||
handle( ResultWas::ThrewException, Catch::translateActiveException() );
|
||||
void AssertionHandler::setCompleted() {
|
||||
m_completed = true;
|
||||
}
|
||||
|
||||
void AssertionHandler::setExceptionGuard() {
|
||||
assert( m_inExceptionGuard == false );
|
||||
m_inExceptionGuard = true;
|
||||
void AssertionHandler::handleUnexpectedInflightException() {
|
||||
m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
|
||||
}
|
||||
void AssertionHandler::unsetExceptionGuard() {
|
||||
assert( m_inExceptionGuard == true );
|
||||
m_inExceptionGuard = false;
|
||||
|
||||
void AssertionHandler::handleExceptionThrownAsExpected() {
|
||||
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||
}
|
||||
void AssertionHandler::handleExceptionNotThrownAsExpected() {
|
||||
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||
}
|
||||
|
||||
void AssertionHandler::handleUnexpectedExceptionNotThrown() {
|
||||
m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
|
||||
}
|
||||
|
||||
void AssertionHandler::handleThrowingCallSkipped() {
|
||||
m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
|
||||
}
|
||||
|
||||
// This is the overload that takes a string and infers the Equals matcher from it
|
||||
|
@@ -8,17 +8,21 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ASSERTIONHANDLER_H_INCLUDED
|
||||
|
||||
#include "catch_decomposer.h"
|
||||
#include "catch_assertioninfo.h"
|
||||
#include "catch_decomposer.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct TestFailureException{};
|
||||
struct AssertionResultData;
|
||||
struct IResultCapture;
|
||||
class RunContext;
|
||||
|
||||
class LazyExpression {
|
||||
friend class AssertionHandler;
|
||||
friend struct AssertionStats;
|
||||
friend class RunContext;
|
||||
|
||||
ITransientExpression const* m_transientExpression = nullptr;
|
||||
bool m_isNegated;
|
||||
@@ -32,11 +36,16 @@ namespace Catch {
|
||||
friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
|
||||
};
|
||||
|
||||
struct AssertionReaction {
|
||||
bool shouldDebugBreak = false;
|
||||
bool shouldThrow = false;
|
||||
};
|
||||
|
||||
class AssertionHandler {
|
||||
AssertionInfo m_assertionInfo;
|
||||
bool m_shouldDebugBreak = false;
|
||||
bool m_shouldThrow = false;
|
||||
bool m_inExceptionGuard = false;
|
||||
AssertionReaction m_reaction;
|
||||
bool m_completed = false;
|
||||
IResultCapture& m_resultCapture;
|
||||
|
||||
public:
|
||||
AssertionHandler
|
||||
@@ -44,26 +53,32 @@ namespace Catch {
|
||||
SourceLineInfo const& lineInfo,
|
||||
StringRef capturedExpression,
|
||||
ResultDisposition::Flags resultDisposition );
|
||||
~AssertionHandler();
|
||||
~AssertionHandler() {
|
||||
if ( !m_completed ) {
|
||||
m_resultCapture.handleIncomplete( m_assertionInfo );
|
||||
}
|
||||
}
|
||||
|
||||
void handle( ITransientExpression const& expr );
|
||||
|
||||
template<typename T>
|
||||
void handle( ExprLhs<T> const& expr ) {
|
||||
handle( expr.makeUnaryExpr() );
|
||||
void handleExpr( ExprLhs<T> const& expr ) {
|
||||
handleExpr( expr.makeUnaryExpr() );
|
||||
}
|
||||
void handle( ResultWas::OfType resultType );
|
||||
void handle( ResultWas::OfType resultType, StringRef const& message );
|
||||
void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated );
|
||||
void handle( AssertionResultData const& resultData, ITransientExpression const* expr );
|
||||
void handleExpr( ITransientExpression const& expr );
|
||||
|
||||
auto shouldDebugBreak() const -> bool;
|
||||
void handleMessage(ResultWas::OfType resultType, StringRef const& message);
|
||||
|
||||
void handleExceptionThrownAsExpected();
|
||||
void handleUnexpectedExceptionNotThrown();
|
||||
void handleExceptionNotThrownAsExpected();
|
||||
void handleThrowingCallSkipped();
|
||||
void handleUnexpectedInflightException();
|
||||
|
||||
void complete();
|
||||
void setCompleted();
|
||||
|
||||
// query
|
||||
auto allowThrows() const -> bool;
|
||||
void reactWithDebugBreak() const;
|
||||
void reactWithoutDebugBreak() const;
|
||||
void useActiveException();
|
||||
void setExceptionGuard();
|
||||
void unsetExceptionGuard();
|
||||
};
|
||||
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
|
||||
|
@@ -17,10 +17,9 @@ namespace Catch {
|
||||
|
||||
if( reconstructedExpression.empty() ) {
|
||||
if( lazyExpression ) {
|
||||
// !TBD Use stringstream for now, but rework above to pass stream in
|
||||
std::ostringstream oss;
|
||||
oss << lazyExpression;
|
||||
reconstructedExpression = oss.str();
|
||||
ReusableStringStream rss;
|
||||
rss << lazyExpression;
|
||||
reconstructedExpression = rss.str();
|
||||
}
|
||||
}
|
||||
return reconstructedExpression;
|
||||
@@ -54,8 +53,8 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
if (isFalseTest(m_info.resultDisposition))
|
||||
return '!' + std::string(m_info.capturedExpression);
|
||||
if( isFalseTest( m_info.resultDisposition ) )
|
||||
return "!(" + m_info.capturedExpression + ")";
|
||||
else
|
||||
return m_info.capturedExpression;
|
||||
}
|
||||
@@ -92,7 +91,7 @@ namespace Catch {
|
||||
return m_info.lineInfo;
|
||||
}
|
||||
|
||||
std::string AssertionResult::getTestMacroName() const {
|
||||
StringRef AssertionResult::getTestMacroName() const {
|
||||
return m_info.macroName;
|
||||
}
|
||||
|
||||
|
@@ -47,7 +47,7 @@ namespace Catch {
|
||||
std::string getExpandedExpression() const;
|
||||
std::string getMessage() const;
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
std::string getTestMacroName() const;
|
||||
StringRef getTestMacroName() const;
|
||||
|
||||
//protected:
|
||||
AssertionInfo m_info;
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include "catch_assertionhandler.h"
|
||||
#include "catch_message.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_debugger.h"
|
||||
|
||||
#if !defined(CATCH_CONFIG_DISABLE)
|
||||
|
||||
@@ -22,48 +21,33 @@
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// We can speedup compilation significantly by breaking into debugger lower in
|
||||
// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER
|
||||
// macro in each assertion
|
||||
#define INTERNAL_CATCH_REACT( handler ) \
|
||||
handler.reactWithDebugBreak();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
|
||||
// macros.
|
||||
// This can potentially cause false negative, if the test code catches
|
||||
// the exception before it propagates back up to the runner.
|
||||
#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard();
|
||||
#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard();
|
||||
#define INTERNAL_CATCH_TRY
|
||||
#define INTERNAL_CATCH_CATCH( capturer )
|
||||
|
||||
#else // CATCH_CONFIG_FAST_COMPILE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// In the event of a failure works out if the debugger needs to be invoked
|
||||
// and/or an exception thrown and takes appropriate action.
|
||||
// This needs to be done as a macro so the debugger will stop in the user
|
||||
// source code rather than in Catch library code
|
||||
#define INTERNAL_CATCH_REACT( handler ) \
|
||||
if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
||||
handler.reactWithoutDebugBreak();
|
||||
|
||||
#define INTERNAL_CATCH_TRY( capturer ) try
|
||||
#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); }
|
||||
#define INTERNAL_CATCH_TRY try
|
||||
#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
|
||||
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_REACT( handler ) handler.complete();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
|
||||
INTERNAL_CATCH_TRY { \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||
catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::isTrue( false && static_cast<bool>( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -82,13 +66,13 @@
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
catchAssertionHandler.handleUnexpectedInflightException(); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
|
||||
@@ -97,15 +81,15 @@
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleExceptionThrownAsExpected(); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
||||
@@ -114,31 +98,31 @@
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(expr); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||
} \
|
||||
catch( exceptionType const& ) { \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleExceptionThrownAsExpected(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
catchAssertionHandler.handleUnexpectedInflightException(); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
catchAssertionHandler.handle( 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 ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#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_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Although this is matcher-based, it can be used with just a string
|
||||
@@ -148,15 +132,15 @@
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
|
||||
Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
#endif // CATCH_CONFIG_DISABLE
|
||||
|
||||
|
@@ -13,12 +13,12 @@ namespace Catch {
|
||||
using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
|
||||
|
||||
// This is the general overload that takes a any string matcher
|
||||
// There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers
|
||||
// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
|
||||
// the Equals matcher (so the header does not mention matchers)
|
||||
void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) {
|
||||
std::string exceptionMessage = Catch::translateActiveException();
|
||||
MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
|
||||
handler.handle( expr );
|
||||
handler.handleExpr( expr );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_matchers.h"
|
||||
#include "catch_matchers_floating.h"
|
||||
#include "catch_matchers_generic.hpp"
|
||||
#include "catch_matchers_string.h"
|
||||
#include "catch_matchers_vector.h"
|
||||
|
||||
@@ -20,18 +22,14 @@ namespace Catch {
|
||||
ArgT const& m_arg;
|
||||
MatcherT m_matcher;
|
||||
StringRef m_matcherString;
|
||||
bool m_result;
|
||||
public:
|
||||
MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
|
||||
: m_arg( arg ),
|
||||
: ITransientExpression{ true, matcher.match( arg ) },
|
||||
m_arg( arg ),
|
||||
m_matcher( matcher ),
|
||||
m_matcherString( matcherString ),
|
||||
m_result( matcher.match( arg ) )
|
||||
m_matcherString( matcherString )
|
||||
{}
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return true; }
|
||||
auto getResult() const -> bool override { return m_result; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
auto matcherAsString = m_matcher.toString();
|
||||
os << Catch::Detail::stringify( m_arg ) << ' ';
|
||||
@@ -58,11 +56,11 @@ namespace Catch {
|
||||
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
||||
do { \
|
||||
Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
|
||||
INTERNAL_CATCH_TRY( catchAssertionHandler ) { \
|
||||
catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
|
||||
INTERNAL_CATCH_TRY { \
|
||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
|
||||
} INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -72,17 +70,17 @@ namespace Catch {
|
||||
if( catchAssertionHandler.allowThrows() ) \
|
||||
try { \
|
||||
static_cast<void>(__VA_ARGS__ ); \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \
|
||||
catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
|
||||
} \
|
||||
catch( exceptionType const& ex ) { \
|
||||
catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
|
||||
catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
catchAssertionHandler.useActiveException(); \
|
||||
catchAssertionHandler.handleUnexpectedInflightException(); \
|
||||
} \
|
||||
else \
|
||||
catchAssertionHandler.handle( Catch::ResultWas::Ok ); \
|
||||
catchAssertionHandler.handleThrowingCallSkipped(); \
|
||||
INTERNAL_CATCH_REACT( catchAssertionHandler ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
} while( false )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_CAPTURE_MATCHERS_HPP_INCLUDED
|
||||
|
@@ -20,9 +20,19 @@ namespace Catch {
|
||||
using namespace clara;
|
||||
|
||||
auto const setWarning = [&]( std::string const& warning ) {
|
||||
if( warning != "NoAssertions" )
|
||||
auto warningSet = [&]() {
|
||||
if( warning == "NoAssertions" )
|
||||
return WarnAbout::NoAssertions;
|
||||
|
||||
if ( warning == "NoTests" )
|
||||
return WarnAbout::NoTests;
|
||||
|
||||
return WarnAbout::Nothing;
|
||||
}();
|
||||
|
||||
if (warningSet == WarnAbout::Nothing)
|
||||
return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
|
||||
return ParserResult::ok( ParseResultType::Matched );
|
||||
};
|
||||
auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
|
||||
|
@@ -15,10 +15,6 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept
|
||||
: file( _file ),
|
||||
line( _line )
|
||||
{}
|
||||
bool SourceLineInfo::empty() const noexcept {
|
||||
return file[0] == '\0';
|
||||
}
|
||||
@@ -38,10 +34,6 @@ namespace Catch {
|
||||
return os;
|
||||
}
|
||||
|
||||
bool isTrue( bool value ){ return value; }
|
||||
bool alwaysTrue() { return true; }
|
||||
bool alwaysFalse() { return false; }
|
||||
|
||||
std::string StreamEndStop::operator+() const {
|
||||
return std::string();
|
||||
}
|
||||
|
@@ -43,7 +43,10 @@ namespace Catch {
|
||||
struct SourceLineInfo {
|
||||
|
||||
SourceLineInfo() = delete;
|
||||
SourceLineInfo( char const* _file, std::size_t _line ) noexcept;
|
||||
SourceLineInfo( char const* _file, std::size_t _line ) noexcept
|
||||
: file( _file ),
|
||||
line( _line )
|
||||
{}
|
||||
|
||||
SourceLineInfo( SourceLineInfo const& other ) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
@@ -60,11 +63,6 @@ namespace Catch {
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
|
||||
|
||||
// This is just here to avoid compiler warnings with macro constants and boolean literals
|
||||
bool isTrue( bool value );
|
||||
bool alwaysTrue();
|
||||
bool alwaysFalse();
|
||||
|
||||
// Use this in variadic streaming macros to allow
|
||||
// >> +StreamEndStop
|
||||
// as well as
|
||||
|
@@ -31,6 +31,14 @@
|
||||
# define CATCH_CPP14_OR_GREATER
|
||||
# endif
|
||||
|
||||
# if __cplusplus >= 201703L
|
||||
# define CATCH_CPP17_OR_GREATER
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_CPP17_OR_GREATER)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -51,14 +59,16 @@
|
||||
#endif // __clang__
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Assume that non-Windows platforms support posix signals by default
|
||||
#if !defined(CATCH_PLATFORM_WINDOWS)
|
||||
#define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// We know some environments not to support full POSIX signals
|
||||
#if defined(__CYGWIN__) || defined(__QNX__)
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||
# endif
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
|
||||
#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
|
||||
#endif
|
||||
|
||||
#ifdef __OS400__
|
||||
@@ -80,9 +90,14 @@
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
|
||||
|
||||
# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
|
||||
# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
|
||||
# endif
|
||||
|
||||
// Universal Windows platform does not support SEH
|
||||
// Or console colours (or console at all...)
|
||||
# if (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
# define CATCH_CONFIG_COLOUR_NONE
|
||||
# else
|
||||
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
||||
@@ -92,26 +107,41 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// All supported compilers support COUNTER macro,
|
||||
//but user still might want to turn it off
|
||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||
// DJGPP
|
||||
#ifdef __DJGPP__
|
||||
# define CATCH_INTERNAL_CONFIG_NO_WCHAR
|
||||
#endif // __DJGPP__
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Now set the actual defines based on the above + anything the user has configured
|
||||
// Use of __COUNTER__ is suppressed during code analysis in
|
||||
// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
|
||||
// handled by it.
|
||||
// Otherwise all supported compilers support COUNTER macro,
|
||||
// but user still might want to turn it off
|
||||
#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
|
||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||
#endif
|
||||
|
||||
// Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for
|
||||
// analytics) because, at time of writing, __COUNTER__ is not properly handled by it.
|
||||
// This does not affect compilation
|
||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||
# define CATCH_CONFIG_COUNTER
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
|
||||
# define CATCH_CONFIG_WINDOWS_SEH
|
||||
#endif
|
||||
// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
|
||||
#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
# define CATCH_CONFIG_POSIX_SIGNALS
|
||||
#endif
|
||||
// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
|
||||
#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
|
||||
# define CATCH_CONFIG_WCHAR
|
||||
#endif
|
||||
|
||||
#if defined(CATCH_INTERNAL_CONFIG_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_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "catch_config.hpp"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_stringref.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -15,12 +15,16 @@ namespace Catch {
|
||||
: m_data( data ),
|
||||
m_stream( openStream() )
|
||||
{
|
||||
if( !data.testsOrTags.empty() ) {
|
||||
TestSpecParser parser( ITagAliasRegistry::get() );
|
||||
TestSpecParser parser(ITagAliasRegistry::get());
|
||||
if (data.testsOrTags.empty()) {
|
||||
parser.parse("~[.]"); // All not hidden tests
|
||||
}
|
||||
else {
|
||||
m_hasTestFilters = true;
|
||||
for( auto const& testOrTags : data.testsOrTags )
|
||||
parser.parse( testOrTags );
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
m_testSpec = parser.testSpec();
|
||||
}
|
||||
|
||||
std::string const& Config::getFilename() const {
|
||||
@@ -35,9 +39,11 @@ namespace Catch {
|
||||
std::string Config::getProcessName() const { return m_data.processName; }
|
||||
|
||||
std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
|
||||
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
|
||||
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
|
||||
|
||||
TestSpec const& Config::testSpec() const { return m_testSpec; }
|
||||
bool Config::hasTestFilters() const { return m_hasTestFilters; }
|
||||
|
||||
bool Config::showHelp() const { return m_data.showHelp; }
|
||||
|
||||
@@ -46,7 +52,8 @@ namespace Catch {
|
||||
std::ostream& Config::stream() const { return m_stream->stream(); }
|
||||
std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
|
||||
bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
|
||||
ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
|
||||
RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
|
||||
unsigned int Config::rngSeed() const { return m_data.rngSeed; }
|
||||
@@ -58,16 +65,7 @@ namespace Catch {
|
||||
Verbosity Config::verbosity() const { return m_data.verbosity; }
|
||||
|
||||
IStream const* Config::openStream() {
|
||||
if( m_data.outputFilename.empty() )
|
||||
return new CoutStream();
|
||||
else if( m_data.outputFilename[0] == '%' ) {
|
||||
if( m_data.outputFilename == "%debug" )
|
||||
return new DebugOutStream();
|
||||
else
|
||||
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
|
||||
}
|
||||
else
|
||||
return new FileStream( m_data.outputFilename );
|
||||
return Catch::makeStream(m_data.outputFilename);
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -78,9 +78,11 @@ namespace Catch {
|
||||
std::string getProcessName() const;
|
||||
|
||||
std::vector<std::string> const& getReporterNames() const;
|
||||
std::vector<std::string> const& getTestsOrTags() const;
|
||||
std::vector<std::string> const& getSectionsToRun() const override;
|
||||
|
||||
virtual TestSpec const& testSpec() const override;
|
||||
bool hasTestFilters() const override;
|
||||
|
||||
bool showHelp() const;
|
||||
|
||||
@@ -90,6 +92,7 @@ namespace Catch {
|
||||
std::string name() const override;
|
||||
bool includeSuccessfulResults() const override;
|
||||
bool warnAboutMissingAssertions() const override;
|
||||
bool warnAboutNoTests() const override;
|
||||
ShowDurations::OrNot showDurations() const override;
|
||||
RunTests::InWhatOrder runOrder() const override;
|
||||
unsigned int rngSeed() const override;
|
||||
@@ -107,6 +110,7 @@ namespace Catch {
|
||||
|
||||
std::unique_ptr<IStream const> m_stream;
|
||||
TestSpec m_testSpec;
|
||||
bool m_hasTestFilters = false;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -11,8 +11,8 @@
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_enforce.h"
|
||||
#include "catch_errno_guard.h"
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "catch_debugger.h"
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace Catch {
|
||||
namespace {
|
||||
|
||||
@@ -82,8 +84,12 @@ namespace {
|
||||
case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
|
||||
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
|
||||
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
|
||||
case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
|
||||
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
|
||||
default:
|
||||
CATCH_ERROR( "Unknown colour requested" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +147,10 @@ namespace {
|
||||
case Colour::BrightRed: return setColour( "[1;31m" );
|
||||
case Colour::BrightGreen: return setColour( "[1;32m" );
|
||||
case Colour::BrightWhite: return setColour( "[1;37m" );
|
||||
case Colour::BrightYellow: return setColour( "[1;33m" );
|
||||
|
||||
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
|
||||
default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
|
||||
}
|
||||
}
|
||||
static IColourImpl* instance() {
|
||||
@@ -161,7 +169,12 @@ namespace {
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
!isDebuggerActive() &&
|
||||
#endif
|
||||
isatty(STDOUT_FILENO);
|
||||
#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
|
||||
isatty(STDOUT_FILENO)
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
;
|
||||
}
|
||||
IColourImpl* platformColourInstance() {
|
||||
ErrnoGuard guard;
|
||||
@@ -194,7 +207,7 @@ namespace Catch {
|
||||
namespace Catch {
|
||||
|
||||
Colour::Colour( Code _colourCode ) { use( _colourCode ); }
|
||||
Colour::Colour( Colour&& rhs ) noexcept {
|
||||
Colour::Colour( Colour&& rhs ) noexcept {
|
||||
m_moved = rhs.m_moved;
|
||||
rhs.m_moved = true;
|
||||
}
|
||||
@@ -203,7 +216,7 @@ namespace Catch {
|
||||
rhs.m_moved = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
||||
|
||||
void Colour::use( Code _colourCode ) {
|
||||
|
@@ -30,10 +30,11 @@ namespace Catch {
|
||||
BrightGreen = Bright | Green,
|
||||
LightGrey = Bright | Grey,
|
||||
BrightWhite = Bright | White,
|
||||
BrightYellow = Bright | Yellow,
|
||||
|
||||
// By intention
|
||||
FileName = LightGrey,
|
||||
Warning = Yellow,
|
||||
Warning = BrightYellow,
|
||||
ResultError = BrightRed,
|
||||
ResultSuccess = BrightGreen,
|
||||
ResultExpectedFailure = Warning,
|
||||
@@ -42,7 +43,7 @@ namespace Catch {
|
||||
Success = Green,
|
||||
|
||||
OriginalExpression = Cyan,
|
||||
ReconstructedExpression = Yellow,
|
||||
ReconstructedExpression = BrightYellow,
|
||||
|
||||
SecondaryText = LightGrey,
|
||||
Headers = White
|
||||
|
@@ -20,7 +20,7 @@ namespace Catch {
|
||||
return m_runner;
|
||||
}
|
||||
|
||||
virtual IConfigPtr getConfig() const override {
|
||||
virtual IConfigPtr const& getConfig() const override {
|
||||
return m_config;
|
||||
}
|
||||
|
||||
@@ -45,21 +45,16 @@ namespace Catch {
|
||||
IResultCapture* m_resultCapture = nullptr;
|
||||
};
|
||||
|
||||
namespace {
|
||||
Context* currentContext = nullptr;
|
||||
}
|
||||
IMutableContext& getCurrentMutableContext() {
|
||||
if( !currentContext )
|
||||
currentContext = new Context();
|
||||
return *currentContext;
|
||||
}
|
||||
IContext& getCurrentContext() {
|
||||
return getCurrentMutableContext();
|
||||
IMutableContext *IMutableContext::currentContext = nullptr;
|
||||
|
||||
void IMutableContext::createContext()
|
||||
{
|
||||
currentContext = new Context();
|
||||
}
|
||||
|
||||
void cleanUpContext() {
|
||||
delete currentContext;
|
||||
currentContext = nullptr;
|
||||
delete IMutableContext::currentContext;
|
||||
IMutableContext::currentContext = nullptr;
|
||||
}
|
||||
IContext::~IContext() = default;
|
||||
IMutableContext::~IMutableContext() = default;
|
||||
|
@@ -15,6 +15,7 @@ namespace Catch {
|
||||
struct IResultCapture;
|
||||
struct IRunner;
|
||||
struct IConfig;
|
||||
struct IMutableContext;
|
||||
|
||||
using IConfigPtr = std::shared_ptr<IConfig const>;
|
||||
|
||||
@@ -24,7 +25,7 @@ namespace Catch {
|
||||
|
||||
virtual IResultCapture* getResultCapture() = 0;
|
||||
virtual IRunner* getRunner() = 0;
|
||||
virtual IConfigPtr getConfig() const = 0;
|
||||
virtual IConfigPtr const& getConfig() const = 0;
|
||||
};
|
||||
|
||||
struct IMutableContext : IContext
|
||||
@@ -33,10 +34,26 @@ namespace Catch {
|
||||
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
|
||||
virtual void setRunner( IRunner* runner ) = 0;
|
||||
virtual void setConfig( IConfigPtr const& config ) = 0;
|
||||
|
||||
private:
|
||||
static IMutableContext *currentContext;
|
||||
friend IMutableContext& getCurrentMutableContext();
|
||||
friend void cleanUpContext();
|
||||
static void createContext();
|
||||
};
|
||||
|
||||
IContext& getCurrentContext();
|
||||
IMutableContext& getCurrentMutableContext();
|
||||
inline IMutableContext& getCurrentMutableContext()
|
||||
{
|
||||
if( !IMutableContext::currentContext )
|
||||
IMutableContext::createContext();
|
||||
return *IMutableContext::currentContext;
|
||||
}
|
||||
|
||||
inline IContext& getCurrentContext()
|
||||
{
|
||||
return getCurrentMutableContext();
|
||||
}
|
||||
|
||||
void cleanUpContext();
|
||||
}
|
||||
|
||||
|
@@ -9,21 +9,23 @@
|
||||
#include "catch_debug_console.h"
|
||||
#include "catch_stream.h"
|
||||
#include "catch_platform.h"
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
namespace Catch {
|
||||
void writeToDebugConsole( std::string const& text ) {
|
||||
::OutputDebugStringA( text.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
void writeToDebugConsole( std::string const& text ) {
|
||||
// !TBD: Need a version for Mac/ XCode and other IDEs
|
||||
Catch::cout() << text;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // Platform
|
||||
|
@@ -14,13 +14,15 @@
|
||||
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
# include <assert.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/sysctl.h>
|
||||
# include <cstddef>
|
||||
# include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
namespace Catch {
|
||||
|
||||
// The following function is taken directly from the following technical note:
|
||||
// http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
|
||||
|
@@ -40,7 +40,10 @@ namespace Catch {
|
||||
#ifdef CATCH_TRAP
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
|
||||
namespace Catch {
|
||||
inline void doNothing() {}
|
||||
}
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
||||
|
@@ -11,7 +11,7 @@
|
||||
#include "catch_tostring.h"
|
||||
#include "catch_stringref.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
@@ -24,27 +24,32 @@
|
||||
namespace Catch {
|
||||
|
||||
struct ITransientExpression {
|
||||
virtual auto isBinaryExpression() const -> bool = 0;
|
||||
virtual auto getResult() const -> bool = 0;
|
||||
auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
|
||||
auto getResult() const -> bool { return m_result; }
|
||||
virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
|
||||
|
||||
// We don't actually need a virtual destructore, but many static analysers
|
||||
ITransientExpression( bool isBinaryExpression, bool result )
|
||||
: m_isBinaryExpression( isBinaryExpression ),
|
||||
m_result( result )
|
||||
{}
|
||||
|
||||
// We don't actually need a virtual destructor, but many static analysers
|
||||
// complain if it's not here :-(
|
||||
virtual ~ITransientExpression();
|
||||
|
||||
bool m_isBinaryExpression;
|
||||
bool m_result;
|
||||
|
||||
};
|
||||
|
||||
void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
|
||||
|
||||
template<typename LhsT, typename RhsT>
|
||||
class BinaryExpr : public ITransientExpression {
|
||||
bool m_result;
|
||||
LhsT m_lhs;
|
||||
StringRef m_op;
|
||||
RhsT m_rhs;
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return true; }
|
||||
auto getResult() const -> bool override { return m_result; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
formatReconstructedExpression
|
||||
( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
|
||||
@@ -52,7 +57,7 @@ namespace Catch {
|
||||
|
||||
public:
|
||||
BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
|
||||
: m_result( comparisonResult ),
|
||||
: ITransientExpression{ true, comparisonResult },
|
||||
m_lhs( lhs ),
|
||||
m_op( op ),
|
||||
m_rhs( rhs )
|
||||
@@ -63,21 +68,21 @@ namespace Catch {
|
||||
class UnaryExpr : public ITransientExpression {
|
||||
LhsT m_lhs;
|
||||
|
||||
auto isBinaryExpression() const -> bool override { return false; }
|
||||
auto getResult() const -> bool override { return m_lhs ? true : false; }
|
||||
|
||||
void streamReconstructedExpression( std::ostream &os ) const override {
|
||||
os << Catch::Detail::stringify( m_lhs );
|
||||
}
|
||||
|
||||
public:
|
||||
UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {}
|
||||
explicit UnaryExpr( LhsT lhs )
|
||||
: ITransientExpression{ false, lhs ? true : false },
|
||||
m_lhs( lhs )
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs == rhs; };
|
||||
auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
|
||||
template<typename T>
|
||||
auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
|
||||
template<typename T>
|
||||
@@ -88,7 +93,7 @@ namespace Catch {
|
||||
auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
|
||||
|
||||
template<typename LhsT, typename RhsT>
|
||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; };
|
||||
auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
|
||||
template<typename T>
|
||||
auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
|
||||
template<typename T>
|
||||
@@ -103,43 +108,43 @@ namespace Catch {
|
||||
class ExprLhs {
|
||||
LhsT m_lhs;
|
||||
public:
|
||||
ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
|
||||
explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator == ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs );
|
||||
auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
|
||||
}
|
||||
auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
|
||||
return BinaryExpr<LhsT, bool>( m_lhs == rhs, m_lhs, "==", rhs );
|
||||
return { m_lhs == rhs, m_lhs, "==", rhs };
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator != ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs );
|
||||
auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
|
||||
}
|
||||
auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
|
||||
return BinaryExpr<LhsT, bool>( m_lhs != rhs, m_lhs, "!=", rhs );
|
||||
return { m_lhs != rhs, m_lhs, "!=", rhs };
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
auto operator > ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs > rhs, m_lhs, ">", rhs );
|
||||
auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator < ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs < rhs, m_lhs, "<", rhs );
|
||||
auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator >= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs >= rhs, m_lhs, ">=", rhs );
|
||||
auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
|
||||
}
|
||||
template<typename RhsT>
|
||||
auto operator <= ( RhsT&& rhs ) -> BinaryExpr<LhsT, RhsT&> const {
|
||||
return BinaryExpr<LhsT, RhsT&>( m_lhs <= rhs, m_lhs, "<=", rhs );
|
||||
auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
|
||||
return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
|
||||
}
|
||||
|
||||
auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
|
||||
return UnaryExpr<LhsT>( m_lhs );
|
||||
return UnaryExpr<LhsT>{ m_lhs };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,13 +158,18 @@ namespace Catch {
|
||||
struct Decomposer {
|
||||
template<typename T>
|
||||
auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
|
||||
return ExprLhs<T const&>( lhs );
|
||||
return ExprLhs<T const&>{ lhs };
|
||||
}
|
||||
|
||||
auto operator <=( bool value ) -> ExprLhs<bool> {
|
||||
return ExprLhs<bool>( value );
|
||||
return ExprLhs<bool>{ value };
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DECOMPOSER_H_INCLUDED
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#ifndef __OBJC__
|
||||
|
||||
#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||
#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
|
||||
// Standard C/C++ Win32 Unicode wmain entry point
|
||||
extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
|
||||
#else
|
||||
|
@@ -8,12 +8,12 @@
|
||||
#define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
#include "catch_stream.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#define CATCH_PREPARE_EXCEPTION( type, msg ) \
|
||||
type( static_cast<std::ostringstream&&>( std::ostringstream() << msg ).str() )
|
||||
type( ( Catch::ReusableStringStream() << msg ).str() )
|
||||
#define CATCH_INTERNAL_ERROR( msg ) \
|
||||
throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg);
|
||||
#define CATCH_ERROR( msg ) \
|
||||
|
@@ -33,6 +33,17 @@ namespace Catch {
|
||||
return Catch::Detail::stringify( [exception description] );
|
||||
}
|
||||
#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();
|
||||
#endif
|
||||
}
|
||||
|
@@ -11,4 +11,10 @@
|
||||
#include "catch_console_colour.h"
|
||||
#include "catch_reporter_registrars.hpp"
|
||||
|
||||
// Allow users to base their work off existing reporters
|
||||
#include "../reporters/catch_reporter_compact.h"
|
||||
#include "../reporters/catch_reporter_console.h"
|
||||
#include "../reporters/catch_reporter_junit.h"
|
||||
#include "../reporters/catch_reporter_xml.h"
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED
|
||||
|
@@ -12,6 +12,13 @@
|
||||
#include "catch_context.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace {
|
||||
// Report the error condition
|
||||
void reportFatal( char const * const message ) {
|
||||
@@ -19,15 +26,9 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
||||
#endif // signals/SEH handling
|
||||
|
||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
@@ -67,7 +68,6 @@ namespace Catch {
|
||||
|
||||
void FatalConditionHandler::reset() {
|
||||
if (isSet) {
|
||||
// Unregister handler and restore the old guarantee
|
||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
exceptionHandlerHandle = nullptr;
|
||||
@@ -86,20 +86,7 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
|
||||
namespace Catch {
|
||||
void FatalConditionHandler::reset() {}
|
||||
}
|
||||
|
||||
|
||||
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
||||
|
||||
#include <signal.h>
|
||||
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -171,6 +158,14 @@ 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__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
@@ -9,23 +9,12 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "catch_platform.h"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
|
||||
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
# if !defined ( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
||||
#if defined( CATCH_CONFIG_WINDOWS_SEH )
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -44,20 +33,7 @@ namespace Catch {
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_WINDOWS_SEH
|
||||
|
||||
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
||||
|
||||
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
||||
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -66,7 +42,7 @@ namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
|
||||
static struct sigaction oldSigActions[];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[];
|
||||
|
||||
@@ -79,8 +55,15 @@ namespace Catch {
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#endif // not Windows
|
||||
#else
|
||||
|
||||
namespace Catch {
|
||||
struct FatalConditionHandler {
|
||||
void reset();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "catch_stringref.h"
|
||||
#include "catch_result_type.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -22,13 +23,14 @@ namespace Catch {
|
||||
struct Counts;
|
||||
struct BenchmarkInfo;
|
||||
struct BenchmarkStats;
|
||||
struct AssertionReaction;
|
||||
|
||||
struct ITransientExpression;
|
||||
|
||||
struct IResultCapture {
|
||||
|
||||
virtual ~IResultCapture();
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& info ) = 0;
|
||||
virtual void assertionEnded( AssertionResult const& result ) = 0;
|
||||
virtual bool sectionStarted( SectionInfo const& sectionInfo,
|
||||
Counts& assertions ) = 0;
|
||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||
@@ -40,16 +42,40 @@ namespace Catch {
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) = 0;
|
||||
virtual void popScopedMessage( MessageInfo const& message ) = 0;
|
||||
|
||||
virtual std::string getCurrentTestName() const = 0;
|
||||
virtual const AssertionResult* getLastResult() const = 0;
|
||||
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( StringRef message ) = 0;
|
||||
|
||||
virtual void handleExpr
|
||||
( AssertionInfo const& info,
|
||||
ITransientExpression const& expr,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleMessage
|
||||
( AssertionInfo const& info,
|
||||
ResultWas::OfType resultType,
|
||||
StringRef const& message,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleUnexpectedExceptionNotThrown
|
||||
( AssertionInfo const& info,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleUnexpectedInflightException
|
||||
( AssertionInfo const& info,
|
||||
std::string const& message,
|
||||
AssertionReaction& reaction ) = 0;
|
||||
virtual void handleIncomplete
|
||||
( AssertionInfo const& info ) = 0;
|
||||
virtual void handleNonExpr
|
||||
( AssertionInfo const &info,
|
||||
ResultWas::OfType resultType,
|
||||
AssertionReaction &reaction ) = 0;
|
||||
|
||||
|
||||
|
||||
virtual bool lastAssertionPassed() = 0;
|
||||
virtual void assertionPassed() = 0;
|
||||
virtual void assertionRun() = 0;
|
||||
|
||||
// Deprecated, do not use:
|
||||
virtual std::string getCurrentTestName() const = 0;
|
||||
virtual const AssertionResult* getLastResult() const = 0;
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
};
|
||||
|
||||
IResultCapture& getResultCapture();
|
||||
|
@@ -25,7 +25,8 @@ namespace Catch {
|
||||
|
||||
struct WarnAbout { enum What {
|
||||
Nothing = 0x00,
|
||||
NoAssertions = 0x01
|
||||
NoAssertions = 0x01,
|
||||
NoTests = 0x02
|
||||
}; };
|
||||
|
||||
struct ShowDurations { enum OrNot {
|
||||
@@ -62,10 +63,12 @@ namespace Catch {
|
||||
virtual bool includeSuccessfulResults() const = 0;
|
||||
virtual bool shouldDebugBreak() const = 0;
|
||||
virtual bool warnAboutMissingAssertions() const = 0;
|
||||
virtual bool warnAboutNoTests() const = 0;
|
||||
virtual int abortAfter() const = 0;
|
||||
virtual bool showInvisibles() const = 0;
|
||||
virtual ShowDurations::OrNot showDurations() const = 0;
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual bool hasTestFilters() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual int benchmarkResolutionMultiple() const = 0;
|
||||
|
@@ -73,7 +73,9 @@ namespace Catch {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||
static std::string translatorName( signature ); \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
|
||||
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
|
||||
static std::string translatorName( signature )
|
||||
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
|
@@ -8,11 +8,11 @@
|
||||
#include "catch_leak_detector.h"
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
||||
#include <crtdbg.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
LeakDetector::LeakDetector() {
|
||||
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
flag |= _CRTDBG_LEAK_CHECK_DF;
|
||||
@@ -23,11 +23,10 @@ namespace Catch {
|
||||
// Change this to leaking allocation's number to break there
|
||||
_CrtSetBreakAlloc(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
LeakDetector::LeakDetector(){}
|
||||
Catch::LeakDetector::LeakDetector() {}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@@ -28,11 +28,10 @@ namespace Catch {
|
||||
|
||||
std::size_t listTests( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( config.testSpec().hasFilters() )
|
||||
if( config.hasTestFilters() )
|
||||
Catch::cout() << "Matching test cases:\n";
|
||||
else {
|
||||
Catch::cout() << "All available test cases:\n";
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
}
|
||||
|
||||
auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||
@@ -54,7 +53,7 @@ namespace Catch {
|
||||
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
|
||||
}
|
||||
|
||||
if( !config.testSpec().hasFilters() )
|
||||
if( !config.hasTestFilters() )
|
||||
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
|
||||
else
|
||||
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
|
||||
@@ -63,8 +62,6 @@ namespace Catch {
|
||||
|
||||
std::size_t listTestsNamesOnly( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( !config.testSpec().hasFilters() )
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
std::size_t matchedTests = 0;
|
||||
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
|
||||
for( auto const& testCaseInfo : matchedTestCases ) {
|
||||
@@ -94,11 +91,10 @@ namespace Catch {
|
||||
|
||||
std::size_t listTags( Config const& config ) {
|
||||
TestSpec testSpec = config.testSpec();
|
||||
if( config.testSpec().hasFilters() )
|
||||
if( config.hasTestFilters() )
|
||||
Catch::cout() << "Tags for matching test cases:\n";
|
||||
else {
|
||||
Catch::cout() << "All available tags:\n";
|
||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
|
||||
}
|
||||
|
||||
std::map<std::string, TagInfo> tagCounts;
|
||||
@@ -115,13 +111,14 @@ namespace Catch {
|
||||
}
|
||||
|
||||
for( auto const& tagCount : tagCounts ) {
|
||||
std::ostringstream oss;
|
||||
oss << " " << std::setw(2) << tagCount.second.count << " ";
|
||||
ReusableStringStream rss;
|
||||
rss << " " << std::setw(2) << tagCount.second.count << " ";
|
||||
auto str = rss.str();
|
||||
auto wrapper = Column( tagCount.second.all() )
|
||||
.initialIndent( 0 )
|
||||
.indent( oss.str().size() )
|
||||
.indent( str.size() )
|
||||
.width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
|
||||
Catch::cout() << oss.str() << wrapper << '\n';
|
||||
Catch::cout() << str << wrapper << '\n';
|
||||
}
|
||||
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
|
||||
return tagCounts.size();
|
||||
|
@@ -43,13 +43,13 @@ namespace Matchers {
|
||||
virtual bool match( PtrT* arg ) const = 0;
|
||||
};
|
||||
|
||||
template<typename ObjectT, typename ComparatorT = ObjectT>
|
||||
struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
|
||||
template<typename T>
|
||||
struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
|
||||
|
||||
|
||||
MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
|
||||
MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
|
||||
MatchNotOf<ComparatorT> operator ! () const;
|
||||
MatchAllOf<T> operator && ( MatcherBase const& other ) const;
|
||||
MatchAnyOf<T> operator || ( MatcherBase const& other ) const;
|
||||
MatchNotOf<T> operator ! () const;
|
||||
};
|
||||
|
||||
template<typename ArgT>
|
||||
@@ -133,17 +133,17 @@ namespace Matchers {
|
||||
MatcherBase<ArgT> const& m_underlyingMatcher;
|
||||
};
|
||||
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
|
||||
return MatchAllOf<ComparatorT>() && *this && other;
|
||||
template<typename T>
|
||||
MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {
|
||||
return MatchAllOf<T>() && *this && other;
|
||||
}
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
|
||||
return MatchAnyOf<ComparatorT>() || *this || other;
|
||||
template<typename T>
|
||||
MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {
|
||||
return MatchAnyOf<T>() || *this || other;
|
||||
}
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
|
||||
return MatchNotOf<ComparatorT>( *this );
|
||||
template<typename T>
|
||||
MatchNotOf<T> MatcherBase<T>::operator ! () const {
|
||||
return MatchNotOf<T>( *this );
|
||||
}
|
||||
|
||||
} // namespace Impl
|
||||
|
139
include/internal/catch_matchers_floating.cpp
Normal file
139
include/internal/catch_matchers_floating.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Created by Martin on 07/11/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)
|
||||
*/
|
||||
|
||||
#include "catch_matchers_floating.h"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Floating {
|
||||
enum class FloatingPointKind : uint8_t {
|
||||
Float,
|
||||
Double
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
struct Converter;
|
||||
|
||||
template <>
|
||||
struct Converter<float> {
|
||||
static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
|
||||
Converter(float f) {
|
||||
std::memcpy(&i, &f, sizeof(f));
|
||||
}
|
||||
int32_t i;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<double> {
|
||||
static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
|
||||
Converter(double d) {
|
||||
std::memcpy(&i, &d, sizeof(d));
|
||||
}
|
||||
int64_t i;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto convert(T t) -> Converter<T> {
|
||||
return Converter<T>(t);
|
||||
}
|
||||
|
||||
template <typename FP>
|
||||
bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
|
||||
// Comparison with NaN should always be false.
|
||||
// This way we can rule it out before getting into the ugly details
|
||||
if (std::isnan(lhs) || std::isnan(rhs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lc = convert(lhs);
|
||||
auto rc = convert(rhs);
|
||||
|
||||
if ((lc.i < 0) != (rc.i < 0)) {
|
||||
// Potentially we can have +0 and -0
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
auto ulpDiff = std::abs(lc.i - rc.i);
|
||||
return ulpDiff <= maxUlpDiff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Floating {
|
||||
WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
|
||||
:m_target{ target }, m_margin{ margin } {
|
||||
if (m_margin < 0) {
|
||||
throw std::domain_error("Allowed margin difference has to be >= 0");
|
||||
}
|
||||
}
|
||||
|
||||
// Performs equivalent check of std::fabs(lhs - rhs) <= margin
|
||||
// But without the subtraction to allow for INFINITY in comparison
|
||||
bool WithinAbsMatcher::match(double const& matchee) const {
|
||||
return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
|
||||
}
|
||||
|
||||
std::string WithinAbsMatcher::describe() const {
|
||||
return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
|
||||
}
|
||||
|
||||
|
||||
WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
|
||||
:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
|
||||
if (m_ulps < 0) {
|
||||
throw std::domain_error("Allowed ulp difference has to be >= 0");
|
||||
}
|
||||
}
|
||||
|
||||
bool WithinUlpsMatcher::match(double const& matchee) const {
|
||||
switch (m_type) {
|
||||
case FloatingPointKind::Float:
|
||||
return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
|
||||
case FloatingPointKind::Double:
|
||||
return almostEqualUlps<double>(matchee, m_target, m_ulps);
|
||||
default:
|
||||
throw std::domain_error("Unknown FloatingPointKind value");
|
||||
}
|
||||
}
|
||||
|
||||
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" : "");
|
||||
}
|
||||
|
||||
}// namespace Floating
|
||||
|
||||
|
||||
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
|
||||
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
|
||||
}
|
||||
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
|
||||
return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
|
||||
}
|
||||
|
||||
Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
|
||||
return Floating::WithinAbsMatcher(target, margin);
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
53
include/internal/catch_matchers_floating.h
Normal file
53
include/internal/catch_matchers_floating.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Created by Martin on 07/11/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_FLOATING_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_FLOATING_H_INCLUDED
|
||||
|
||||
#include "catch_matchers.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <cmath>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
namespace Floating {
|
||||
|
||||
enum class FloatingPointKind : uint8_t;
|
||||
|
||||
struct WithinAbsMatcher : MatcherBase<double> {
|
||||
WithinAbsMatcher(double target, double margin);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
||||
private:
|
||||
double m_target;
|
||||
double m_margin;
|
||||
};
|
||||
|
||||
struct WithinUlpsMatcher : MatcherBase<double> {
|
||||
WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
|
||||
bool match(double const& matchee) const override;
|
||||
std::string describe() const override;
|
||||
private:
|
||||
double m_target;
|
||||
int m_ulps;
|
||||
FloatingPointKind m_type;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Floating
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// This allows the types to be inferred
|
||||
Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
|
||||
Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
|
||||
Floating::WithinAbsMatcher WithinAbs(double target, double margin);
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_FLOATING_H_INCLUDED
|
9
include/internal/catch_matchers_generic.cpp
Normal file
9
include/internal/catch_matchers_generic.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "catch_matchers_generic.hpp"
|
||||
|
||||
std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
|
||||
if (desc.empty()) {
|
||||
return "matches undescribed predicate";
|
||||
} else {
|
||||
return "matches predicate: \"" + desc + '"';
|
||||
}
|
||||
}
|
58
include/internal/catch_matchers_generic.hpp
Normal file
58
include/internal/catch_matchers_generic.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Created by Martin Hořeňovský on 03/04/2017.
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
#include "catch_matchers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Generic {
|
||||
|
||||
namespace Detail {
|
||||
std::string finalizeDescription(const std::string& desc);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PredicateMatcher : public MatcherBase<T> {
|
||||
std::function<bool(T const&)> m_predicate;
|
||||
std::string m_description;
|
||||
public:
|
||||
|
||||
PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
|
||||
:m_predicate(std::move(elem)),
|
||||
m_description(Detail::finalizeDescription(descr))
|
||||
{}
|
||||
|
||||
bool match( T const& item ) const override {
|
||||
return m_predicate(item);
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return m_description;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Generic
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// The user has to explicitly specify type to the function, because
|
||||
// infering std::function<bool(T const&)> is hard (but possible) and
|
||||
// requires a lot of TMP.
|
||||
template<typename T>
|
||||
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
|
||||
return Generic::PredicateMatcher<T>(predicate, description);
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
|
@@ -8,6 +8,9 @@
|
||||
|
||||
#include "catch_matchers_string.h"
|
||||
#include "catch_string_manip.h"
|
||||
#include "catch_tostring.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
@@ -74,6 +77,23 @@ namespace Matchers {
|
||||
return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||
}
|
||||
|
||||
|
||||
|
||||
RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}
|
||||
|
||||
bool RegexMatcher::match(std::string const& matchee) const {
|
||||
auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
|
||||
if (m_caseSensitivity == CaseSensitive::Choice::No) {
|
||||
flags |= std::regex::icase;
|
||||
}
|
||||
auto reg = std::regex(m_regex, flags);
|
||||
return std::regex_match(matchee, reg);
|
||||
}
|
||||
|
||||
std::string RegexMatcher::describe() const {
|
||||
return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");
|
||||
}
|
||||
|
||||
} // namespace StdString
|
||||
|
||||
|
||||
@@ -90,5 +110,9 @@ namespace Matchers {
|
||||
return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||
}
|
||||
|
||||
StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {
|
||||
return StdString::RegexMatcher(regex, caseSensitivity);
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
@@ -52,6 +52,16 @@ namespace Matchers {
|
||||
bool match( std::string const& source ) const override;
|
||||
};
|
||||
|
||||
struct RegexMatcher : MatcherBase<std::string> {
|
||||
RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
|
||||
bool match( std::string const& matchee ) const override;
|
||||
std::string describe() const override;
|
||||
|
||||
private:
|
||||
std::string m_regex;
|
||||
CaseSensitive::Choice m_caseSensitivity;
|
||||
};
|
||||
|
||||
} // namespace StdString
|
||||
|
||||
|
||||
@@ -62,6 +72,7 @@ namespace Matchers {
|
||||
StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
|
||||
StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
|
||||
StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
|
||||
StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
@@ -10,13 +10,36 @@
|
||||
|
||||
#include "catch_matchers.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
namespace Vector {
|
||||
namespace Detail {
|
||||
template <typename InputIterator, typename T>
|
||||
size_t count(InputIterator first, InputIterator last, T const& item) {
|
||||
size_t cnt = 0;
|
||||
for (; first != last; ++first) {
|
||||
if (*first == item) {
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
template <typename InputIterator, typename T>
|
||||
bool contains(InputIterator first, InputIterator last, T const& item) {
|
||||
for (; first != last; ++first) {
|
||||
if (*first == item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
|
||||
struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
|
||||
|
||||
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
||||
|
||||
@@ -37,7 +60,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
|
||||
struct ContainsMatcher : MatcherBase<std::vector<T>> {
|
||||
|
||||
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
@@ -67,7 +90,7 @@ namespace Matchers {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
|
||||
struct EqualsMatcher : MatcherBase<std::vector<T>> {
|
||||
|
||||
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
@@ -89,6 +112,46 @@ namespace Matchers {
|
||||
std::vector<T> const& m_comparator;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
|
||||
UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
|
||||
bool match(std::vector<T> const& vec) const override {
|
||||
// Note: This is a reimplementation of std::is_permutation,
|
||||
// because I don't want to include <algorithm> inside the common path
|
||||
if (m_target.size() != vec.size()) {
|
||||
return false;
|
||||
}
|
||||
auto lfirst = m_target.begin(), llast = m_target.end();
|
||||
auto rfirst = vec.begin(), rlast = vec.end();
|
||||
// Cut common prefix to optimize checking of permuted parts
|
||||
while (lfirst != llast && *lfirst != *rfirst) {
|
||||
++lfirst; ++rfirst;
|
||||
}
|
||||
if (lfirst == llast) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto mid = lfirst; mid != llast; ++mid) {
|
||||
// Skip already counted items
|
||||
if (Detail::contains(lfirst, mid, *mid)) {
|
||||
continue;
|
||||
}
|
||||
size_t num_vec = Detail::count(rfirst, rlast, *mid);
|
||||
if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string describe() const override {
|
||||
return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
|
||||
}
|
||||
private:
|
||||
std::vector<T> const& m_target;
|
||||
};
|
||||
|
||||
} // namespace Vector
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
@@ -109,6 +172,11 @@ namespace Matchers {
|
||||
return Vector::EqualsMatcher<T>( comparator );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
|
||||
return Vector::UnorderedEqualsMatcher<T>(target);
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "catch_message.h"
|
||||
#include "catch_interfaces_capture.h"
|
||||
#include "catch_uncaught_exceptions.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -50,10 +51,8 @@ namespace Catch {
|
||||
}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
if ( !std::uncaught_exception() ){
|
||||
if ( !uncaught_exceptions() ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
@@ -9,9 +9,9 @@
|
||||
#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "catch_result_type.h"
|
||||
#include "catch_common.h"
|
||||
#include "catch_stream.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@@ -40,8 +40,7 @@ namespace Catch {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// !TBD reuse a global/ thread-local stream
|
||||
std::ostringstream m_stream;
|
||||
ReusableStringStream m_stream;
|
||||
};
|
||||
|
||||
struct MessageBuilder : MessageStream {
|
||||
@@ -60,7 +59,7 @@ namespace Catch {
|
||||
|
||||
class ScopedMessage {
|
||||
public:
|
||||
ScopedMessage( MessageBuilder const& builder );
|
||||
explicit ScopedMessage( MessageBuilder const& builder );
|
||||
~ScopedMessage();
|
||||
|
||||
MessageInfo m_info;
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <TargetConditionals.h>
|
||||
# if TARGET_OS_MAC == 1
|
||||
# if TARGET_OS_OSX == 1
|
||||
# define CATCH_PLATFORM_MAC
|
||||
# elif TARGET_OS_IPHONE == 1
|
||||
# define CATCH_PLATFORM_IPHONE
|
||||
|
@@ -25,7 +25,7 @@ namespace Catch {
|
||||
return std::rand() % n;
|
||||
}
|
||||
RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const {
|
||||
return std::rand() % max();
|
||||
return std::rand() % (max)();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,8 +7,6 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
|
||||
|
||||
#include "catch_random_number_generator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Catch {
|
||||
@@ -20,10 +18,10 @@ namespace Catch {
|
||||
unsigned int rngSeed();
|
||||
|
||||
struct RandomNumberGenerator {
|
||||
using result_type = std::ptrdiff_t;
|
||||
using result_type = unsigned int;
|
||||
|
||||
static constexpr result_type min() { return 0; }
|
||||
static constexpr result_type max() { return 1000000; }
|
||||
static constexpr result_type (min)() { return 0; }
|
||||
static constexpr result_type (max)() { return 1000000; }
|
||||
|
||||
result_type operator()( result_type n ) const;
|
||||
result_type operator()() const;
|
||||
|
@@ -87,6 +87,7 @@ namespace Catch {
|
||||
delete getTheRegistryHub();
|
||||
getTheRegistryHub() = nullptr;
|
||||
cleanUpContext();
|
||||
ReusableStringStream::cleanup();
|
||||
}
|
||||
std::string translateActiveException() {
|
||||
return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
|
||||
|
@@ -29,7 +29,7 @@ namespace Catch {
|
||||
|
||||
public:
|
||||
|
||||
ReporterRegistrar( std::string const& name ) {
|
||||
explicit ReporterRegistrar( std::string const& name ) {
|
||||
getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user