mirror of
https://github.com/catchorg/Catch2.git
synced 2025-07-29 18:27:41 +02:00
Compare commits
500 Commits
v1.2.1-dev
...
v1.9.5
Author | SHA1 | Date | |
---|---|---|---|
017a63da62 | |||
b90d0b7267 | |||
efba988ccc | |||
004228efb2 | |||
e0aaba6cf8 | |||
a09bef23ed | |||
3e018ef131 | |||
adb66f55a7 | |||
377c9a746d | |||
ea48ae0f75 | |||
2d1739b429 | |||
1c59034be4 | |||
52a84788e0 | |||
3e328f55fc | |||
b18e67522f | |||
4b086bd5b5 | |||
aac594aae3 | |||
a49fa0edbe | |||
d271683c14 | |||
0bb8e1247e | |||
32d97caf42 | |||
bc93b29789 | |||
df5cf2d323 | |||
b62c0256b2 | |||
1ea84cb734 | |||
2a5d3736e8 | |||
3dcc923351 | |||
589c40077b | |||
d4e0b1d093 | |||
b8443e67da | |||
5604ec7266 | |||
6f012f2d1d | |||
98e61c31df | |||
e641485132 | |||
a3ceb8f007 | |||
b819432271 | |||
9ceae8f51f | |||
5ffc8a84cd | |||
6e0fa4be68 | |||
a0ada2e935 | |||
e4694f58da | |||
fc7f0a02b8 | |||
211b330346 | |||
d36fe214a6 | |||
a34c053f0a | |||
4cdb203ec3 | |||
8014bf1124 | |||
49d87cf182 | |||
eedcc82d31 | |||
8e8259091c | |||
7869e5b007 | |||
a49af4648c | |||
417b2bcf5c | |||
8f0feaa6d2 | |||
b95163bd3a | |||
2809be87cc | |||
ac369b7b83 | |||
1aa3e4abfa | |||
e5c5a636a9 | |||
2bf30e9e5a | |||
b591cb9a03 | |||
714d01c07c | |||
c6990cdf91 | |||
da8786b8fd | |||
5577322062 | |||
1b03c5ab6a | |||
7dd3c19027 | |||
29d26d3179 | |||
ca764ec8d9 | |||
250f0ee7fb | |||
09e4830199 | |||
8f85d08e9f | |||
3ae076ce8d | |||
94425ad59b | |||
0354d50278 | |||
cdd83c2e15 | |||
9a07dde16d | |||
6e091d3991 | |||
95d85fb186 | |||
3a3f152979 | |||
4fe2432e05 | |||
c3a41e26a7 | |||
4838039b65 | |||
2a221b8fcd | |||
79ce6930a2 | |||
d762a7ca6c | |||
f23b6b8b85 | |||
4597b43912 | |||
f64d914bff | |||
d07999ddff | |||
e04dc5105b | |||
cffb031ce1 | |||
f3ec843ba6 | |||
55ed17f97b | |||
6a502cc2f5 | |||
6a009fabcb | |||
7a8a0205b4 | |||
4dc06bdb70 | |||
08b597b3e2 | |||
46d166406d | |||
4ec8d53e91 | |||
e7984e3711 | |||
90d89377ea | |||
0692317bc5 | |||
e8b31108d6 | |||
95fc8d62a2 | |||
0c015aa887 | |||
f69f821853 | |||
485dbdc0e7 | |||
0afd52b98d | |||
38b05f1400 | |||
db9866677e | |||
4101ff314a | |||
68da5a6d19 | |||
e4a25ad5ff | |||
5d6c744d38 | |||
5dd0639520 | |||
a2515755c3 | |||
807941eb31 | |||
a2e20b07f8 | |||
ace70407a2 | |||
613e1466f9 | |||
d8f45cd5f1 | |||
3afd077b55 | |||
e95bf48445 | |||
932a405e18 | |||
9a037204fa | |||
374c050a42 | |||
8b8e3ee117 | |||
af1ed708e4 | |||
041498b221 | |||
d5a5883a10 | |||
6fea473414 | |||
68e7fdce20 | |||
b4c9bf5802 | |||
e952fa8946 | |||
84a178f0b0 | |||
f9db24a824 | |||
9bee606dd6 | |||
be4f6ab8e1 | |||
fd6c7aee6d | |||
cd6de9cd34 | |||
40f6a5b8a4 | |||
95b0eb2b6c | |||
0b28d3daf2 | |||
8435dcbb61 | |||
99347df70e | |||
658b5f63ef | |||
c6535a080e | |||
673ec550f5 | |||
ff78e7c45a | |||
da023b2f9a | |||
470561cbbd | |||
417202b743 | |||
0952b76e16 | |||
bbeb192ec9 | |||
e4f4335b07 | |||
8c07899715 | |||
d5c623b3b6 | |||
061a183036 | |||
70ac6dbb9f | |||
593161ddd8 | |||
71e500f4b5 | |||
ad942885ce | |||
e058a37614 | |||
72b72ca937 | |||
a8a6b3159d | |||
9e2616aeac | |||
c5ffd2e3f0 | |||
0f24a8c06f | |||
b0260c615d | |||
a63ce953a0 | |||
b753f05d74 | |||
9bab7c8229 | |||
d8c4512b25 | |||
2e08bfe9cc | |||
d2a59ad37b | |||
10dfca34ac | |||
45d4096756 | |||
4e6938d78e | |||
1ca8cefa9a | |||
ca66dd243c | |||
44632c3d71 | |||
aa28196e8b | |||
5d8055319e | |||
b1835e1de9 | |||
8cd413572a | |||
30e4dbef1c | |||
90b3946e9c | |||
9202a77498 | |||
d8230a8d4d | |||
c6178601c5 | |||
2e0ae01b05 | |||
1f71d1f760 | |||
fe690a68ef | |||
c9a37c59c4 | |||
3cfef738e7 | |||
5cb9e47034 | |||
044b616127 | |||
f88049169e | |||
7b13a8f85a | |||
6da5e0862a | |||
2049113935 | |||
d4ae1b18c0 | |||
2081caa452 | |||
a5a013811c | |||
1400127d6f | |||
7fed25ad1f | |||
5530303be7 | |||
29fa1edcc7 | |||
1cb8bafb1f | |||
d08cee288f | |||
873ef276b6 | |||
bc68b9f454 | |||
67d513aa73 | |||
9a3486a705 | |||
d890791800 | |||
26f6012bb9 | |||
50dee9ae57 | |||
b2a6fe971b | |||
0837132ce3 | |||
9012f95964 | |||
324260f253 | |||
d0620c3495 | |||
fd7dde10d3 | |||
9a3788d98c | |||
005787f1c5 | |||
d2e814ff23 | |||
f75a511b5c | |||
ab44fb6811 | |||
d6b8ac5a4e | |||
c72ba93f92 | |||
73159ace3d | |||
9952dda524 | |||
e543cc0646 | |||
c1a5391034 | |||
a38ccec33a | |||
1ff56301a1 | |||
aee3675968 | |||
0579f07092 | |||
e9ad954435 | |||
1e87cae8af | |||
26df0781a5 | |||
4d0cd602e3 | |||
ab199d9cf9 | |||
97d8003a71 | |||
1f271c9944 | |||
7db4d8d90c | |||
a5ce57b346 | |||
7b8a27eadb | |||
2b74613c54 | |||
23600609c0 | |||
4feb2dbb50 | |||
84af6bc955 | |||
197bf075c4 | |||
1f5ec9884c | |||
88b760276d | |||
23eb4cc580 | |||
a189387f49 | |||
f65776890c | |||
39753558eb | |||
f126d7943a | |||
cd489d9647 | |||
e991c006b7 | |||
7e7c813486 | |||
712323ab7c | |||
ce37f48ffa | |||
090fc74cca | |||
f58ff0c540 | |||
a600bfeb75 | |||
8cad76a749 | |||
1a3f6d829b | |||
b524fa7cd8 | |||
5121b5b058 | |||
1e5176bd69 | |||
7dd4f2977a | |||
50c95a0143 | |||
0dabd951ba | |||
7ae96c710b | |||
70d3c937c3 | |||
38af8d7035 | |||
c97ada1910 | |||
615aa071a8 | |||
af0b03abd2 | |||
15816c5760 | |||
f11a45aa67 | |||
bcaa2f9646 | |||
efab3ca8b2 | |||
60f8ebec49 | |||
e1dbb7cf64 | |||
02a69b449f | |||
c390c4cb9f | |||
60a9ac7e65 | |||
c06afe438e | |||
73872207db | |||
51860f1568 | |||
dab1d9d222 | |||
4ce11d63a6 | |||
99c2ea594c | |||
51107d7cbd | |||
83f4b39680 | |||
b1171bd1f2 | |||
6c23a6582b | |||
7bcb42496d | |||
184865358c | |||
225e90d8ba | |||
31c23b9489 | |||
f347611403 | |||
1efd8d3067 | |||
876af874f3 | |||
e7bcbb35c0 | |||
4a04682e49 | |||
9a56609569 | |||
81159838a5 | |||
78a2866dc7 | |||
9acc6b9673 | |||
c4b5057094 | |||
d38b9266e7 | |||
227598af47 | |||
cfaf906417 | |||
ee0ca512ea | |||
b71a06cf98 | |||
531d26739f | |||
2e87f8e328 | |||
afe46ff270 | |||
c65aeaf25f | |||
750b52b814 | |||
e12fc4aca0 | |||
99cdc62fef | |||
e6ef60a2c4 | |||
e1c4a4bd9b | |||
25d017763b | |||
b634e592da | |||
3b98a0166f | |||
877fd523bc | |||
a1e9b841ff | |||
3b7511e564 | |||
ffc4a9dc14 | |||
7c8b93eac3 | |||
e3659cdddd | |||
40dbdf6cb2 | |||
70f43d719b | |||
a281173099 | |||
b3907a78e1 | |||
d5360e8e29 | |||
9062ebe390 | |||
e6aa1f4e4e | |||
1ff0acfe22 | |||
713ec400e8 | |||
3b2f206191 | |||
4e4d733f90 | |||
b68e8f9a24 | |||
a7cda91d4d | |||
a1bed572be | |||
737f4ea77c | |||
b0de6c938a | |||
6991549457 | |||
b50572bbfd | |||
5b00fd40ba | |||
7bb3e859aa | |||
0bcae64d3d | |||
8abe17a393 | |||
10c44847f4 | |||
0cde0e90a6 | |||
0f0dcd31eb | |||
62cbde369e | |||
1ae84897d4 | |||
976a655496 | |||
37e1e24309 | |||
5a4dde4b5d | |||
8d326424f3 | |||
ccc34b63b6 | |||
7255be28cc | |||
7d2668fa15 | |||
2a4dba177f | |||
8d1e240700 | |||
e273a3dc88 | |||
7bff9cb451 | |||
fd1da4a1d1 | |||
e1fbbe1590 | |||
c8fefc4670 | |||
64193078bc | |||
8d16d95a99 | |||
2be372710e | |||
0c093bee38 | |||
dedc7c56ce | |||
a9561ecb31 | |||
e4df006568 | |||
fb99cc556d | |||
862d13138c | |||
79acc0504b | |||
f9afa2a68d | |||
0c8c6b347a | |||
40b6ad73df | |||
30cebd6177 | |||
e27c4ee042 | |||
072114293b | |||
f90ee9fb37 | |||
c17ba0870a | |||
79f01100e3 | |||
ccf7f2842a | |||
e0302db4a6 | |||
88732e85b2 | |||
1c9a6cab88 | |||
40f6068d52 | |||
21cbfc107e | |||
31861bbd46 | |||
b1eeec7c69 | |||
c23b374f3d | |||
916317bd81 | |||
8c459dd207 | |||
fd7d35464b | |||
c47c1797d2 | |||
f5d2b2dce8 | |||
02c7e41c7c | |||
5095619955 | |||
35f510545d | |||
742457cbcf | |||
1aa6c91e64 | |||
ac220289a6 | |||
be3570ef22 | |||
a74d760d74 | |||
f666f5f0ae | |||
7940d58a2f | |||
ebf9f3bb9d | |||
1ebebd4ab8 | |||
b57e734eb4 | |||
5aa2b82b17 | |||
5c198d85e6 | |||
5a6b291878 | |||
1706dd4f11 | |||
92b141ee53 | |||
4f1263d6b4 | |||
3b19458fed | |||
e5537842d0 | |||
0fe303b6b7 | |||
1c47fe023a | |||
6f3bc629be | |||
6de7142d1f | |||
7544644bb4 | |||
86c0ea2999 | |||
7075b7defb | |||
c984fc3ecd | |||
447f53e9e3 | |||
13a887ad24 | |||
02af70ed0b | |||
c362894565 | |||
97e335437e | |||
ae5ee2cf63 | |||
f895e0d95f | |||
458f37ed57 | |||
91bfe68a75 | |||
8ccb18daa9 | |||
dce2154474 | |||
e52ad48fb7 | |||
776247af81 | |||
3b4edd7a48 | |||
880a2046d9 | |||
ffad3a0a39 | |||
3bd20bf2cd | |||
c7243562b0 | |||
b84e08ad6f | |||
aca16a0f99 | |||
f294c98472 | |||
7424b23bfb | |||
dbd3a84d92 | |||
5262e61e9d | |||
a5fba672e1 | |||
2106d82881 | |||
981347b6e4 | |||
9e341231ba | |||
2b688e1cef | |||
84d1c080d6 | |||
722315a1f5 | |||
fdc42d0af4 | |||
d274fc571c | |||
7e15d9b20b | |||
0e64973f55 | |||
e4fa62a14e | |||
a49f088032 | |||
ed6e9128a4 | |||
3523c39f44 | |||
2585d280d1 | |||
92356769f1 | |||
d10b73f9f1 | |||
71fd2c2fdf | |||
08844e7e57 | |||
054e3c5b43 | |||
f3e7722cc6 | |||
315c83ad87 | |||
9576ad9108 | |||
e91738103c | |||
8c32b49d5f | |||
ece529ae7c | |||
d758428fe2 | |||
bc00d59a4e | |||
15317632f3 | |||
a28d40e941 | |||
7da777a4b7 | |||
1dd0d4c61a |
29
.github/issue_template.md
vendored
Normal file
29
.github/issue_template.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
## Description
|
||||
<!--
|
||||
If your issue is a bugreport, this means describing what you did,
|
||||
what did you want to happen and what actually did happen.
|
||||
|
||||
If your issue is a feature request, describe the feature and why do you
|
||||
want it.
|
||||
-->
|
||||
|
||||
|
||||
### Steps to reproduce
|
||||
<!--
|
||||
This is only relevant for bug reports, but if you do have one,
|
||||
please provide a minimal set of steps to reproduce the problem.
|
||||
|
||||
Usually this means providing a small and self-contained code using Catch
|
||||
and specifying compiler flags/tools used if relevant.
|
||||
-->
|
||||
|
||||
|
||||
### Extra information
|
||||
<!--
|
||||
Fill in any extra information that might be important for your issue.
|
||||
|
||||
If your issue is a bugreport, definitely fill out at least the following.
|
||||
-->
|
||||
* Catch version: **v42.42.42**
|
||||
* Operating System: **Joe's discount operating system**
|
||||
* Compiler+version: **Hidden Dragon v1.2.3**
|
25
.github/pull_request_template.md
vendored
Normal file
25
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
Please do not submit pull requests changing the `version.hpp`
|
||||
or the single-include `catch.hpp` file, these are changed
|
||||
only when a new release is made.
|
||||
-->
|
||||
|
||||
|
||||
## Description
|
||||
<!--
|
||||
Describe the what and the why of your pull request. Remember that these two
|
||||
are usually a bit different. As an example, if you have made various changes
|
||||
to decrease the number of new strings allocated, thats what. The why probably
|
||||
was that you have a large set of tests and found that this speeds them up.
|
||||
-->
|
||||
|
||||
## GitHub Issues
|
||||
<!--
|
||||
If this PR was motivated by some existing issues, reference them here.
|
||||
|
||||
If it is a simple bug-fix, please also add a line like 'Closes #123'
|
||||
to your commit message, so that it is automatically closed.
|
||||
If it is not, don't, as it might take several iterations for a feature
|
||||
to be done properly. If in doubt, leave it open and reference it in the
|
||||
PR itself, so that maintainers can decide.
|
||||
-->
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -14,9 +14,16 @@ Breakpoints.xcbkptlist
|
||||
projects/VS2010/TestCatch/_UpgradeReport_Files/
|
||||
projects/VS2010/TestCatch/TestCatch/TestCatch.vcxproj.filters
|
||||
projects/VisualStudio/TestCatch/UpgradeLog.XML
|
||||
projects/CMake/.idea
|
||||
projects/CMake/cmake-build-debug
|
||||
UpgradeLog.XML
|
||||
Resources/DWARF
|
||||
projects/XCode/iOSTest/Build
|
||||
projects/Generated
|
||||
*.pyc
|
||||
DerivedData
|
||||
*.xccheckout
|
||||
Build
|
||||
.idea
|
||||
cmake-build-debug
|
||||
cmake-build-release
|
||||
.vs
|
189
.travis.yml
189
.travis.yml
@ -1,35 +1,35 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/.ccache
|
||||
|
||||
env:
|
||||
global:
|
||||
- USE_CCACHE=1
|
||||
- CCACHE_COMPRESS=1
|
||||
- CCACHE_MAXSIZE=200M
|
||||
- CCACHE_CPP2=1
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# 1/ Linux Clang Builds
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang34
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang']
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang34
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang35
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.5']
|
||||
env: COMPILER='ccache clang++-3.5' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang35
|
||||
env: COMPILER='ccache clang++-3.5' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++-3.5' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
@ -38,12 +38,12 @@ matrix:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.6']
|
||||
env: COMPILER='ccache clang++-3.6' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang36
|
||||
env: COMPILER='ccache clang++-3.6' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++-3.6' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
@ -52,41 +52,69 @@ matrix:
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.7']
|
||||
env: COMPILER='ccache clang++-3.7' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang37
|
||||
env: COMPILER='ccache clang++-3.7' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++-3.7' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: &clang38
|
||||
apt:
|
||||
sources: ['llvm-toolchain-precise', 'ubuntu-toolchain-r-test']
|
||||
sources: ['llvm-toolchain-precise-3.8', 'ubuntu-toolchain-r-test']
|
||||
packages: ['clang-3.8']
|
||||
env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='ccache clang++-3.8' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
# 2/ Linux GCC Builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc44
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.4']
|
||||
env: COMPILER='g++-4.4' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc44
|
||||
env: COMPILER='g++-4.4' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc47
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.7']
|
||||
env: COMPILER='g++-4.7' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc47
|
||||
env: COMPILER='g++-4.7' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc48
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.8']
|
||||
env: COMPILER='ccache g++-4.8' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc48
|
||||
env: COMPILER='ccache g++-4.8' BUILD_TYPE='Debug'
|
||||
env: COMPILER='g++-4.8' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
@ -95,12 +123,12 @@ matrix:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-4.9']
|
||||
env: COMPILER='ccache g++-4.9' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-4.9' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc49
|
||||
env: COMPILER='ccache g++-4.9' BUILD_TYPE='Debug'
|
||||
env: COMPILER='g++-4.9' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
- os: linux
|
||||
@ -109,35 +137,112 @@ matrix:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-5']
|
||||
env: COMPILER='ccache g++-5' BUILD_TYPE='Release'
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc5
|
||||
env: COMPILER='ccache g++-5' BUILD_TYPE='Debug'
|
||||
env: COMPILER='g++-5' BUILD_TYPE='Debug'
|
||||
|
||||
|
||||
# 3/ OSX Clang Builds
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc6
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6']
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Release'
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Debug'
|
||||
|
||||
# 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
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Debug'
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Release' CPP11=1
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons: *clang38
|
||||
env: COMPILER='clang++-3.8' BUILD_TYPE='Debug' CPP11=1
|
||||
|
||||
# 4a/ Linux C++14 GCC builds
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: *gcc6
|
||||
env: COMPILER='g++-6' BUILD_TYPE='Release' 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
|
||||
|
||||
|
||||
# 5/ OSX Clang Builds
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Release'
|
||||
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Debug'
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='ccache clang++' BUILD_TYPE='Release'
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Debug' USE_CPP11=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
compiler: clang
|
||||
env: COMPILER='clang++' BUILD_TYPE='Release' USE_CPP11=1
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
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
|
||||
|
||||
|
||||
install:
|
||||
@ -146,16 +251,16 @@ install:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
|
||||
CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
|
||||
mkdir cmake && travis_retry wget --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||
export PATH=${DEPS_DIR}/cmake/bin:${PATH}
|
||||
elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew install cmake ccache
|
||||
which cmake || brew install cmake
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- export CXX=${COMPILER}
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- cmake -Hprojects/CMake -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
|
||||
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -Wdev -DUSE_CPP11=${CPP11} -DUSE_CPP14=${CPP14}
|
||||
- cd Build
|
||||
|
||||
script:
|
||||
|
284
CMakeLists.txt
Normal file
284
CMakeLists.txt
Normal file
@ -0,0 +1,284 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(CatchSelfTest)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# define some folders
|
||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
||||
set(HEADER_DIR ${CATCH_DIR}/include)
|
||||
|
||||
if(USE_CPP11)
|
||||
## We can't turn this on by default, since it breaks on travis
|
||||
message(STATUS "Enabling C++11")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
elseif(USE_CPP14)
|
||||
message(STATUS "Enabling C++14")
|
||||
set(CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
if(USE_WMAIN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
|
||||
endif()
|
||||
|
||||
#checks that the given hard-coded list contains all headers + sources in the given folder
|
||||
function(CheckFileList LIST_VAR FOLDER)
|
||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||
file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||
"${FOLDER}/*.hpp"
|
||||
"${FOLDER}/*.h")
|
||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(CheckFileListRec LIST_VAR FOLDER)
|
||||
set(MESSAGE " should be added to the variable ${LIST_VAR}")
|
||||
set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
|
||||
file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
|
||||
"${FOLDER}/*.hpp"
|
||||
"${FOLDER}/*.h")
|
||||
list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
|
||||
foreach(EXTRA_ITEM ${GLOBBED_LIST})
|
||||
string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
|
||||
message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# define the sources of the self test
|
||||
# Please keep these ordered alphabetically
|
||||
set(TEST_SOURCES
|
||||
${SELF_TEST_DIR}/ApproxTests.cpp
|
||||
${SELF_TEST_DIR}/BDDTests.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}/GeneratorTests.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}/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
|
||||
)
|
||||
CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
|
||||
|
||||
# A set of impl files that just #include a single header
|
||||
# Please keep these ordered alphabetically
|
||||
set(IMPL_SOURCES
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_common.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_capture.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_config.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_exception.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_generators.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_registry_hub.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_runner.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_testcase.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_message.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_ptr.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_streambuf.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
|
||||
${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
|
||||
)
|
||||
CheckFileList(IMPL_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(TOP_LEVEL_HEADERS
|
||||
${HEADER_DIR}/catch.hpp
|
||||
${HEADER_DIR}/catch_session.hpp
|
||||
${HEADER_DIR}/catch_with_main.hpp
|
||||
)
|
||||
CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(EXTERNAL_HEADERS
|
||||
${HEADER_DIR}/external/clara.h
|
||||
${HEADER_DIR}/external/tbc_text_format.h
|
||||
)
|
||||
CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
|
||||
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(INTERNAL_HEADERS
|
||||
${HEADER_DIR}/internal/catch_approx.hpp
|
||||
${HEADER_DIR}/internal/catch_assertionresult.h
|
||||
${HEADER_DIR}/internal/catch_assertionresult.hpp
|
||||
${HEADER_DIR}/internal/catch_capture.hpp
|
||||
${HEADER_DIR}/internal/catch_clara.h
|
||||
${HEADER_DIR}/internal/catch_commandline.hpp
|
||||
${HEADER_DIR}/internal/catch_common.h
|
||||
${HEADER_DIR}/internal/catch_common.hpp
|
||||
${HEADER_DIR}/internal/catch_compiler_capabilities.h
|
||||
${HEADER_DIR}/internal/catch_config.hpp
|
||||
${HEADER_DIR}/internal/catch_console_colour.hpp
|
||||
${HEADER_DIR}/internal/catch_console_colour_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_context.h
|
||||
${HEADER_DIR}/internal/catch_context_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_debugger.h
|
||||
${HEADER_DIR}/internal/catch_debugger.hpp
|
||||
${HEADER_DIR}/internal/catch_default_main.hpp
|
||||
${HEADER_DIR}/internal/catch_errno_guard.hpp
|
||||
${HEADER_DIR}/internal/catch_evaluate.hpp
|
||||
${HEADER_DIR}/internal/catch_exception_translator_registry.hpp
|
||||
${HEADER_DIR}/internal/catch_expression_lhs.hpp
|
||||
${HEADER_DIR}/internal/catch_fatal_condition.hpp
|
||||
${HEADER_DIR}/internal/catch_generators.hpp
|
||||
${HEADER_DIR}/internal/catch_generators_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_interfaces_capture.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_config.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_exception.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_generators.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_reporter.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_runner.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
|
||||
${HEADER_DIR}/internal/catch_interfaces_testcase.h
|
||||
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.h
|
||||
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.hpp
|
||||
${HEADER_DIR}/internal/catch_list.hpp
|
||||
${HEADER_DIR}/internal/catch_matchers.hpp
|
||||
${HEADER_DIR}/internal/catch_matchers_string.h
|
||||
${HEADER_DIR}/internal/catch_matchers_string.hpp
|
||||
${HEADER_DIR}/internal/catch_matchers_vector.h
|
||||
${HEADER_DIR}/internal/catch_message.h
|
||||
${HEADER_DIR}/internal/catch_message.hpp
|
||||
${HEADER_DIR}/internal/catch_notimplemented_exception.h
|
||||
${HEADER_DIR}/internal/catch_notimplemented_exception.hpp
|
||||
${HEADER_DIR}/internal/catch_objc.hpp
|
||||
${HEADER_DIR}/internal/catch_objc_arc.hpp
|
||||
${HEADER_DIR}/internal/catch_option.hpp
|
||||
${HEADER_DIR}/internal/catch_platform.h
|
||||
${HEADER_DIR}/internal/catch_ptr.hpp
|
||||
${HEADER_DIR}/internal/catch_reenable_warnings.h
|
||||
${HEADER_DIR}/internal/catch_registry_hub.hpp
|
||||
${HEADER_DIR}/internal/catch_reporter_registrars.hpp
|
||||
${HEADER_DIR}/internal/catch_reporter_registry.hpp
|
||||
${HEADER_DIR}/internal/catch_result_builder.h
|
||||
${HEADER_DIR}/internal/catch_result_builder.hpp
|
||||
${HEADER_DIR}/internal/catch_result_type.h
|
||||
${HEADER_DIR}/internal/catch_run_context.hpp
|
||||
${HEADER_DIR}/internal/catch_section.h
|
||||
${HEADER_DIR}/internal/catch_section.hpp
|
||||
${HEADER_DIR}/internal/catch_section_info.h
|
||||
${HEADER_DIR}/internal/catch_section_info.hpp
|
||||
${HEADER_DIR}/internal/catch_stream.h
|
||||
${HEADER_DIR}/internal/catch_stream.hpp
|
||||
${HEADER_DIR}/internal/catch_streambuf.h
|
||||
${HEADER_DIR}/internal/catch_suppress_warnings.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias_registry.h
|
||||
${HEADER_DIR}/internal/catch_tag_alias_registry.hpp
|
||||
${HEADER_DIR}/internal/catch_test_case_info.h
|
||||
${HEADER_DIR}/internal/catch_test_case_info.hpp
|
||||
${HEADER_DIR}/internal/catch_test_case_registry_impl.hpp
|
||||
${HEADER_DIR}/internal/catch_test_case_tracker.hpp
|
||||
${HEADER_DIR}/internal/catch_test_registry.hpp
|
||||
${HEADER_DIR}/internal/catch_test_spec.hpp
|
||||
${HEADER_DIR}/internal/catch_test_spec_parser.hpp
|
||||
${HEADER_DIR}/internal/catch_text.h
|
||||
${HEADER_DIR}/internal/catch_timer.h
|
||||
${HEADER_DIR}/internal/catch_timer.hpp
|
||||
${HEADER_DIR}/internal/catch_tostring.h
|
||||
${HEADER_DIR}/internal/catch_tostring.hpp
|
||||
${HEADER_DIR}/internal/catch_totals.hpp
|
||||
${HEADER_DIR}/internal/catch_type_traits.hpp
|
||||
${HEADER_DIR}/internal/catch_version.h
|
||||
${HEADER_DIR}/internal/catch_version.hpp
|
||||
${HEADER_DIR}/internal/catch_wildcard_pattern.hpp
|
||||
${HEADER_DIR}/internal/catch_windows_h_proxy.h
|
||||
${HEADER_DIR}/internal/catch_xmlwriter.hpp
|
||||
)
|
||||
CheckFileList(INTERNAL_HEADERS ${HEADER_DIR}/internal)
|
||||
|
||||
# Please keep these ordered alphabetically
|
||||
set(REPORTER_HEADERS
|
||||
${HEADER_DIR}/reporters/catch_reporter_automake.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_bases.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_compact.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_console.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_junit.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_multi.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_tap.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
|
||||
${HEADER_DIR}/reporters/catch_reporter_xml.hpp
|
||||
)
|
||||
CheckFileList(REPORTER_HEADERS ${HEADER_DIR}/reporters)
|
||||
|
||||
# Specify the headers, too, so CLion recognises them as project files
|
||||
set(HEADERS
|
||||
${TOP_LEVEL_HEADERS}
|
||||
${EXTERNAL_HEADERS}
|
||||
${INTERNAL_HEADERS}
|
||||
${REPORTER_HEADERS}
|
||||
)
|
||||
|
||||
|
||||
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 ${IMPL_SOURCES})
|
||||
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
|
||||
|
||||
# configure the executable
|
||||
include_directories(${HEADER_DIR})
|
||||
|
||||
# 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} ${HEADERS})
|
||||
add_executable(Benchmark ${BENCH_SOURCES} ${HEADERS})
|
||||
|
||||
# Add desired warnings
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
|
||||
target_compile_options( SelfTest PRIVATE -Wall -Wextra )
|
||||
target_compile_options( Benchmark PRIVATE -Wall -Wextra )
|
||||
endif()
|
||||
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
|
||||
target_compile_options( SelfTest PRIVATE /W4 /w44265 /WX )
|
||||
target_compile_options( Benchmark PRIVATE /W4 )
|
||||
endif()
|
||||
|
||||
|
||||
# configure unit tests via CTest
|
||||
enable_testing()
|
||||
add_test(NAME RunTests COMMAND SelfTest)
|
||||
|
||||
add_test(NAME ListTests COMMAND SelfTest --list-tests)
|
||||
set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases")
|
||||
|
||||
add_test(NAME ListTags COMMAND SelfTest --list-tags)
|
||||
set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
|
||||
|
||||
endif() # !NO_SELFTEST
|
||||
|
||||
|
||||
install(DIRECTORY "single_include/" DESTINATION "include/catch")
|
13
README.md
13
README.md
@ -1,12 +1,10 @@
|
||||

|
||||
|
||||
*v1.2.1-develop.16*
|
||||
[](https://github.com/philsquared/catch/releases)
|
||||
[](https://travis-ci.org/philsquared/Catch)
|
||||
[](https://ci.appveyor.com/project/philsquared/catch/branch/master)
|
||||
|
||||
Build status (on Travis CI) [](https://travis-ci.org/philsquared/Catch)
|
||||
|
||||
[Please see this page if you are updating from a version before 1.0](docs/whats-changed.md)
|
||||
|
||||
<a href="https://raw.githubusercontent.com/philsquared/Catch/master/single_include/catch.hpp">[The latest, single header, version can be downloaded directly using this link]</a>
|
||||
<a href="https://github.com/philsquared/Catch/releases/download/v1.9.5/catch.hpp">The latest, single header, version can be downloaded directly using this link</a>
|
||||
|
||||
## What's the Catch?
|
||||
|
||||
@ -19,8 +17,7 @@ This documentation comprises these three parts:
|
||||
* [Tutorial](docs/tutorial.md) - getting started
|
||||
* [Reference section](docs/Readme.md) - all the details
|
||||
|
||||
The documentation will continue until morale improves
|
||||
|
||||
## More
|
||||
* Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/philsquared/Catch/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)
|
||||
|
61
appveyor.yml
Normal file
61
appveyor.yml
Normal file
@ -0,0 +1,61 @@
|
||||
# version string format -- This will be overwritten later anyway
|
||||
version: "{build}"
|
||||
|
||||
os:
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2013
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- additional_flags: "/permissive- /std:c++latest"
|
||||
wmain: 0
|
||||
|
||||
- additional_flags: ""
|
||||
wmain: 0
|
||||
|
||||
- additional_flags: "/D_UNICODE /DUNICODE"
|
||||
wmain: 1
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
-
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
os: Visual Studio 2015
|
||||
-
|
||||
additional_flags: "/permissive- /std:c++latest"
|
||||
os: Visual Studio 2013
|
||||
|
||||
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)"
|
||||
|
||||
# fetch repository as zip archive
|
||||
shallow_clone: true
|
||||
|
||||
# Win32 and x64 are CMake-compatible solution platform names.
|
||||
# This allows us to pass %PLATFORM% to CMake -A.
|
||||
platform:
|
||||
- Win32
|
||||
- x64
|
||||
|
||||
# build Configurations, i.e. Debug, Release, etc.
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
#Cmake will autodetect the compiler, but we set the arch
|
||||
before_build:
|
||||
- set CXXFLAGS=%additional_flags%
|
||||
- cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
|
||||
|
||||
# build with MSBuild
|
||||
build:
|
||||
project: Build\CatchSelfTest.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%
|
BIN
catch-hand-icon.png
Normal file
BIN
catch-hand-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
BIN
catch-icon-tiny.png
Normal file
BIN
catch-icon-tiny.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 19 KiB |
149
contrib/ParseAndAddCatchTests.cmake
Normal file
149
contrib/ParseAndAddCatchTests.cmake
Normal file
@ -0,0 +1,149 @@
|
||||
#==================================================================================================#
|
||||
# supported macros #
|
||||
# - TEST_CASE, #
|
||||
# - SCENARIO, #
|
||||
# - TEST_CASE_METHOD, #
|
||||
# - CATCH_TEST_CASE, #
|
||||
# - CATCH_SCENARIO, #
|
||||
# - CATCH_TEST_CASE_METHOD. #
|
||||
# #
|
||||
# Usage #
|
||||
# 1. make sure this module is in the path or add this otherwise: #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# 2. make sure that you've enabled testing option for the project by the call: #
|
||||
# enable_testing() #
|
||||
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
||||
# project(testing_target) #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# enable_testing() #
|
||||
# #
|
||||
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
|
||||
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
|
||||
# #
|
||||
# file(GLOB SOURCE_FILES "*.cpp") #
|
||||
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
||||
# #
|
||||
# include(ParseAndAddCatchTests) #
|
||||
# ParseAndAddCatchTests(${PROJECT_NAME}) #
|
||||
# #
|
||||
# The following variables affect the behavior of the script: #
|
||||
# #
|
||||
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
|
||||
# -- enables debug messages #
|
||||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
||||
|
||||
function(PrintDebugMessage)
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# This removes the contents between
|
||||
# - block comments (i.e. /* ... */)
|
||||
# - full line comments (i.e. // ... )
|
||||
# contents have been read into '${CppCode}'.
|
||||
# !keep partial line comments
|
||||
function(RemoveComments CppCode)
|
||||
string(ASCII 2 CMakeBeginBlockComment)
|
||||
string(ASCII 3 CMakeEndBlockComment)
|
||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
||||
|
||||
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Worker function
|
||||
function(ParseFile SourceFile TestTarget)
|
||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||
if(NOT EXISTS ${SourceFile})
|
||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||
return()
|
||||
endif()
|
||||
PrintDebugMessage("parsing ${SourceFile}")
|
||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
RemoveComments(Contents)
|
||||
|
||||
# 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}")
|
||||
|
||||
foreach(TestName ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
|
||||
# Strip wrapping quotation marks
|
||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||
|
||||
# Validate that a test name and tags have been provided
|
||||
list(LENGTH TestStrings TestStringsLength)
|
||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||
endif()
|
||||
|
||||
# Assign name and tags
|
||||
list(GET TestStrings 0 Name)
|
||||
if("${TestType}" STREQUAL "SCENARIO")
|
||||
set(Name "Scenario: ${Name}")
|
||||
endif()
|
||||
if(TestFixture)
|
||||
set(CTestName "${TestFixture}:${Name}")
|
||||
else()
|
||||
set(CTestName "${Name}")
|
||||
endif()
|
||||
set(CTestName "${TestTarget}:${CTestName}")
|
||||
# add target to labels to enable running all tests added from this target
|
||||
set(Labels ${TestTarget})
|
||||
if(TestStringsLength EQUAL 2)
|
||||
list(GET TestStrings 1 Tags)
|
||||
string(TOLOWER "${Tags}" Tags)
|
||||
# remove target from labels if the test is hidden
|
||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||
list(REMOVE_ITEM Labels ${TestTarget})
|
||||
endif()
|
||||
string(REPLACE "]" ";" Tags "${Tags}")
|
||||
string(REPLACE "[" "" Tags "${Tags}")
|
||||
endif()
|
||||
|
||||
list(APPEND Labels ${Tags})
|
||||
|
||||
PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
if(Labels)
|
||||
PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddCatchTests TestTarget)
|
||||
PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||
endfunction()
|
@ -1,20 +1,30 @@
|
||||
These are the currently documented areas of the framework. There is more to come.
|
||||
|
||||
Before looking at this material be sure to read the [tutorial](tutorial.md)
|
||||
To get the most out of Catch, start with the [tutorial](tutorial.md).
|
||||
Once you're up and running consider the following reference material.
|
||||
|
||||
Writing tests:
|
||||
* [Assertion macros](assertions.md)
|
||||
* [Matchers](matchers.md)
|
||||
* [Logging macros](logging.md)
|
||||
* [Test cases and sections](test-cases-and-sections.md)
|
||||
* [Test fixtures](test-fixtures.md)
|
||||
* [Command line](command-line.md)
|
||||
* [Build systems](build-systems.md)
|
||||
* [Reporters](reporters.md)
|
||||
* [Event Listeners](event-listeners.md)
|
||||
|
||||
Fine tuning:
|
||||
* [Supplying your own main()](own-main.md)
|
||||
* [Configuration](configuration.md)
|
||||
* [Compile-time configuration](configuration.md)
|
||||
* [String Conversions](tostring.md)
|
||||
|
||||
Running:
|
||||
* [Command line](command-line.md)
|
||||
* [CI and Build system integration](build-systems.md)
|
||||
|
||||
FAQ:
|
||||
* [Why are my tests slow to compile?](slow-compiles.md)
|
||||
|
||||
Other
|
||||
|
||||
* [Known limitations](limitations.md)
|
||||
|
||||
Other:
|
||||
* [Why Catch?](why-catch.md)
|
||||
* [What's changed](whats-changed.md)
|
||||
* [Open Source Projects using Catch](opensource-users.md)
|
||||
* [Contributing](contributing.md)
|
||||
* [Release Notes](release-notes.md)
|
||||
|
@ -34,6 +34,15 @@ Example:
|
||||
REQUIRE_FALSE( thisReturnsFalse() );
|
||||
```
|
||||
|
||||
Do note that "overly complex" expressions cannot be decomposed and thus will not compile. This is done partly for practical reasons (to keep the underlying expression template machinery to minimum) and partly for philosophical reasons (assertions should be simple and deterministic).
|
||||
|
||||
Examples:
|
||||
* `CHECK(a == 1 && b == 2);`
|
||||
This expression is too complex because of the `&&` operator. If you want to check that 2 or more properties hold, you can either put the expression into parenthesis, which stops decomposition from working, or you need to decompose the expression into two assertions: `CHECK( a == 1 ); CHECK( b == 2);`
|
||||
* `CHECK( a == 2 || b == 1 );`
|
||||
This expression is too complex because of the `||` operator. If you want to check that one of several properties hold, you can put the expression into parenthesis (unlike with `&&`, expression decomposition into several `CHECK`s is not possible).
|
||||
|
||||
|
||||
### Floating point comparisons
|
||||
|
||||
When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
|
||||
@ -44,16 +53,40 @@ Catch provides a way to perform tolerant comparisons of floating point values th
|
||||
REQUIRE( performComputation() == Approx( 2.1 ) );
|
||||
```
|
||||
|
||||
By default a small epsilon value is used that covers many simple cases of rounding errors. When this is insufficent the epsilon value (the amount within which a difference either way is ignored) can be specified by calling the ```epsilon()``` method on the ```Approx``` instance. e.g.:
|
||||
This way `Approx` is constructed with reasonable defaults, covering most simple cases of rounding errors. If these are insufficient, each `Approx` instance has 3 tuning knobs, that can be used to customize it for your computation.
|
||||
|
||||
```
|
||||
REQUIRE( 22/7 == Approx( 3.141 ).epsilon( 0.01 ) );
|
||||
* __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`.
|
||||
|
||||
#### epsilon example
|
||||
```cpp
|
||||
Approx target = Approx(100).epsilon(0.01);
|
||||
100.0 == target; // Obviously true
|
||||
200.0 == target; // Obviously still false
|
||||
100.5 == target; // True, because we set target to allow up to 1% error
|
||||
```
|
||||
|
||||
When dealing with very large or very small numbers it can be useful to specify a scale, which can be achieved by calling the ```scale()``` method on the ```Approx``` instance.
|
||||
#### margin example
|
||||
_Margin check is used only if the relative (epsilon and scale based) check fails._
|
||||
```cpp
|
||||
Approx target = Approx(100).margin(5);
|
||||
100.0 == target; // Obviously true
|
||||
200.0 == target; // Obviously still false
|
||||
104.0 == target; // True, because we set target to allow absolute error up to 5
|
||||
```
|
||||
|
||||
#### 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).
|
||||
|
||||
|
||||
## Exceptions
|
||||
|
||||
* **REQUIRE_NOTHROW(** _expression_ **)** and
|
||||
* **CHECK_NOTHROW(** _expression_ **)**
|
||||
|
||||
Expects that no exception is thrown during evaluation of the expression.
|
||||
|
||||
* **REQUIRE_THROWS(** _expression_ **)** and
|
||||
* **CHECK_THROWS(** _expression_ **)**
|
||||
|
||||
@ -62,20 +95,46 @@ Expects that an exception (of any type) is be thrown during evaluation of the ex
|
||||
* **REQUIRE_THROWS_AS(** _expression_, _exception type_ **)** and
|
||||
* **CHECK_THROWS_AS(** _expression_, _exception type_ **)**
|
||||
|
||||
Expects that an exception of the _specified type_ is thrown during evaluation of the expression.
|
||||
Expects that an exception of the _specified type_ is thrown during evaluation of the expression. Note that the _exception type_ is used verbatim and you should include (const) reference.
|
||||
|
||||
* **REQUIRE_NOTHROW(** _expression_ **)** and
|
||||
* **CHECK_NOTHROW(** _expression_ **)**
|
||||
* **REQUIRE_THROWS_WITH(** _expression_, _string or string matcher_ **)** and
|
||||
* **CHECK_THROWS_WITH(** _expression_, _string or string matcher_ **)**
|
||||
|
||||
Expects that no exception is thrown during evaluation of the expression.
|
||||
Expects that an exception is thrown that, when converted to a string, matches the _string_ or _string matcher_ provided (see next section for Matchers).
|
||||
|
||||
e.g.
|
||||
```cpp
|
||||
REQUIRE_THROWS_WITH( openThePodBayDoors(), Contains( "afraid" ) && Contains( "can't do that" ) );
|
||||
REQUIRE_THROWS_WITH( dismantleHal(), "My mind is going" );
|
||||
```
|
||||
|
||||
|
||||
Please note that the `THROW` family of assertions expects to be passed a single expression, not a statement or series of statements. If you want to check a more complicated sequence of operations, you can use a C++11 lambda function.
|
||||
|
||||
```cpp
|
||||
REQUIRE_NOTHROW([&](){
|
||||
int i = 1;
|
||||
int j = 2;
|
||||
auto k = i + j;
|
||||
if (k == 3) {
|
||||
throw 1;
|
||||
}
|
||||
}());
|
||||
```
|
||||
|
||||
## Matcher expressions
|
||||
|
||||
To support Matchers a slightly different form is used. Matchers will be more fully documented elsewhere. *Note that Matchers are still at early stage development and are subject to change.*
|
||||
To support Matchers a slightly different form is used. Matchers have [their own documentation](matchers.md).
|
||||
|
||||
* **REQUIRE_THAT(** _lhs_, _matcher call_ **)** and
|
||||
* **CHECK_THAT(** _lhs_, _matcher call_ **)**
|
||||
* **REQUIRE_THAT(** _lhs_, _matcher expression_ **)** and
|
||||
* **CHECK_THAT(** _lhs_, _matcher expression_ **)**
|
||||
|
||||
Matchers can be composed using `&&`, `||` and `!` operators.
|
||||
|
||||
## Thread Safety
|
||||
|
||||
Currently assertions in Catch are not thread safe.
|
||||
For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Integration with build systems
|
||||
# CI and build system integration
|
||||
|
||||
Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
|
||||
|
||||
# Continuous Integration systems
|
||||
|
||||
Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (as has been done with TeamCity).
|
||||
Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP and Automake reporters).
|
||||
|
||||
Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
|
||||
|
||||
@ -26,14 +26,8 @@ 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.
|
||||
|
||||
## TeamCity Reporter
|
||||
```-r teamcity```
|
||||
|
||||
The TeamCity Reporter writes TeamCity service messages to stdout. In order to be able to use this reporter an additional header must also be included.
|
||||
|
||||
```catch_reporter_teamcity.hpp``` can be found in the ```include\reporters``` directory. It should be included in the same file that ```#define```s ```CATCH_CONFIG_MAIN``` or ```CATCH_CONFIG_RUNNER```. The ```#include``` should be placed after ```#include```ing Catch itself.
|
||||
|
||||
e.g.:
|
||||
## 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.
|
||||
|
||||
```
|
||||
#define CATCH_CONFIG_MAIN
|
||||
@ -41,14 +35,47 @@ e.g.:
|
||||
#include "catch_reporter_teamcity.hpp"
|
||||
```
|
||||
|
||||
### TeamCity Reporter
|
||||
```-r teamcity```
|
||||
|
||||
The TeamCity Reporter writes TeamCity service messages to stdout. In order to be able to use this reporter an additional header must also be included.
|
||||
|
||||
Being specific to TeamCity this is the best reporter to use with it - but it is completely unsuitable for any other purpose. It is a streaming format (it writes as it goes) - although test results don't appear in the TeamCity interface until the completion of a suite (usually the whole test run).
|
||||
|
||||
### Automake Reporter
|
||||
```-r automake```
|
||||
|
||||
The Automake Reporter writes out the [meta tags](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html#Log-files-generation-and-test-results-recording) expected by automake via `make check`.
|
||||
|
||||
### TAP (Test Anything Protocol) Reporter
|
||||
```-r tap```
|
||||
|
||||
Because of the incremental nature of Catch's test suites and ability to run specific tests, our implementation of TAP reporter writes out the number of tests in a suite last.
|
||||
|
||||
# Low-level tools
|
||||
|
||||
## CMake
|
||||
|
||||
You can use the following CMake script to automatically fetch Catch from github and configure it as an external project:
|
||||
In general we recommend "vendoring" Catch's single-include releases inside your own repository. If you do this, the following example shows a minimal CMake project:
|
||||
```CMake
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(cmake_test)
|
||||
|
||||
# Prepare "Catch" library for other executables
|
||||
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/catch)
|
||||
add_library(Catch INTERFACE)
|
||||
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
|
||||
|
||||
# Make test executable
|
||||
set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
|
||||
add_executable(tests ${TEST_SOURCES})
|
||||
target_link_libraries(tests Catch)
|
||||
```
|
||||
Note that it assumes that the path to the Catch's header is `catch/catch.hpp` from the `CMakeLists.txt` file.
|
||||
|
||||
|
||||
You can also use the following CMake snippet to automatically fetch the entire Catch repository from github and configure it as an external project:
|
||||
```CMake
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
project(catch_builder CXX)
|
||||
@ -69,7 +96,7 @@ ExternalProject_Add(
|
||||
|
||||
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
||||
ExternalProject_Get_Property(catch source_dir)
|
||||
set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch")
|
||||
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
||||
```
|
||||
|
||||
If you put it in, e.g., `${PROJECT_SRC_DIR}/${EXT_PROJECTS_DIR}/catch/`, you can use it in your project by adding the following to your root CMake file:
|
||||
@ -81,6 +108,36 @@ include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
|
||||
enable_testing(true) # Enables unit-testing.
|
||||
```
|
||||
|
||||
The advantage of this approach is that you can always automatically update Catch to the latest release. The disadvantage is that it means bringing in lot more than you need.
|
||||
|
||||
|
||||
### Automatic test registration
|
||||
If you are also using ctest, `contrib/ParseAndAddCatchTests.cmake` is a CMake script that attempts to parse your test files and automatically register all test cases, using tags as labels. This means that these
|
||||
```cpp
|
||||
TEST_CASE("Test1", "[unit]") {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
|
||||
TEST_CASE("Test2") {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
|
||||
TEST_CASE("Test3", "[a][b][c]") {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
```
|
||||
would be registered as 3 tests, `Test1`, `Test2` and `Test3`, and ctest 4 labels would be created, `a`, `b`, `c` and `unit`.
|
||||
|
||||
### CodeCoverage module (GCOV, LCOV...)
|
||||
|
||||
If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
@ -17,6 +17,9 @@ Click one of the followings links to take you straight to that option - or scrol
|
||||
<a href="#warnings"> ` -w, --warn`</a><br />
|
||||
<a href="#reporting-timings"> ` -d, --durations`</a><br />
|
||||
<a href="#input-file"> ` -f, --input-file`</a><br />
|
||||
<a href="#run-section"> ` -c, --section`</a><br />
|
||||
<a href="#filenames-as-tags"> ` -#, --filenames-as-tags`</a><br />
|
||||
|
||||
|
||||
</br>
|
||||
|
||||
@ -66,6 +69,8 @@ A series of tags form an AND expression wheras a comma-separated sequence forms
|
||||
<pre>[one][two],[three]</pre>
|
||||
This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
|
||||
|
||||
Test names containing special characters, such as `,` or `[` can specify them on the command line using `\`.
|
||||
`\` also escapes itself.
|
||||
|
||||
<a id="choosing-a-reporter-to-use"></a>
|
||||
## Choosing a reporter to use
|
||||
@ -88,7 +93,6 @@ The JUnit reporter is an xml format that follows the structure of the JUnit XML
|
||||
<pre>-b, --break</pre>
|
||||
|
||||
In some IDEs (currently XCode and Visual Studio) it is possible for Catch to break into the debugger on a test failure. This can be very helpful during debug sessions - especially when there is more than one path through a particular test.
|
||||
In addition to the command line option, ensure you have built your code with the DEBUG preprocessor symbol
|
||||
|
||||
<a id="showing-results-for-successful-tests"></a>
|
||||
## Showing results for successful tests
|
||||
@ -115,7 +119,7 @@ Sometimes this results in a flood of failure messages and you'd rather just see
|
||||
--list-reporters
|
||||
</pre>
|
||||
|
||||
```-l``` or ```--list-tests`` will list all registered tests, along with any tags.
|
||||
```-l``` or ```--list-tests``` will list all registered tests, along with any tags.
|
||||
If one or more test-specs have been supplied too then only the matching tests will be listed.
|
||||
|
||||
```-t``` or ```--list-tags``` lists all available tags, along with the number of test cases they match. Again, supplying test specs limits the tags that match.
|
||||
@ -215,6 +219,59 @@ In either case the actual value for the seed is printed as part of Catch's outpu
|
||||
|
||||
Prints the command line arguments to stdout
|
||||
|
||||
|
||||
<a id="run-section"></a>
|
||||
## Specify the section to run
|
||||
<pre>-c, --section <section name></pre>
|
||||
|
||||
To limit execution to a specific section within a test case, use this option one or more times.
|
||||
To narrow to sub-sections use multiple instances, where each subsequent instance specifies a deeper nesting level.
|
||||
|
||||
E.g. if you have:
|
||||
|
||||
<pre>
|
||||
TEST_CASE( "Test" ) {
|
||||
SECTION( "sa" ) {
|
||||
SECTION( "sb" ) {
|
||||
/*...*/
|
||||
}
|
||||
SECTION( "sc" ) {
|
||||
/*...*/
|
||||
}
|
||||
}
|
||||
SECTION( "sd" ) {
|
||||
/*...*/
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
Then you can run `sb` with:
|
||||
<pre>./MyExe Test -c sa -c sb</pre>
|
||||
|
||||
Or run just `sd` with:
|
||||
<pre>./MyExe Test -c sd</pre>
|
||||
|
||||
To run all of `sa`, including `sb` and `sc` use:
|
||||
<pre>./MyExe Test -c sa</pre>
|
||||
|
||||
There are some limitations of this feature to be aware of:
|
||||
- Code outside of sections being skipped will still be executed - e.g. any set-up code in the TEST_CASE before the
|
||||
start of the first section.</br>
|
||||
- At time of writing, wildcards are not supported in section names.
|
||||
- If you specify a section without narrowing to a test case first then all test cases will be executed
|
||||
(but only matching sections within them).
|
||||
|
||||
|
||||
<a id="filenames-as-tags"></a>
|
||||
## Filenames as tags
|
||||
<pre>-#, --filenames-as-tags</pre>
|
||||
|
||||
When this option is used then every test is given an additional tag which is formed of the unqualified
|
||||
filename it is found in, with any extension stripped, prefixed with the `#` character.
|
||||
|
||||
So, for example, tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
16
docs/commercial-users.md
Normal file
16
docs/commercial-users.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Commercial users of Catch
|
||||
|
||||
As well as [Open Source](opensource-users.md) users Catch is widely used within proprietary code bases too.
|
||||
Many organisations like to keep this information internal, and that's fine,
|
||||
but if you're more open it would be great if we could list the names of as
|
||||
many organisations as possible that use Catch somewhere in their codebase.
|
||||
Enterprise environments often tend to be far more conservative in their tool adoption -
|
||||
and being aware that other companies are using Catch can ease the path in.
|
||||
|
||||
So if you are aware of Catch usage in your organisation, and are fairly confident there is no issue with sharing this
|
||||
fact then please let us know - either directly, via a PR or
|
||||
[issue](https://github.com/philsquared/Catch/issues), or on the [forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum).
|
||||
|
||||
- Bloomberg
|
||||
- NASA
|
||||
- [Inscopix Inc.](https://www.inscopix.com/)
|
@ -1,6 +1,6 @@
|
||||
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```).
|
||||
|
||||
Nonetheless there are still some occasions where finer control is needed. For these occasions Catch exposes a small set of macros for configuring how it is built.
|
||||
Nonetheless there are still some occasions where finer control is needed. For these occasions Catch exposes a set of macros for configuring how it is built.
|
||||
|
||||
# main()/ implementation
|
||||
|
||||
@ -52,15 +52,18 @@ This can be useful on certain platforms that do not provide ```std::cout``` and
|
||||
|
||||
# C++ conformance toggles
|
||||
|
||||
CATCH_CONFIG_CPP11_NULLPTR // nullptr is supported?
|
||||
CATCH_CONFIG_CPP11_NOEXCEPT // noexcept is supported?
|
||||
CATCH_CONFIG_CPP11_GENERATED_METHODS // delete and default keywords for methods
|
||||
CATCH_CONFIG_CPP11_IS_ENUM // std::is_enum is supported?
|
||||
CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported
|
||||
CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient
|
||||
CATCH_CONFIG_CPP11_LONG_LONG // generates overloads for the long long type
|
||||
CATCH_CONFIG_CPP11_OVERRIDE // CATCH_OVERRIDE expands to override (for virtual function implementations)
|
||||
CATCH_CONFIG_CPP11_UNIQUE_PTR // Use std::unique_ptr instead of std::auto_ptr
|
||||
CATCH_CONFIG_CPP11_NULLPTR // nullptr is supported?
|
||||
CATCH_CONFIG_CPP11_NOEXCEPT // noexcept is supported?
|
||||
CATCH_CONFIG_CPP11_GENERATED_METHODS // delete and default keywords for methods
|
||||
CATCH_CONFIG_CPP11_IS_ENUM // std::is_enum is supported?
|
||||
CATCH_CONFIG_CPP11_TUPLE // std::tuple is supported
|
||||
CATCH_CONFIG_VARIADIC_MACROS // Usually pre-C++11 compiler extensions are sufficient
|
||||
CATCH_CONFIG_CPP11_LONG_LONG // generates overloads for the long long type
|
||||
CATCH_CONFIG_CPP11_OVERRIDE // CATCH_OVERRIDE expands to override (for virtual function implementations)
|
||||
CATCH_CONFIG_CPP11_UNIQUE_PTR // Use std::unique_ptr instead of std::auto_ptr
|
||||
CATCH_CONFIG_CPP11_SHUFFLE // Use std::shuffle instead of std::random_shuffle
|
||||
CATCH_CONFIG_CPP11_TYPE_TRAITS // Use std::enable_if and <type_traits>
|
||||
CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK // Use C++11 expression SFINAE to check if class can be inserted to std::ostream
|
||||
|
||||
Catch has some basic compiler detection that will attempt to select the appropriate mix of these macros. However being incomplete - and often without access to the respective compilers - this detection tends to be conservative.
|
||||
So overriding control is given to the user. If a compiler supports a feature (and Catch does not already detect it) then one or more of these may be defined to enable it (or suppress it, in some cases). If you do do this please raise an issue, specifying your compiler version (ideally with an idea of how to detect it) and stating that it has such support.
|
||||
@ -68,6 +71,58 @@ You may also suppress any of these features by using the `_NO_` form, e.g. `CATC
|
||||
|
||||
All C++11 support can be disabled with `CATCH_CONFIG_NO_CPP11`
|
||||
|
||||
## `CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK`
|
||||
|
||||
This flag is off by default, but allows you to resolve problems caused by types with private base class that are streamable, but the classes themselves are not. Without it, the following code will cause a compilation error:
|
||||
```cpp
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
||||
struct A {};
|
||||
std::ostream &operator<< (std::ostream &o, const A &v) { return o << 0; }
|
||||
|
||||
struct B : private A {
|
||||
bool operator==(int){ return true;}
|
||||
};
|
||||
|
||||
B f ();
|
||||
std::ostream g ();
|
||||
|
||||
TEST_CASE ("Error in streamable check") {
|
||||
B x;
|
||||
REQUIRE (x == 4);
|
||||
}
|
||||
```
|
||||
|
||||
# Other toggles
|
||||
|
||||
CATCH_CONFIG_COUNTER // Use __COUNTER__ to generate unique names for test cases
|
||||
CATCH_CONFIG_WINDOWS_SEH // Enable SEH handling on Windows
|
||||
CATCH_CONFIG_FAST_COMPILE // Sacrifices some (rather minor) features for compilation speed
|
||||
CATCH_CONFIG_POSIX_SIGNALS // Enable handling POSIX signals
|
||||
CATCH_CONFIG_WINDOWS_CRTDBG // Enable leak checking using Windows's CRT Debug Heap
|
||||
|
||||
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.
|
||||
|
||||
`CATCH_CONFIG_POSIX_SIGNALS` is on by default, except when Catch is compiled under `Cygwin`, where it is disabled by default (but can be force-enabled by defining `CATCH_CONFIG_POSIX_SIGNALS`).
|
||||
|
||||
`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.
|
||||
|
||||
Just as with the C++11 conformance toggles, 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*.
|
||||
* The `REQUIRE` family of macros (`REQUIRE`, `REQUIRE_FALSE` and `REQUIRE_THAT`) no longer uses 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.
|
||||
|
||||
# Windows header clutter
|
||||
|
||||
On Windows Catch includes `windows.h`. To minimize global namespace clutter in the implementation file, it defines `NOMINMAX` and `WIN32_LEAN_AND_MEAN` before including it. You can control this behaviour via two macros:
|
||||
|
||||
CATCH_CONFIG_NO_NOMINMAX // Stops Catch from using NOMINMAX macro
|
||||
CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN // Stops Catch from using WIN32_LEAN_AND_MEAN macro
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
@ -1,22 +1,40 @@
|
||||
# Contributing to Catch
|
||||
|
||||
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated. Of course so are bug reports and other comments and questions.
|
||||
So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
|
||||
additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
|
||||
Of course so are bug reports and other comments and questions.
|
||||
|
||||
If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to help you find your way around. As this is liable to drift out of date please raise an issue or, better still, a pull request for this file, if you notice that.
|
||||
If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to
|
||||
help you find your way around. As this is liable to drift out of date please raise an issue or, better still, a pull
|
||||
request for this file, if you notice that.
|
||||
|
||||
## Branches
|
||||
|
||||
Ongoing development is on the "develop" branch (if there is one, currently), or on feature branches that are branched off of develop. Please target any pull requests at develop, or, for larger chunks of work, a branch off of develop.
|
||||
Ongoing development is currently on _master_. At some point an integration branch will be set-up and PRs should target
|
||||
that - but for now it's all against master. You may see feature branches come and go from time to time, too.
|
||||
|
||||
## Directory structure
|
||||
|
||||
Users of Catch primarily use the single header version. Maintainers should work with the full source (which is still, primarily, in headers). This can be found in the ```include``` folder, but you may prefer to use one of the IDE project files (for MSVC or XCode). These can be found under ```projects/```*IDE Name*```/```*project name*. A number of contributors have proposed make files, and submitted their own versions. At some point these should be made available too.
|
||||
_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
|
||||
primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
|
||||
`projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
|
||||
project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion
|
||||
that can work with the CMake file directly.
|
||||
|
||||
In addition to the include files and IDE projects there are a number of tests in cpp files. These can all be found in ```projects/SelfTest```. You'll also see a ```SurrogateCpps``` directory in there. This contains a set of cpp files that each ```#include``` a single header. While these files are not essential to compilation they help to keep the implementation headers self-contained. At time of writing this set is not complete but has reasonable coverage. If you add additional headers please try to remember to add a surrogate cpp for it.
|
||||
As well as the runtime test files you'll also see a `SurrogateCpps` directory under `projects/SelfTest`.
|
||||
This contains a set of .cpp files that each `#include` a single header.
|
||||
While these files are not essential to compilation they help to keep the implementation headers self-contained.
|
||||
At time of writing this set is not complete but has reasonable coverage.
|
||||
If you add additional headers please try to remember to add a surrogate cpp for it.
|
||||
|
||||
The other directories are ```scripts``` which contains a set of python scripts to help in testing Catch as well as generating the single include, and docs, which contains the documentation as a set of markdown files.
|
||||
The other directories are `scripts` which contains a set of python scripts to help in testing Catch as well as
|
||||
generating the single include, and `docs`, which contains the documentation as a set of markdown files.
|
||||
|
||||
*this document is in-progress...*
|
||||
__When submitting a pull request please do not include changes to the single include, or to the version number file
|
||||
as these are managed by the scripts!__
|
||||
|
||||
|
||||
*this document is still in-progress...*
|
||||
|
||||
---
|
||||
|
||||
|
73
docs/event-listeners.md
Normal file
73
docs/event-listeners.md
Normal file
@ -0,0 +1,73 @@
|
||||
# Event Listeners
|
||||
|
||||
A `Listener` is a class you can register with Catch that will then be passed events,
|
||||
such as a test case starting or ending, as they happen during a test run.
|
||||
`Listeners` are actually types of `Reporters`, with a few small differences:
|
||||
|
||||
1. Once registered in code they are automatically used - you don't need to specify them on the command line
|
||||
2. They are called in addition to (just before) any reporters, and you can register multiple listeners.
|
||||
3. They derive from `Catch::TestEventListenerBase`, which has default stubs for all the events,
|
||||
so you are not forced to implement events you're not interested in.
|
||||
4. You register a listener with `CATCH_REGISTER_LISTENER`
|
||||
|
||||
|
||||
## Implementing a Listener
|
||||
|
||||
In your main source file (i.e. the one that has the `#define` for `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`),
|
||||
simply derive a class from `Catch::TestEventListenerBase` and implement the methods you are interested in.
|
||||
Then register it using `INTERNAL_CATCH_REGISTER_LISTENER`.
|
||||
|
||||
For example:
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
|
||||
struct MyListener : Catch::TestEventListenerBase {
|
||||
|
||||
using TestEventListenerBase::TestEventListenerBase; // inherit constructor
|
||||
|
||||
virtual void testCaseStarting( Catch::TestCaseInfo const& testInfo ) override {
|
||||
// Perform some setup before a test case is run
|
||||
}
|
||||
|
||||
virtual void testCaseEnded( Catch::TestCaseStats const& testCaseStats ) override {
|
||||
// Tear-down after a test case is run
|
||||
}
|
||||
};
|
||||
CATCH_REGISTER_LISTENER( MyListener )
|
||||
```
|
||||
|
||||
_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:
|
||||
|
||||
```c++
|
||||
// The whole test run, starting and ending
|
||||
virtual void testRunStarting( TestRunInfo const& testRunInfo );
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats );
|
||||
|
||||
// Test cases starting and ending
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo );
|
||||
virtual void testCaseEnded( TestCaseStats const& testCaseStats );
|
||||
|
||||
// Sections starting and ending
|
||||
virtual void sectionStarting( SectionInfo const& sectionInfo );
|
||||
virtual void sectionEnded( SectionStats const& sectionStats );
|
||||
|
||||
// Assertions before/ after
|
||||
virtual void assertionStarting( AssertionInfo const& assertionInfo );
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats );
|
||||
|
||||
// A test is being skipped (because it is "hidden")
|
||||
virtual void skipTest( TestCaseInfo const& testInfo );
|
||||
```
|
||||
|
||||
More information about the events (e.g. name of the test case) is contained in the structs passed as arguments -
|
||||
just look in the source code to see what fields are available.
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
99
docs/limitations.md
Normal file
99
docs/limitations.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Known limitations
|
||||
|
||||
Catch has some known limitations, that we are not planning to change. Some of these are caused by our desire to support C++98 compilers, some of these are caused by our desire to keep Catch crossplatform, some exist because their priority is seen as low compared to the development effort they would need and some other yet are compiler/runtime bugs.
|
||||
|
||||
## Features
|
||||
This section outlines some missing features, what is their status and their possible workarounds.
|
||||
|
||||
### Thread safe assertions
|
||||
Because threading support in standard C++98 is limited (well, non-existent), assertion macros in Catch are not thread safe. This does not mean that you cannot use threads inside Catch's test, but that only single thread can interact with Catch's assertions and other macros.
|
||||
|
||||
This means that this is ok
|
||||
```cpp
|
||||
std::vector<std::thread> threads;
|
||||
std::atomic<int> cnt{ 0 };
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
threads.emplace_back([&]() {
|
||||
++cnt; ++cnt; ++cnt; ++cnt;
|
||||
});
|
||||
}
|
||||
for (auto& t : threads) { t.join(); }
|
||||
REQUIRE(cnt == 16);
|
||||
```
|
||||
because only one thread passes the `REQUIRE` macro and this is not
|
||||
```cpp
|
||||
std::vector<std::thread> threads;
|
||||
std::atomic<int> cnt{ 0 };
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
threads.emplace_back([&]() {
|
||||
++cnt; ++cnt; ++cnt; ++cnt;
|
||||
CHECK(cnt == 16);
|
||||
});
|
||||
}
|
||||
for (auto& t : threads) { t.join(); }
|
||||
REQUIRE(cnt == 16);
|
||||
```
|
||||
|
||||
|
||||
_This limitation is highly unlikely to be lifted before Catch 2 is released._
|
||||
|
||||
### Process isolation in a test
|
||||
Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
|
||||
|
||||
### Running multiple tests in parallel
|
||||
Catch's test execution is strictly serial. If you find yourself with a test suite that takes too long to run and you want to make it parallel, there are 2 feasible solutions
|
||||
* You can split your tests into multiple binaries and then run these binaries in parallel.
|
||||
* You can have Catch list contained test cases and then run the same test binary multiple times in parallel, passing each instance list of test cases it should run.
|
||||
|
||||
Both of these solutions have their problems, but should let you wring parallelism out of your test suite.
|
||||
|
||||
## 3rd party bugs
|
||||
This section outlines known bugs in 3rd party components (this means compilers, standard libraries, standard runtimes).
|
||||
|
||||
### 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"
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
### 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
|
||||
```cpp
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("a") {
|
||||
CHECK_THROWS(throw 3);
|
||||
}
|
||||
|
||||
TEST_CASE("b") {
|
||||
int i = 0;
|
||||
SECTION("a") { i = 1; }
|
||||
SECTION("b") { i = 2; }
|
||||
CHECK(i > 0);
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
@ -1,6 +1,32 @@
|
||||
# Logging macros
|
||||
|
||||
Additional messages can be logged during a test case.
|
||||
Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
|
||||
|
||||
```cpp
|
||||
TEST_CASE("Foo") {
|
||||
INFO("Test case start");
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
INFO("The number is " << i);
|
||||
CHECK(i == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Bar") {
|
||||
INFO("Test case start");
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
INFO("The number is " << i);
|
||||
CHECK(i == i);
|
||||
}
|
||||
CHECK(false);
|
||||
}
|
||||
```
|
||||
When the `CHECK` fails in the "Foo" test case, then two messages will be printed.
|
||||
```
|
||||
Test case start
|
||||
The number is 1
|
||||
```
|
||||
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
|
||||
|
||||
|
||||
## Streaming macros
|
||||
|
||||
@ -26,6 +52,10 @@ The message is always reported but does not fail the test.
|
||||
|
||||
The message is reported and the test case fails.
|
||||
|
||||
**FAIL_CHECK(** _message expression_ **)**
|
||||
|
||||
AS `FAIL`, but does not abort the test
|
||||
|
||||
## Quickly capture a variable value
|
||||
|
||||
**CAPTURE(** _expression_ **)**
|
||||
|
103
docs/matchers.md
Normal file
103
docs/matchers.md
Normal file
@ -0,0 +1,103 @@
|
||||
# Matchers
|
||||
|
||||
Matchers are an alternative way to do assertions which are easily extensible and composable.
|
||||
This makes them well suited to use with more complex types (such as collections) or your own custom types.
|
||||
Matchers were first popularised by the [Hamcrest](https://en.wikipedia.org/wiki/Hamcrest) family of frameworks.
|
||||
|
||||
## In use
|
||||
|
||||
Matchers are introduced with the `REQUIRE_THAT` or `CHECK_THAT` macros, which take two arguments.
|
||||
The first argument is the thing (object or value) under test. The second part is a match _expression_,
|
||||
which consists of either a single matcher or one or more matchers combined using `&&`, `||` or `!` operators.
|
||||
|
||||
For example, to assert that a string ends with a certain substring:
|
||||
|
||||
```c++
|
||||
std::string str = getStringFromSomewhere();
|
||||
REQUIRE_THAT( str, EndsWith( "as a service" ) );
|
||||
```
|
||||
|
||||
The matcher objects can take multiple arguments, allowing more fine tuning.
|
||||
The built-in string matchers, for example, take a second argument specifying whether the comparison is
|
||||
case sensitive or not:
|
||||
|
||||
```c++
|
||||
REQUIRE_THAT( str, EndsWith( "as a service", Catch::CaseSensitive::No ) );
|
||||
```
|
||||
|
||||
And matchers can be combined:
|
||||
|
||||
```c++
|
||||
REQUIRE_THAT( str,
|
||||
EndsWith( "as a service" ) ||
|
||||
(StartsWith( "Big data" ) && !Contains( "web scale" ) ) );
|
||||
```
|
||||
|
||||
## Built in matchers
|
||||
Currently Catch has some string matchers and some vector matchers.
|
||||
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).
|
||||
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.
|
||||
|
||||
|
||||
## Custom matchers
|
||||
It's easy to provide your own matchers to extend Catch or just to work with your own types.
|
||||
|
||||
You need to provide two things:
|
||||
1. A matcher class, derived from `Catch::MatcherBase<T>` - where `T` is the type being tested.
|
||||
The constructor takes and stores any arguments needed (e.g. something to compare against) and you must
|
||||
override two methods: `match()` and `describe()`.
|
||||
2. A simple builder function. This is what is actually called from the test code and allows overloading.
|
||||
|
||||
Here's an example for asserting that an integer falls within a given range
|
||||
(note that it is all inline for the sake of keeping the example short):
|
||||
|
||||
```c++
|
||||
// The matcher class
|
||||
class IntRange : public Catch::MatcherBase<int> {
|
||||
int m_begin, m_end;
|
||||
public:
|
||||
IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}
|
||||
|
||||
// Performs the test for this matcher
|
||||
virtual bool match( int const& i ) const override {
|
||||
return i >= m_begin && i <= m_end;
|
||||
}
|
||||
|
||||
// Produces a string describing what this matcher does. It should
|
||||
// include any provided data (the begin/ end in this case) and
|
||||
// be written as if it were stating a fact (in the output it will be
|
||||
// preceded by the value under test).
|
||||
virtual std::string describe() const {
|
||||
std::ostringstream ss;
|
||||
ss << "is between " << m_begin << " and " << m_end;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// The builder function
|
||||
inline IntRange IsBetween( int begin, int end ) {
|
||||
return IntRange( begin, end );
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// Usage
|
||||
TEST_CASE("Integers are within a range")
|
||||
{
|
||||
CHECK_THAT( 3, IsBetween( 1, 10 ) );
|
||||
CHECK_THAT( 100, IsBetween( 1, 10 ) );
|
||||
}
|
||||
```
|
||||
|
||||
Running this test gives the following in the console:
|
||||
|
||||
```
|
||||
/**/TestFile.cpp:123: FAILED:
|
||||
CHECK_THAT( 100, IsBetween( 1, 10 ) )
|
||||
with expansion:
|
||||
100 is between 1 and 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
74
docs/opensource-users.md
Normal file
74
docs/opensource-users.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Open Source projects using Catch
|
||||
|
||||
Catch is great for open source. With it's [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
|
||||
[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 -
|
||||
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
|
||||
|
||||
### [Azmq](https://github.com/zeromq/azmq)
|
||||
Boost Asio style bindings for ZeroMQ
|
||||
|
||||
### [ChakraCore](https://github.com/Microsoft/ChakraCore)
|
||||
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
|
||||
|
||||
### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
|
||||
The next-generation core storage and query engine for Couchbase Lite/
|
||||
|
||||
### [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
|
||||
|
||||
### [nanodbc](https://github.com/lexicalunit/nanodbc/)
|
||||
A small C++ library wrapper for the native C ODBC API.
|
||||
|
||||
### [Nonius](https://github.com/libnonius/nonius)
|
||||
A header-only framework for benchmarking small snippets of C++ code.
|
||||
|
||||
### [SOCI](https://github.com/SOCI/soci)
|
||||
The C++ Database Access Library
|
||||
|
||||
### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
|
||||
A polymorphic value-type for C++
|
||||
|
||||
### [Ppconsul](https://github.com/oliora/ppconsul)
|
||||
A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure
|
||||
|
||||
### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
|
||||
A library of algorithms for values-distributed-in-time
|
||||
|
||||
### [Trompeloeil](https://github.com/rollbear/trompeloeil)
|
||||
A thread safe header only mocking framework for C++14
|
||||
|
||||
## Applications & Tools
|
||||
|
||||
### [ArangoDB](https://github.com/arangodb/arangodb)
|
||||
ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values.
|
||||
|
||||
### [MAME](https://github.com/mamedev/mame)
|
||||
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.
|
||||
|
||||
### [Standardese](https://github.com/foonathan/standardese)
|
||||
Standardese aims to be a nextgen Doxygen
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
@ -16,7 +16,7 @@ If you just need to have code that executes before and/ or after Catch this is t
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch.hpp"
|
||||
|
||||
int main( int argc, char* const argv[] )
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
// global setup...
|
||||
|
||||
@ -24,7 +24,7 @@ int main( int argc, char* const argv[] )
|
||||
|
||||
// global clean-up...
|
||||
|
||||
return result;
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
```
|
||||
|
||||
@ -36,9 +36,9 @@ If you still want Catch to process the command line, but you want to programatic
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch.hpp"
|
||||
|
||||
int main( int argc, char* const argv[] )
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
Catch::Session session; // There must be exactly once instance
|
||||
Catch::Session session; // There must be exactly one instance
|
||||
|
||||
// writing to session.configData() here sets defaults
|
||||
// this is the preferred way to set them
|
||||
@ -51,7 +51,11 @@ int main( int argc, char* const argv[] )
|
||||
// overrides command line args
|
||||
// only do this if you know you need to
|
||||
|
||||
return session.run();
|
||||
int numFailed = session.run();
|
||||
// Note that on unices only the lower 8 bits are usually used, clamping
|
||||
// the return value to 255 prevents false negative when some multiple
|
||||
// of 256 tests has failed
|
||||
return ( numFailed < 0xff ? numFailed : 0xff );
|
||||
}
|
||||
```
|
||||
|
||||
@ -65,4 +69,4 @@ Catch embeds a powerful command line parser which you can also use to parse your
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
280
docs/release-notes.md
Normal file
280
docs/release-notes.md
Normal file
@ -0,0 +1,280 @@
|
||||
# 1.9.5
|
||||
|
||||
### Fixes
|
||||
* Truthy expressions are now reconstructed properly, not as booleans (#914)
|
||||
* Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
|
||||
* Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
|
||||
* Fixed incorrect gcc version detection when deciding to use `__COUNTER__` (#928)
|
||||
* Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
|
||||
* Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
|
||||
|
||||
### Improvements
|
||||
* CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
|
||||
* Various documentation improvements
|
||||
|
||||
|
||||
|
||||
# 1.9.4
|
||||
|
||||
### Fixes
|
||||
* `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
|
||||
* `INFO` messages are no longer cleared after being reported once
|
||||
|
||||
### Improvements and minor changes
|
||||
* Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
|
||||
* Note that Catch still officially supports only ASCII
|
||||
|
||||
# 1.9.3
|
||||
|
||||
### Fixes
|
||||
* Completed the fix for (lack of) uint64_t in earlier Visual Studios
|
||||
|
||||
# 1.9.2
|
||||
|
||||
### Improvements and minor changes
|
||||
* All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
|
||||
* Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
|
||||
|
||||
|
||||
### Fixes
|
||||
* POSIX signals are now disabled by default under QNX (#889)
|
||||
* QNX does not support current enough (2001) POSIX specification
|
||||
* JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
|
||||
* `Catch::Option` should now have its storage properly aligned.
|
||||
* Catch no longer attempts to define `uint64_t` on windows (#862)
|
||||
* This was causing trouble when compiled under Cygwin
|
||||
|
||||
### Other
|
||||
* Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
|
||||
* We now provide cmake script that autoregisters Catch tests into ctest.
|
||||
* See `contrib` folder.
|
||||
|
||||
|
||||
# 1.9.1
|
||||
|
||||
### Fixes
|
||||
* Unexpected exceptions are no longer ignored by default (#885, #887)
|
||||
|
||||
|
||||
# 1.9.0
|
||||
|
||||
|
||||
### Improvements and minor changes
|
||||
* Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
|
||||
* It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
|
||||
* This actually reverts changes made in v1.7.2
|
||||
* Catch's `Version` struct should no longer be double freed when multiple instances of Catch tests are loaded into single program (#858)
|
||||
* It is now a static variable in an inline function instead of being an `extern`ed struct.
|
||||
* Attempt to register invalid tag or tag alias now throws instead of calling `exit()`.
|
||||
* Because this happen before entering main, it still aborts execution
|
||||
* Further improvements to this are coming
|
||||
* `CATCH_CONFIG_FAST_COMPILE` now speeds-up compilation of `REQUIRE*` assertions by further ~15%.
|
||||
* The trade-off is disabling translation of unexpected exceptions into text.
|
||||
* When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
|
||||
* Captured messages are now printed on unexpected exceptions
|
||||
|
||||
### Fixes:
|
||||
* Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
|
||||
* GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
|
||||
* This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
|
||||
* You can now tell Catch to use C++11-based check when checking whether a type can be streamed to output.
|
||||
* This fixes cases when an unstreamable type has streamable private base (#877)
|
||||
* [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
|
||||
|
||||
|
||||
### Other notes:
|
||||
* We have added VS 2017 to our CI
|
||||
* Work on Catch 2 should start soon
|
||||
|
||||
|
||||
|
||||
# 1.8.2
|
||||
|
||||
|
||||
### Improvements and minor changes
|
||||
* TAP reporter now behaves as if `-s` was always set
|
||||
* This should be more consistent with the protocol desired behaviour.
|
||||
* Compact reporter now obeys `-d yes` argument (#780)
|
||||
* The format is "XXX.123 s: <section-name>" (3 decimal places are always present).
|
||||
* Before it did not report the durations at all.
|
||||
* XML reporter now behaves the same way as Console reporter in regards to `INFO`
|
||||
* This means it reports `INFO` messages on success, if output on success (`-s`) is enabled.
|
||||
* Previously it only reported `INFO` messages on failure.
|
||||
* `CAPTURE(expr)` now stringifies `expr` in the same way assertion macros do (#639)
|
||||
* Listeners are now finally [documented](event-listeners.md).
|
||||
* Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
|
||||
|
||||
|
||||
### Fixes:
|
||||
* Catch no longer attempts to reconstruct expression that led to a fatal error (#810)
|
||||
* This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
|
||||
* Fixed (C4265) missing virtual destructor warning in Matchers (#844)
|
||||
* `std::string`s are now taken by `const&` everywhere (#842).
|
||||
* Previously some places were taking them by-value.
|
||||
* Catch should no longer change errno (#835).
|
||||
* This was caused by libstdc++ bug that we now work around.
|
||||
* Catch now provides `FAIL_CHECK( ... )` macro (#765).
|
||||
* Same as `FAIL( ... )`, but does not abort the test.
|
||||
* Functions like `fabs`, `tolower`, `memset`, `isalnum` are now used with `std::` qualification (#543).
|
||||
* Clara no longer assumes first argument (binary name) is always present (#729)
|
||||
* If it is missing, empty string is used as default.
|
||||
* Clara no longer reads 1 character past argument string (#830)
|
||||
* Regression in Objective-C bindings (Matchers) fixed (#854)
|
||||
|
||||
|
||||
### Other notes:
|
||||
* We have added VS 2013 and 2015 to our CI
|
||||
* Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
|
||||
|
||||
|
||||
|
||||
# 1.8.1
|
||||
|
||||
### Fixes
|
||||
|
||||
Cygwin issue with `gettimeofday` - `#define` was not early enough
|
||||
|
||||
# 1.8.0
|
||||
|
||||
### New features/ minor changes
|
||||
|
||||
* Matchers have new, simpler (and documented) interface.
|
||||
* Catch provides string and vector matchers.
|
||||
* For details see [Matchers documentation](matchers.md).
|
||||
* Changed console reporter test duration reporting format (#322)
|
||||
* Old format: `Some simple comparisons between doubles completed in 0.000123s`
|
||||
* New format: `xxx.123s: Some simple comparisons between doubles` _(There will always be exactly 3 decimal places)_
|
||||
* Added opt-in leak detection under MSVC + Windows (#439)
|
||||
* Enable it by compiling Catch's main with `CATCH_CONFIG_WINDOWS_CRTDBG`
|
||||
* Introduced new compile-time flag, `CATCH_CONFIG_FAST_COMPILE`, trading features for compilation speed.
|
||||
* Moves debug breaks out of tests and into implementation, speeding up test compilation time (~10% on linux).
|
||||
* _More changes are coming_
|
||||
* Added [TAP (Test Anything Protocol)](https://testanything.org/) and [Automake](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html#Log-files-generation-and-test-results-recording) reporters.
|
||||
* These are not present in the default single-include header and need to be downloaded from GitHub separately.
|
||||
* For details see [documentation about integrating with build systems](build-systems.md).
|
||||
* XML reporter now reports filename as part of the `Section` and `TestCase` tags.
|
||||
* `Approx` now supports an optional margin of absolute error
|
||||
* It has also received [new documentation](assertions.md).
|
||||
|
||||
### Fixes
|
||||
* Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
|
||||
* Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
|
||||
* 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
|
||||
* Otherwise it is supressed for the whole TU
|
||||
* Fixed test spec parser issue (with escapes in multiple names)
|
||||
|
||||
### Other
|
||||
* Various documentation fixes and improvements
|
||||
|
||||
|
||||
# 1.7.2
|
||||
|
||||
### Fixes and minor improvements
|
||||
Xml:
|
||||
|
||||
(technically the first two are breaking changes but are also fixes and arguably break few if any people)
|
||||
* C-escape control characters instead of XML encoding them (which requires XML 1.1)
|
||||
* Revert XML output to XML 1.0
|
||||
* Can provide stylesheet references by extending the XML reporter
|
||||
* Added description and tags attribites to XML Reporter
|
||||
* Tags are closed and the stream flushed more eagerly to avoid stdout interpolation
|
||||
|
||||
|
||||
Other:
|
||||
* `REQUIRE_THROWS_AS` now catches exception by `const&` and reports expected type
|
||||
* In `SECTION`s the file/ line is now of the `SECTION`. not the `TEST_CASE`
|
||||
* Added std:: qualification to some functions from C stdlib
|
||||
* Removed use of RTTI (`dynamic_cast`) that had crept back in
|
||||
* Silenced a few more warnings in different circumstances
|
||||
* Travis improvements
|
||||
|
||||
# 1.7.1
|
||||
|
||||
### Fixes:
|
||||
* Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
|
||||
* Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
|
||||
* For specifics, look into the [documentation](configuration.md).
|
||||
* Fixed compilation error under MinGW caused by improper compiler detection.
|
||||
* Fixed XML reporter sometimes leaving an empty output file when a test ends with signal/structured exception.
|
||||
* Fixed XML reporter not reporting captured stdout/stderr.
|
||||
* Fixed possible infinite recursion in Windows SEH.
|
||||
* Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
|
||||
|
||||
## 1.7.0
|
||||
|
||||
### Features/ Changes:
|
||||
* Catch now runs significantly faster for passing tests
|
||||
* Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
|
||||
* Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
|
||||
* Catch can now run specific sections within test cases.
|
||||
* For now the support is only basic (no wildcards or tags), for details see the [documentation](command-line.md).
|
||||
* Catch now supports SEH on Windows as well as signals on Linux.
|
||||
* After receiving a signal, Catch reports failing assertion and then passes the signal onto the previous handler.
|
||||
* Approx can be used to compare values against strong typedefs (available in C++11 mode only).
|
||||
* Strong typedefs mean types that are explicitly convertible to double.
|
||||
* CHECK macro no longer stops executing section if an exception happens.
|
||||
* Certain characters (space, tab, etc) are now pretty printed.
|
||||
* This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
|
||||
|
||||
### Fixes:
|
||||
* Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
|
||||
* THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
|
||||
* Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
|
||||
* Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
|
||||
|
||||
### Other:
|
||||
* Catch's CMakeLists now defines install command.
|
||||
* Catch's CMakeLists now generates projects with warnings enabled.
|
||||
|
||||
|
||||
## 1.6.1
|
||||
|
||||
### Features/ Changes:
|
||||
* Catch now supports breaking into debugger on Linux
|
||||
|
||||
### Fixes:
|
||||
* Generators no longer leak memory (generators are still unsupported in general)
|
||||
* JUnit reporter now reports UTC timestamps, instead of "tbd"
|
||||
* `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
|
||||
|
||||
### Other:
|
||||
* Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
|
||||
* The use of `__COUNTER__` is supressed when Catch is parsed by CLion
|
||||
* This change is not active when compiling a binary
|
||||
* Approval tests can now be run on Windows
|
||||
* CMake will now warn if a file is present in the `include` folder but not is not enumerated as part of the project
|
||||
* Catch now defines `NOMINMAX` and `WIN32_LEAN_AND_MEAN` before including `windows.h`
|
||||
* This can be disabled if needed, see [documentation](configuration.md) for details.
|
||||
|
||||
|
||||
## 1.6.0
|
||||
|
||||
### Cmake/ projects:
|
||||
* Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
|
||||
|
||||
### Features/ Changes:
|
||||
* Approx now supports `>=` and `<=`
|
||||
* Can now use `\` to escape chars in test names on command line
|
||||
* Standardize C++11 feature toggles
|
||||
|
||||
### Fixes:
|
||||
* Blue shell colour
|
||||
* Missing argument to `CATCH_CHECK_THROWS`
|
||||
* Don't encode extended ASCII in XML
|
||||
* use `std::shuffle` on more compilers (fixes deprecation warning/error)
|
||||
* Use `__COUNTER__` more consistently (where available)
|
||||
|
||||
### Other:
|
||||
* Tweaks and changes to scripts - particularly for Approval test - to make them more portable
|
||||
|
||||
|
||||
# Older versions
|
||||
Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
44
docs/release-process.md
Normal file
44
docs/release-process.md
Normal file
@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
|
||||
## Approval testing
|
||||
|
||||
Catch's releases are primarily validated against output from previous release, stored in `projects/SelfTest/Baselines`. To validate current sources, build the SelfTest binary and pass it to the `approvalTests.py` script: `approvalTests.py <path/to/SelfTest>`.
|
||||
|
||||
There should be no differences, as Approval tests should be updated when changes to Catch are made, but if there are, then they need to be manually reviewed and either approved (using `approve.py`) or Catch requires other fixes.
|
||||
|
||||
|
||||
## Incrementing version number
|
||||
|
||||
Catch uses a variant of [semantic versioning](http://semver.org/), with breaking API changes (and thus major version increments) being very rare. Thus, the release will usually increment the patch version, when it only contains couple of bugfixes, or minor version, when it contains new functionality, or larger changes in implementation of current functionality.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
## Release notes
|
||||
|
||||
Once a release is ready, release notes need to be written. They should summarize changes done since last release. For rough idea of expected notes see previous releases. Once written, release notes should be placed in `docs/release-notes.md`.
|
||||
|
||||
|
||||
## Commit and push update to GitHub
|
||||
|
||||
After version number is incremented, single-include header is regenerated and release notes are updated, changes should be commited and pushed to GitHub.
|
||||
|
||||
|
||||
## Release on GitHub
|
||||
|
||||
After pushing changes to GitHub, GitHub release *needs* to be created. Tag version and release title should be same as the new version, description should contain the release notes for the current release. Single header version of `catch.hpp` *needs* to be attached as a binary, as that is where the official download link links to. Preferably it should use linux line endings.
|
||||
|
||||
|
||||
## vcpkg update
|
||||
|
||||
As a last step, optionally update Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg) with Catch's new version. `updateVcpkgPackage.py` can do a lot of neccessary work for you, but it assumes that you have your fork of vcpkg checked out in a directory next to the directory, where you have checked out Catch.
|
||||
|
||||
It creates a branch and commits neccessary changes, that you then should review, synchronize and open a PR against.
|
45
docs/reporters.md
Normal file
45
docs/reporters.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Reporters
|
||||
|
||||
Catch has a modular reporting system and comes bundled with a handful of useful reporters built in.
|
||||
You can also write your own reporters.
|
||||
|
||||
## Using different reporters
|
||||
|
||||
The reporter to use can easily be controlled from the command line.
|
||||
To specify a reporter use [`-r` or `--reporter`](command-line.md#choosing-a-reporter-to-use), followed by the name of the reporter, e.g.:
|
||||
|
||||
```
|
||||
-r xml
|
||||
```
|
||||
|
||||
If you don't specify a reporter then the console reporter is used by default.
|
||||
There are four reporters built in to the single include:
|
||||
|
||||
* `console` writes as lines of text, formatted to a typical terminal width, with colours if a capable terminal is detected.
|
||||
* `compact` similar to `console` but optimised for minimal output - each entry on one line
|
||||
* `junit` writes xml that corresponds to Ant's [junitreport](http://help.catchsoftware.com/display/ET/JUnit+Format) target. Useful for build systems that understand Junit. If you are using Jenkins with Catch 1.x, you can improve quality of output by applying changes in [#923](https://github.com/philsquared/Catch/pull/923).
|
||||
Because of the way the junit format is structured the run must complete before anything is written.
|
||||
* `xml` writes an xml format tailored to Catch. Unlike `junit` this is a streaming format so results are delivered progressively.
|
||||
|
||||
There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
|
||||
Do this in one source file - typically the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
|
||||
|
||||
* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
|
||||
Use this when building as part of a TeamCity build to see results as they happen.
|
||||
* `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
|
||||
* `automake` writes in a format that correspond to [automake .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
|
||||
|
||||
You see what reporters are available from the command line by running with `--list-reporters`.
|
||||
|
||||
By default all these reports are written to stdout, but can be redirected to a file with [`-o` or `--out`](command-line.md#sending-output-to-a-file)
|
||||
|
||||
## Writing your own reporter
|
||||
|
||||
You can write your own custom reporter and register it with Catch.
|
||||
At time of writing the interface is subject to some changes so is not, yet, documented here.
|
||||
If you are determined you shouldn't have too much trouble working it out from the existing implementations -
|
||||
but do keep in mind upcoming changes (these will be minor, simplifying, changes such as not needing to forward calls to the base class).
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
@ -17,6 +17,48 @@ Because Catch is implemented *entirely* in headers you might think that the whol
|
||||
|
||||
As a result the main source file *does* compile the whole of Catch every time! So it makes sense to dedicate this file to *only* ```#define```-ing the identifier and ```#include```-ing Catch (and implementing the runner code, if you're doing that). Keep all your test cases in other files. This way you won't pay the recompilation cost for the whole of Catch
|
||||
|
||||
## Practical example
|
||||
Assume you have the `Factorial` function from the [tutorial](tutorial.md) in `factorial.cpp` (with forward declaration in `factorial.h`) and want to test it and keep the compile times down when adding new tests. Then you should have 2 files, `tests-main.cpp` and `tests-factorial.cpp`:
|
||||
|
||||
```cpp
|
||||
// tests-main.cpp
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
```
|
||||
|
||||
```cpp
|
||||
// tests-factorial.cpp
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "factorial.h"
|
||||
|
||||
TEST_CASE( "Factorials are computed", "[factorial]" ) {
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
||||
```
|
||||
|
||||
After compiling `tests-main.cpp` once, it is enough to link it with separately compiled `tests-factorial.cpp`. This means that adding more tests to `tests-factorial.cpp`, will not result in recompiling Catch's main and the resulting compilation times will decrease substantially.
|
||||
|
||||
```
|
||||
$ g++ tests-main.cpp -c
|
||||
$ g++ tests-main.o tests-factorial.cpp -o tests && ./tests -r compact
|
||||
Passed 1 test case with 4 assertions.
|
||||
```
|
||||
|
||||
Now, the next time we change the file `tests-factorial.cpp` (say we add `REQUIRE( Factorial(0) == 1)`), it is enough to recompile the tests instead of recompiling main as well:
|
||||
|
||||
```
|
||||
$ g++ tests-main.o tests-factorial.cpp -o tests && ./tests -r compact
|
||||
tests-factorial.cpp:11: failed: Factorial(0) == 1 for: 0 == 1
|
||||
Failed 1 test case, failed 1 assertion.
|
||||
```
|
||||
|
||||
## Other possible solutions
|
||||
You can also opt to sacrifice some features in order to speed-up Catch's compilation times. For details see the [documentation on Catch's compile-time configuration](configuration.md#other-toggles).
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
@ -2,7 +2,7 @@
|
||||
|
||||
While Catch fully supports the traditional, xUnit, style of class-based fixtures containing test case methods this is not the preferred style.
|
||||
|
||||
Instead Catch provides a powerful mechanism for nesting test case sections within a test case. For a more detailed discussion see the [tutorial](tutorial.md#testCasesAndSections).
|
||||
Instead Catch provides a powerful mechanism for nesting test case sections within a test case. For a more detailed discussion see the [tutorial](tutorial.md#test-cases-and-sections).
|
||||
|
||||
Test cases and sections are very easy to use in practice:
|
||||
|
||||
@ -28,20 +28,22 @@ The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects
|
||||
|
||||
For more detail on command line selection see [the command line docs](command-line.md#specifying-which-tests-to-run)
|
||||
|
||||
Tag names are not case sensitive.
|
||||
Tag names are not case sensitive and can contain any ASCII characters. This means that tags `[tag with spaces]` and `[I said "good day"]` are both allowed tags and can be filtered on. Escapes are not supported however and `[\]]` is not a valid tag.
|
||||
|
||||
### Special Tags
|
||||
|
||||
All tag names beginning with non-alphanumeric characters are reserved by Catch. Catch defines a number of "special" tags, which have meaning to the test runner itself. These special tags all begin with a symbol character. Following is a list of currently defined special tags and their meanings.
|
||||
|
||||
* `[!hide]` or `[.]` (or, for legacy reasons, `[hide]`) - causes test cases to be skipped from the default list (ie when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
||||
* `[!hide]` or `[.]` (or, for legacy reasons, `[hide]`) - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
|
||||
|
||||
* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be exluded when running with `-e` or `--nothrow`.
|
||||
|
||||
* `[!shouldfail]` - reverse the failing logic of the test: if the test is successful if it fails, and vice-versa.
|
||||
* `[!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.
|
||||
|
||||
* `[!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]`.
|
||||
|
||||
* `[@<alias>]` - tag aliases all begin with `@` (see below).
|
||||
@ -52,7 +54,7 @@ Between tag expressions and wildcarded test names (as well as combinations of th
|
||||
|
||||
CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
|
||||
|
||||
Aliases must begining with the `@` character. An example of a tag alias is:
|
||||
Aliases must begin with the `@` character. An example of a tag alias is:
|
||||
|
||||
CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
|
||||
|
||||
@ -83,4 +85,4 @@ Other than the additional prefixes and the formatting in the console reporter th
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
@ -1,4 +1,4 @@
|
||||
Although Catch allows you to group tests together as sections within a test case, it can still convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
|
||||
Although Catch allows you to group tests together as sections within a test case, it can still be convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
|
||||
|
||||
```c++
|
||||
class UniqueTestsFixture {
|
||||
@ -29,4 +29,4 @@ The two test cases here will create uniquely-named derived classes of UniqueTest
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
[Home](Readme.md)
|
||||
|
@ -16,16 +16,7 @@ std::ostream& operator << ( std::ostream& os, T const& value ) {
|
||||
|
||||
(where ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).
|
||||
|
||||
You should put this function in the same namespace as your type.
|
||||
|
||||
Alternatively you may prefer to write it as a member function:
|
||||
|
||||
```
|
||||
std::ostream& T::operator << ( std::ostream& os ) const {
|
||||
os << convertMyTypeToString( *this );
|
||||
return os;
|
||||
}
|
||||
```
|
||||
You should put this function in the same namespace as your type and it has to be declared before including Catch's header.
|
||||
|
||||
## Catch::toString overload
|
||||
|
||||
@ -39,11 +30,12 @@ namespace Catch {
|
||||
}
|
||||
```
|
||||
|
||||
Again ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable. Note that the function must be in the Catch namespace, which itself must be in the global namespace.
|
||||
Again ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable. Note that the function must be in the Catch namespace, which itself must be in the global namespace and must be declared _before_ Catch's header is included.
|
||||
|
||||
**Please note that overloading `Catch::toString` is currently considered legacy and will not be supported in the next major version of Catch.**
|
||||
|
||||
## Catch::StringMaker<T> specialisation
|
||||
|
||||
There are some cases where overloading toString does not work as expected. Specialising StringMaker<T> gives you more precise, and reliable, control - but at the cost of slightly more code and complexity:
|
||||
Another way of telling Catch how to convert a type to string is specialising `Catch::StringMaker` template. This allows you to have separate way of stringifying types for Catch, than you have for writing it to a stream and also doesn't require you to declare it before including Catch's header.
|
||||
|
||||
```
|
||||
namespace Catch {
|
||||
@ -55,6 +47,16 @@ namespace Catch {
|
||||
}
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
```
|
||||
CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
|
||||
return ex.message();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Getting Catch
|
||||
|
||||
The simplest way to get Catch is to download the single header version from [http://builds.catch-lib.net](http://builds.catch-lib.net). Don't be put off by the word "builds" there. 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 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 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.
|
||||
|
||||
@ -68,7 +68,7 @@ with expansion:
|
||||
0 == 1
|
||||
```
|
||||
|
||||
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That let's us immediately see what the problem is.
|
||||
Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That lets us immediately see what the problem is.
|
||||
|
||||
Let's change the factorial function to:
|
||||
|
||||
@ -233,7 +233,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 it's own source file](slow-compiles.md).
|
||||
In fact it is usually a good idea to put the block with the ```#define``` [in its own source file](slow-compiles.md).
|
||||
|
||||
Do not write your tests in header files!
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
## What's new in Catch for 1.0
|
||||
|
||||
After a long "developer preview" state Catch turned 1.0 in mid-2013. Just prior to this a large number of changes, some of them breaking, where merged from the integration branch and now form part of the 1.0 code-base. If this might affect you please read this summary through so you know what to expect.
|
||||
|
||||
* Calling Catch from your own ```main()``` has changed - please review [the updated docs](own-main.md)
|
||||
* The command line has changed. The biggest change is that test case names and tags should now only be supplied as primary arguments - in fact the ```-t``` option has been repurposed to mean "list tags". There are [updated docs for this too](command-line.md)
|
||||
* There is a new reporter interface. If you have written a custom reporter you can use the ```LegacyReporterAdapter``` to minimise any differences. Ideally you should update to the new interface - especially as it has been designed to be more robust in the face of future changes (which should be minimal).
|
||||
* The docs have moved from the wiki to the repository itself. They consist of a set of markdown files in the docs folder and are referenced directly from the README in the root. You can still read them online from GitHub.
|
||||
* Lots of new goodness - more documentation for which is coming. The existing docs have been updated to account for some of the changes already (e.g. variadic macros). A quick rundown:
|
||||
* Variadic macros are used, where possible, so that, e.g. you can write a ```TEST_CASE``` with just a name - or even no name at all (making it an anonymous test case).
|
||||
* The hierarchical naming convention is deprecated in favour of using tags (see next)
|
||||
* ```TEST_CASE```s (but not ```SECTION```s) can now be tagged by placing keywords in square brackets in the second argument - e.g.: ```TEST_CASE( "A nice name", "[tag1][tag2]")```. The old style is still supported but please consider using this new style.
|
||||
* Tests can still be "hidden" using the ```./``` prefix as before, but the preferred way now is to give it the ```[hide]``` tag (hidden tests are skipped if you run the test process without specifying any test specs).
|
||||
* As well as ```TEST_CASE```s and ```SECTION```s you can now also use BDD-style ```SCENARIO``` (in place of ```TEST_CASE```) and ```GIVEN```, ```WHEN``` and ```THEN``` macros (in place of ```SECTION```s).
|
||||
* New command line parser. Under the hood it is a complete rewrite - now powered by a command line library that will soon be spun out as a separate project: Clara. The options themselves are largely the same but there are some notable differences (as already discussed).
|
||||
* Completely overhauled output from the textual reporter (now the Console reporter). This now features a much clearer, cleaner format, including good use of indentation.
|
||||
|
||||
More information can be found in [this blog post](http://www.levelofindirection.com/journal/2013/6/28/catch-10.html).
|
||||
|
||||
If you find any issues please raise issue tickets on the [issue tracker on GitHub](https://github.com/philsquared/Catch/issues) as before. For general questions, comments and suggestions, though, please use the [new forums on Google Groups](https://groups.google.com/forum/?fromgroups#!forum/catch-forum).
|
||||
|
||||
---
|
||||
|
||||
[Home](Readme.md)
|
@ -35,6 +35,10 @@ So what does Catch bring to the party that differentiates it from these? Apart f
|
||||
* Implement test fixtures using Obj-C classes too (like OCUnit)
|
||||
* Additional built in matchers that work with Obj-C types (e.g. string matchers)
|
||||
|
||||
## Who else is using Catch?
|
||||
|
||||
See the list of [open source projects using Catch](opensource-users.md).
|
||||
|
||||
See the [tutorial](tutorial.md) to get more of a taste of using CATCH in practice
|
||||
|
||||
---
|
||||
|
@ -36,7 +36,8 @@
|
||||
#include "internal/catch_generators.hpp"
|
||||
#include "internal/catch_interfaces_exception.h"
|
||||
#include "internal/catch_approx.hpp"
|
||||
#include "internal/catch_matchers.hpp"
|
||||
#include "internal/catch_matchers_string.h"
|
||||
#include "internal/catch_matchers_vector.h"
|
||||
#include "internal/catch_compiler_capabilities.h"
|
||||
#include "internal/catch_interfaces_tag_alias_registry.h"
|
||||
|
||||
@ -50,6 +51,29 @@
|
||||
#endif
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
|
||||
// !TBD: Move the leak detector code into a separate header
|
||||
#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
|
||||
#include <crtdbg.h>
|
||||
class LeakDetector {
|
||||
public:
|
||||
LeakDetector() {
|
||||
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
flag |= _CRTDBG_LEAK_CHECK_DF;
|
||||
flag |= _CRTDBG_ALLOC_MEM_DF;
|
||||
_CrtSetDbgFlag(flag);
|
||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
|
||||
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
|
||||
// Change this to leaking allocation's number to break there
|
||||
_CrtSetBreakAlloc(-1);
|
||||
}
|
||||
};
|
||||
#else
|
||||
class LeakDetector {};
|
||||
#endif
|
||||
|
||||
LeakDetector leakDetector;
|
||||
|
||||
#include "internal/catch_impl.hpp"
|
||||
#endif
|
||||
|
||||
@ -67,48 +91,63 @@
|
||||
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
|
||||
#ifdef CATCH_CONFIG_PREFIX_ALL
|
||||
|
||||
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
|
||||
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
|
||||
#else
|
||||
#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
|
||||
#endif
|
||||
|
||||
#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
|
||||
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" )
|
||||
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
|
||||
#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
|
||||
#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
|
||||
|
||||
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
|
||||
#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
|
||||
#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
|
||||
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
|
||||
#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
|
||||
#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
|
||||
#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
|
||||
|
||||
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
|
||||
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
|
||||
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
|
||||
#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
|
||||
#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
|
||||
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
|
||||
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
|
||||
#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
|
||||
|
||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
|
||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
|
||||
#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
|
||||
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
|
||||
#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#else
|
||||
#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#endif
|
||||
|
||||
|
||||
#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||
#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
|
||||
#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
|
||||
#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
|
||||
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
|
||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
|
||||
#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#else
|
||||
#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
||||
#define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
||||
#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
||||
#define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
|
||||
#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
||||
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
|
||||
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
|
||||
#define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
|
||||
#define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#endif
|
||||
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
||||
|
||||
@ -134,48 +173,64 @@
|
||||
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
|
||||
#else
|
||||
|
||||
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
|
||||
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
|
||||
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
|
||||
|
||||
#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
|
||||
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
|
||||
#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" )
|
||||
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
|
||||
#else
|
||||
#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr )
|
||||
#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
|
||||
#endif
|
||||
|
||||
#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
|
||||
#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
|
||||
#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
|
||||
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
|
||||
#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
|
||||
#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
|
||||
#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
|
||||
#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
|
||||
#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
|
||||
|
||||
#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
|
||||
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
|
||||
#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" )
|
||||
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
|
||||
#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
|
||||
#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
|
||||
|
||||
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
|
||||
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
|
||||
#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
|
||||
#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
|
||||
#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
|
||||
#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
|
||||
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
|
||||
#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
|
||||
#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
|
||||
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#else
|
||||
#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
|
||||
#endif
|
||||
|
||||
|
||||
#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
|
||||
#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
|
||||
#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
|
||||
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||
#define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
|
||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
|
||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||
#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
|
||||
#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
|
||||
#else
|
||||
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
||||
#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
|
||||
#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
|
||||
#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
|
||||
#define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
|
||||
#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
|
||||
#define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
|
||||
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
|
||||
#define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
|
||||
#define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
|
||||
#endif
|
||||
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace Catch {
|
||||
}
|
||||
return reporter;
|
||||
}
|
||||
|
||||
|
||||
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
|
||||
std::vector<std::string> reporters = config->getReporterNames();
|
||||
if( reporters.empty() )
|
||||
@ -40,7 +40,7 @@ namespace Catch {
|
||||
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
|
||||
it != itEnd;
|
||||
++it )
|
||||
reporter = addReporter( reporter, createReporter( *it, config ) );
|
||||
reporter = addReporter( reporter, createReporter( *it, config ) );
|
||||
return reporter;
|
||||
}
|
||||
Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
|
||||
@ -51,15 +51,15 @@ namespace Catch {
|
||||
reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
|
||||
return reporters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Totals runTests( Ptr<Config> const& config ) {
|
||||
|
||||
Ptr<IConfig const> iconfig = config.get();
|
||||
|
||||
|
||||
Ptr<IStreamingReporter> reporter = makeReporter( config );
|
||||
reporter = addListeners( iconfig, reporter );
|
||||
|
||||
|
||||
RunContext context( iconfig, reporter );
|
||||
|
||||
Totals totals;
|
||||
@ -83,13 +83,13 @@ namespace Catch {
|
||||
context.testGroupEnded( iconfig->name(), totals, 1, 1 );
|
||||
return totals;
|
||||
}
|
||||
|
||||
|
||||
void applyFilenamesAsTags( IConfig const& config ) {
|
||||
std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
|
||||
for(std::size_t i = 0; i < tests.size(); ++i ) {
|
||||
TestCase& test = const_cast<TestCase&>( tests[i] );
|
||||
std::set<std::string> tags = test.tags;
|
||||
|
||||
|
||||
std::string filename = test.lineInfo.file;
|
||||
std::string::size_type lastSlash = filename.find_last_of( "\\/" );
|
||||
if( lastSlash != std::string::npos )
|
||||
@ -98,7 +98,7 @@ namespace Catch {
|
||||
std::string::size_type lastDot = filename.find_last_of( "." );
|
||||
if( lastDot != std::string::npos )
|
||||
filename = filename.substr( 0, lastDot );
|
||||
|
||||
|
||||
tags.insert( "#" + filename );
|
||||
setTags( test, tags );
|
||||
}
|
||||
@ -125,16 +125,16 @@ namespace Catch {
|
||||
}
|
||||
|
||||
void showHelp( std::string const& processName ) {
|
||||
Catch::cout() << "\nCatch v" << libraryVersion << "\n";
|
||||
Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
|
||||
|
||||
m_cli.usage( Catch::cout(), processName );
|
||||
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
|
||||
}
|
||||
|
||||
int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
||||
int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
||||
try {
|
||||
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
||||
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
||||
m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
|
||||
if( m_configData.showHelp )
|
||||
showHelp( m_configData.processName );
|
||||
m_config.reset();
|
||||
@ -158,7 +158,7 @@ namespace Catch {
|
||||
m_config.reset();
|
||||
}
|
||||
|
||||
int run( int argc, char* const argv[] ) {
|
||||
int run( int argc, char const* const* const argv ) {
|
||||
|
||||
int returnCode = applyCommandLine( argc, argv );
|
||||
if( returnCode == 0 )
|
||||
@ -166,6 +166,32 @@ namespace Catch {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
int run( int argc, wchar_t const* const* const argv ) {
|
||||
|
||||
char **utf8Argv = new char *[ argc ];
|
||||
|
||||
for ( int i = 0; i < argc; ++i ) {
|
||||
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
|
||||
|
||||
utf8Argv[ i ] = new char[ bufSize ];
|
||||
|
||||
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
|
||||
}
|
||||
|
||||
int returnCode = applyCommandLine( argc, utf8Argv );
|
||||
if( returnCode == 0 )
|
||||
returnCode = run();
|
||||
|
||||
for ( int i = 0; i < argc; ++i )
|
||||
delete [] utf8Argv[ i ];
|
||||
|
||||
delete [] utf8Argv;
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
int run() {
|
||||
if( m_configData.showHelp )
|
||||
return 0;
|
||||
@ -173,12 +199,12 @@ namespace Catch {
|
||||
try
|
||||
{
|
||||
config(); // Force config to be constructed
|
||||
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
if( m_configData.filenamesAsTags )
|
||||
applyFilenamesAsTags( *m_config );
|
||||
|
||||
|
||||
// Handle list request
|
||||
if( Option<std::size_t> listed = list( config() ) )
|
||||
return static_cast<int>( *listed );
|
||||
|
@ -8,8 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED
|
||||
|
||||
#include "catch_runner.hpp"
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
||||
#include "internal/catch_default_main.hpp"
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_WITH_MAIN_HPP_INCLUDED
|
||||
|
355
include/external/clara.h
vendored
355
include/external/clara.h
vendored
@ -6,6 +6,8 @@
|
||||
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
// Version 0.0.2.4
|
||||
|
||||
// Only use header guard if we are not using an outer namespace
|
||||
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
|
||||
|
||||
@ -38,6 +40,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
// Use optional outer namespace
|
||||
#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
|
||||
@ -172,16 +176,179 @@ namespace Tbc {
|
||||
#endif // TBC_TEXT_FORMAT_H_INCLUDED
|
||||
|
||||
// ----------- end of #include from tbc_text_format.h -----------
|
||||
// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
|
||||
// ........... back in clara.h
|
||||
|
||||
#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
|
||||
|
||||
|
||||
// ----------- #included from clara_compilers.h -----------
|
||||
|
||||
/*
|
||||
* Created by Phil on 10/02/2016.
|
||||
* Copyright 2016 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
||||
#define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
||||
|
||||
// Detect a number of compiler features - mostly C++11/14 conformance - by compiler
|
||||
// The following features are defined:
|
||||
//
|
||||
// CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported?
|
||||
// CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported?
|
||||
// CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods
|
||||
// CLARA_CONFIG_CPP11_OVERRIDE : is override supported?
|
||||
// CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
|
||||
|
||||
// CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
||||
|
||||
// CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported?
|
||||
|
||||
// In general each macro has a _NO_<feature name> form
|
||||
// (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature.
|
||||
// Many features, at point of detection, define an _INTERNAL_ macro, so they
|
||||
// can be combined, en-mass, with the _NO_ forms later.
|
||||
|
||||
// All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
#if __has_feature(cxx_nullptr)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
|
||||
#if __has_feature(cxx_noexcept)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#endif
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GCC
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
|
||||
// - otherwise more recent versions define __cplusplus >= 201103L
|
||||
// and will get picked up below
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if (_MSC_VER >= 1600)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#endif
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// C++ language feature support
|
||||
|
||||
// catch all support for C++11
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
|
||||
#define CLARA_CPP11_OR_GREATER
|
||||
|
||||
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
|
||||
#ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#endif
|
||||
|
||||
#ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#endif
|
||||
|
||||
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE
|
||||
#endif
|
||||
#if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
|
||||
#define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
// Now set the actual defines based on the above + anything the user has configured
|
||||
#if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11)
|
||||
#define CLARA_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
#if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11)
|
||||
#define CLARA_CONFIG_CPP11_NOEXCEPT
|
||||
#endif
|
||||
#if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11)
|
||||
#define CLARA_CONFIG_CPP11_GENERATED_METHODS
|
||||
#endif
|
||||
#if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11)
|
||||
#define CLARA_CONFIG_CPP11_OVERRIDE
|
||||
#endif
|
||||
#if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11)
|
||||
#define CLARA_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
|
||||
|
||||
// noexcept support:
|
||||
#if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT)
|
||||
#define CLARA_NOEXCEPT noexcept
|
||||
# define CLARA_NOEXCEPT_IS(x) noexcept(x)
|
||||
#else
|
||||
#define CLARA_NOEXCEPT throw()
|
||||
# define CLARA_NOEXCEPT_IS(x)
|
||||
#endif
|
||||
|
||||
// nullptr support
|
||||
#ifdef CLARA_CONFIG_CPP11_NULLPTR
|
||||
#define CLARA_NULL nullptr
|
||||
#else
|
||||
#define CLARA_NULL NULL
|
||||
#endif
|
||||
|
||||
// override support
|
||||
#ifdef CLARA_CONFIG_CPP11_OVERRIDE
|
||||
#define CLARA_OVERRIDE override
|
||||
#else
|
||||
#define CLARA_OVERRIDE
|
||||
#endif
|
||||
|
||||
// unique_ptr support
|
||||
#ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR
|
||||
# define CLARA_AUTO_PTR( T ) std::unique_ptr<T>
|
||||
#else
|
||||
# define CLARA_AUTO_PTR( T ) std::auto_ptr<T>
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED
|
||||
|
||||
|
||||
// ----------- end of #include from clara_compilers.h -----------
|
||||
// ........... back in clara.h
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define CLARA_PLATFORM_WINDOWS
|
||||
#endif
|
||||
|
||||
|
||||
// Use optional outer namespace
|
||||
#ifdef STITCH_CLARA_OPEN_NAMESPACE
|
||||
STITCH_CLARA_OPEN_NAMESPACE
|
||||
@ -230,9 +397,12 @@ namespace Clara {
|
||||
inline void convertInto( std::string const& _source, std::string& _dest ) {
|
||||
_dest = _source;
|
||||
}
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( std::tolower( c ) );
|
||||
}
|
||||
inline void convertInto( std::string const& _source, bool& _dest ) {
|
||||
std::string sourceLC = _source;
|
||||
std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
|
||||
std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh );
|
||||
if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
|
||||
_dest = true;
|
||||
else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
|
||||
@ -240,23 +410,16 @@ namespace Clara {
|
||||
else
|
||||
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
|
||||
}
|
||||
inline void convertInto( bool _source, bool& _dest ) {
|
||||
_dest = _source;
|
||||
}
|
||||
template<typename T>
|
||||
inline void convertInto( bool, T& ) {
|
||||
throw std::runtime_error( "Invalid conversion" );
|
||||
}
|
||||
|
||||
|
||||
template<typename ConfigT>
|
||||
struct IArgFunction {
|
||||
virtual ~IArgFunction() {}
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
#ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS
|
||||
IArgFunction() = default;
|
||||
IArgFunction( IArgFunction const& ) = default;
|
||||
# endif
|
||||
#endif
|
||||
virtual void set( ConfigT& config, std::string const& value ) const = 0;
|
||||
virtual void setFlag( ConfigT& config ) const = 0;
|
||||
virtual bool takesArg() const = 0;
|
||||
virtual IArgFunction* clone() const = 0;
|
||||
};
|
||||
@ -264,11 +427,11 @@ namespace Clara {
|
||||
template<typename ConfigT>
|
||||
class BoundArgFunction {
|
||||
public:
|
||||
BoundArgFunction() : functionObj( CATCH_NULL ) {}
|
||||
BoundArgFunction() : functionObj( CLARA_NULL ) {}
|
||||
BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
|
||||
BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {}
|
||||
BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {}
|
||||
BoundArgFunction& operator = ( BoundArgFunction const& other ) {
|
||||
IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL;
|
||||
IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL;
|
||||
delete functionObj;
|
||||
functionObj = newFunctionObj;
|
||||
return *this;
|
||||
@ -278,13 +441,10 @@ namespace Clara {
|
||||
void set( ConfigT& config, std::string const& value ) const {
|
||||
functionObj->set( config, value );
|
||||
}
|
||||
void setFlag( ConfigT& config ) const {
|
||||
functionObj->setFlag( config );
|
||||
}
|
||||
bool takesArg() const { return functionObj->takesArg(); }
|
||||
|
||||
bool isSet() const {
|
||||
return functionObj != CATCH_NULL;
|
||||
return functionObj != CLARA_NULL;
|
||||
}
|
||||
private:
|
||||
IArgFunction<ConfigT>* functionObj;
|
||||
@ -294,7 +454,6 @@ namespace Clara {
|
||||
template<typename C>
|
||||
struct NullBinder : IArgFunction<C>{
|
||||
virtual void set( C&, std::string const& ) const {}
|
||||
virtual void setFlag( C& ) const {}
|
||||
virtual bool takesArg() const { return true; }
|
||||
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
|
||||
};
|
||||
@ -305,9 +464,6 @@ namespace Clara {
|
||||
virtual void set( C& p, std::string const& stringValue ) const {
|
||||
convertInto( stringValue, p.*member );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
convertInto( true, p.*member );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<M>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
|
||||
M C::* member;
|
||||
@ -320,11 +476,6 @@ namespace Clara {
|
||||
convertInto( stringValue, value );
|
||||
(p.*member)( value );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
typename RemoveConstRef<M>::type value;
|
||||
convertInto( true, value );
|
||||
(p.*member)( value );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<M>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
|
||||
void (C::*member)( M );
|
||||
@ -338,9 +489,6 @@ namespace Clara {
|
||||
if( value )
|
||||
(p.*member)();
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
(p.*member)();
|
||||
}
|
||||
virtual bool takesArg() const { return false; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
|
||||
void (C::*member)();
|
||||
@ -355,9 +503,6 @@ namespace Clara {
|
||||
if( value )
|
||||
function( obj );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
function( p );
|
||||
}
|
||||
virtual bool takesArg() const { return false; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
|
||||
void (*function)( C& );
|
||||
@ -371,11 +516,6 @@ namespace Clara {
|
||||
convertInto( stringValue, value );
|
||||
function( obj, value );
|
||||
}
|
||||
virtual void setFlag( C& obj ) const {
|
||||
typename RemoveConstRef<T>::type value;
|
||||
convertInto( true, value );
|
||||
function( obj, value );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<T>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
|
||||
void (*function)( C&, T );
|
||||
@ -383,8 +523,20 @@ namespace Clara {
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
struct Parser {
|
||||
Parser() : separators( " \t=:" ) {}
|
||||
inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
|
||||
std::vector<std::string> args( static_cast<std::size_t>( argc ) );
|
||||
for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
|
||||
args[i] = argv[i];
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
class Parser {
|
||||
enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
|
||||
Mode mode;
|
||||
std::size_t from;
|
||||
bool inQuotes;
|
||||
public:
|
||||
|
||||
struct Token {
|
||||
enum Type { Positional, ShortOpt, LongOpt };
|
||||
@ -393,38 +545,77 @@ namespace Clara {
|
||||
std::string data;
|
||||
};
|
||||
|
||||
void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
|
||||
Parser() : mode( None ), from( 0 ), inQuotes( false ){}
|
||||
|
||||
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
|
||||
const std::string doubleDash = "--";
|
||||
for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
|
||||
parseIntoTokens( argv[i] , tokens);
|
||||
for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
|
||||
parseIntoTokens( args[i], tokens);
|
||||
}
|
||||
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
|
||||
while( !arg.empty() ) {
|
||||
Parser::Token token( Parser::Token::Positional, arg );
|
||||
arg = "";
|
||||
if( token.data[0] == '-' ) {
|
||||
if( token.data.size() > 1 && token.data[1] == '-' ) {
|
||||
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
|
||||
}
|
||||
else {
|
||||
token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
|
||||
if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
|
||||
arg = "-" + token.data.substr( 1 );
|
||||
token.data = token.data.substr( 0, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( token.type != Parser::Token::Positional ) {
|
||||
std::size_t pos = token.data.find_first_of( separators );
|
||||
if( pos != std::string::npos ) {
|
||||
arg = token.data.substr( pos+1 );
|
||||
token.data = token.data.substr( 0, pos );
|
||||
}
|
||||
}
|
||||
tokens.push_back( token );
|
||||
|
||||
void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
|
||||
for( std::size_t i = 0; i < arg.size(); ++i ) {
|
||||
char c = arg[i];
|
||||
if( c == '"' )
|
||||
inQuotes = !inQuotes;
|
||||
mode = handleMode( i, c, arg, tokens );
|
||||
}
|
||||
mode = handleMode( arg.size(), '\0', arg, tokens );
|
||||
}
|
||||
Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
switch( mode ) {
|
||||
case None: return handleNone( i, c );
|
||||
case MaybeShortOpt: return handleMaybeShortOpt( i, c );
|
||||
case ShortOpt:
|
||||
case LongOpt:
|
||||
case SlashOpt: return handleOpt( i, c, arg, tokens );
|
||||
case Positional: return handlePositional( i, c, arg, tokens );
|
||||
default: throw std::logic_error( "Unknown mode" );
|
||||
}
|
||||
}
|
||||
std::string separators;
|
||||
|
||||
Mode handleNone( std::size_t i, char c ) {
|
||||
if( inQuotes ) {
|
||||
from = i;
|
||||
return Positional;
|
||||
}
|
||||
switch( c ) {
|
||||
case '-': return MaybeShortOpt;
|
||||
#ifdef CLARA_PLATFORM_WINDOWS
|
||||
case '/': from = i+1; return SlashOpt;
|
||||
#endif
|
||||
default: from = i; return Positional;
|
||||
}
|
||||
}
|
||||
Mode handleMaybeShortOpt( std::size_t i, char c ) {
|
||||
switch( c ) {
|
||||
case '-': from = i+1; return LongOpt;
|
||||
default: from = i; return ShortOpt;
|
||||
}
|
||||
}
|
||||
|
||||
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
|
||||
return mode;
|
||||
|
||||
std::string optName = arg.substr( from, i-from );
|
||||
if( mode == ShortOpt )
|
||||
for( std::size_t j = 0; j < optName.size(); ++j )
|
||||
tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
|
||||
else if( mode == SlashOpt && optName.size() == 1 )
|
||||
tokens.push_back( Token( Token::ShortOpt, optName ) );
|
||||
else
|
||||
tokens.push_back( Token( Token::LongOpt, optName ) );
|
||||
return None;
|
||||
}
|
||||
Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
|
||||
return mode;
|
||||
|
||||
std::string data = arg.substr( from, i-from );
|
||||
tokens.push_back( Token( Token::Positional, data ) );
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ConfigT>
|
||||
@ -503,7 +694,7 @@ namespace Clara {
|
||||
}
|
||||
};
|
||||
|
||||
typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr;
|
||||
typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr;
|
||||
|
||||
friend void addOptName( Arg& arg, std::string const& optName )
|
||||
{
|
||||
@ -580,8 +771,8 @@ namespace Clara {
|
||||
m_arg->description = description;
|
||||
return *this;
|
||||
}
|
||||
ArgBuilder& detail( std::string const& _detail ) {
|
||||
m_arg->detail = _detail;
|
||||
ArgBuilder& detail( std::string const& detail ) {
|
||||
m_arg->detail = detail;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -665,14 +856,14 @@ namespace Clara {
|
||||
maxWidth = (std::max)( maxWidth, it->commands().size() );
|
||||
|
||||
for( it = itBegin; it != itEnd; ++it ) {
|
||||
Detail::Text usageText( it->commands(), Detail::TextAttributes()
|
||||
Detail::Text usage( it->commands(), Detail::TextAttributes()
|
||||
.setWidth( maxWidth+indent )
|
||||
.setIndent( indent ) );
|
||||
Detail::Text desc( it->description, Detail::TextAttributes()
|
||||
.setWidth( width - maxWidth - 3 ) );
|
||||
|
||||
for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) {
|
||||
std::string usageCol = i < usageText.size() ? usageText[i] : "";
|
||||
for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
|
||||
std::string usageCol = i < usage.size() ? usage[i] : "";
|
||||
os << usageCol;
|
||||
|
||||
if( i < desc.size() && !desc[i].empty() )
|
||||
@ -729,21 +920,21 @@ namespace Clara {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
ConfigT parse( int argc, char const * const * argv ) const {
|
||||
ConfigT parse( std::vector<std::string> const& args ) const {
|
||||
ConfigT config;
|
||||
parseInto( argc, argv, config );
|
||||
parseInto( args, config );
|
||||
return config;
|
||||
}
|
||||
|
||||
std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
|
||||
std::string processName = argv[0];
|
||||
std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
|
||||
std::string processName = args.empty() ? std::string() : args[0];
|
||||
std::size_t lastSlash = processName.find_last_of( "/\\" );
|
||||
if( lastSlash != std::string::npos )
|
||||
processName = processName.substr( lastSlash+1 );
|
||||
m_boundProcessName.set( config, processName );
|
||||
std::vector<Parser::Token> tokens;
|
||||
Parser parser;
|
||||
parser.parseIntoTokens( argc, argv, tokens );
|
||||
parser.parseIntoTokens( args, tokens );
|
||||
return populate( tokens, config );
|
||||
}
|
||||
|
||||
@ -774,7 +965,7 @@ namespace Clara {
|
||||
arg.boundField.set( config, tokens[++i].data );
|
||||
}
|
||||
else {
|
||||
arg.boundField.setFlag( config );
|
||||
arg.boundField.set( config, "true" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
111
include/external/tbc_text_format.h
vendored
111
include/external/tbc_text_format.h
vendored
@ -37,19 +37,16 @@ namespace Tbc {
|
||||
TextAttributes()
|
||||
: initialIndent( std::string::npos ),
|
||||
indent( 0 ),
|
||||
width( consoleWidth-1 ),
|
||||
tabChar( '\t' )
|
||||
width( consoleWidth-1 )
|
||||
{}
|
||||
|
||||
TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; }
|
||||
TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; }
|
||||
TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; }
|
||||
TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; }
|
||||
|
||||
std::size_t initialIndent; // indent of first line, or npos
|
||||
std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos
|
||||
std::size_t width; // maximum width of text, including indent. Longer text will wrap
|
||||
char tabChar; // If this char is seen the indent is changed to current pos
|
||||
};
|
||||
|
||||
class Text {
|
||||
@ -57,63 +54,80 @@ namespace Tbc {
|
||||
Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
|
||||
: attr( _attr )
|
||||
{
|
||||
std::string wrappableChars = " [({.,/|\\-";
|
||||
std::size_t indent = _attr.initialIndent != std::string::npos
|
||||
? _attr.initialIndent
|
||||
: _attr.indent;
|
||||
std::string remainder = _str;
|
||||
const std::string wrappableBeforeChars = "[({<\t";
|
||||
const std::string wrappableAfterChars = "])}>-,./|\\";
|
||||
const std::string wrappableInsteadOfChars = " \n\r";
|
||||
std::string indent = _attr.initialIndent != std::string::npos
|
||||
? std::string( _attr.initialIndent, ' ' )
|
||||
: std::string( _attr.indent, ' ' );
|
||||
|
||||
typedef std::string::const_iterator iterator;
|
||||
iterator it = _str.begin();
|
||||
const iterator strEnd = _str.end();
|
||||
|
||||
while( it != strEnd ) {
|
||||
|
||||
while( !remainder.empty() ) {
|
||||
if( lines.size() >= 1000 ) {
|
||||
lines.push_back( "... message truncated due to excessive size" );
|
||||
return;
|
||||
}
|
||||
std::size_t tabPos = std::string::npos;
|
||||
std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
|
||||
std::size_t pos = remainder.find_first_of( '\n' );
|
||||
if( pos <= width ) {
|
||||
width = pos;
|
||||
}
|
||||
pos = remainder.find_last_of( _attr.tabChar, width );
|
||||
if( pos != std::string::npos ) {
|
||||
tabPos = pos;
|
||||
if( remainder[width] == '\n' )
|
||||
width--;
|
||||
remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
|
||||
}
|
||||
|
||||
if( width == remainder.size() ) {
|
||||
spliceLine( indent, remainder, width );
|
||||
}
|
||||
else if( remainder[width] == '\n' ) {
|
||||
spliceLine( indent, remainder, width );
|
||||
if( width <= 1 || remainder.size() != 1 )
|
||||
remainder = remainder.substr( 1 );
|
||||
indent = _attr.indent;
|
||||
}
|
||||
else {
|
||||
pos = remainder.find_last_of( wrappableChars, width );
|
||||
if( pos != std::string::npos && pos > 0 ) {
|
||||
spliceLine( indent, remainder, pos );
|
||||
if( remainder[0] == ' ' )
|
||||
remainder = remainder.substr( 1 );
|
||||
|
||||
std::string suffix;
|
||||
std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) );
|
||||
iterator itEnd = it+width;
|
||||
iterator itNext = _str.end();
|
||||
|
||||
iterator itNewLine = std::find( it, itEnd, '\n' );
|
||||
if( itNewLine != itEnd )
|
||||
itEnd = itNewLine;
|
||||
|
||||
if( itEnd != strEnd ) {
|
||||
bool foundWrapPoint = false;
|
||||
iterator findIt = itEnd;
|
||||
do {
|
||||
if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) {
|
||||
itEnd = findIt+1;
|
||||
itNext = findIt+1;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) {
|
||||
itEnd = findIt;
|
||||
itNext = findIt;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) {
|
||||
itNext = findIt+1;
|
||||
itEnd = findIt;
|
||||
foundWrapPoint = true;
|
||||
}
|
||||
if( findIt == it )
|
||||
break;
|
||||
else
|
||||
--findIt;
|
||||
}
|
||||
while( !foundWrapPoint );
|
||||
|
||||
if( !foundWrapPoint ) {
|
||||
// No good wrap char, so we'll break mid word and add a hyphen
|
||||
--itEnd;
|
||||
itNext = itEnd;
|
||||
suffix = "-";
|
||||
}
|
||||
else {
|
||||
spliceLine( indent, remainder, width-1 );
|
||||
lines.back() += "-";
|
||||
while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos )
|
||||
--itEnd;
|
||||
}
|
||||
if( lines.size() == 1 )
|
||||
indent = _attr.indent;
|
||||
if( tabPos != std::string::npos )
|
||||
indent += tabPos;
|
||||
}
|
||||
lines.push_back( indent + std::string( it, itEnd ) + suffix );
|
||||
|
||||
if( indent.size() != _attr.indent )
|
||||
indent = std::string( _attr.indent, ' ' );
|
||||
it = itNext;
|
||||
}
|
||||
}
|
||||
|
||||
void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
|
||||
lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
|
||||
_remainder = _remainder.substr( _pos );
|
||||
}
|
||||
|
||||
|
||||
typedef std::vector<std::string>::const_iterator const_iterator;
|
||||
|
||||
@ -138,6 +152,7 @@ namespace Tbc {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
TextAttributes attr;
|
||||
|
@ -13,6 +13,10 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
|
||||
@ -20,12 +24,14 @@ namespace Detail {
|
||||
public:
|
||||
explicit Approx ( double value )
|
||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
||||
m_margin( 0.0 ),
|
||||
m_scale( 1.0 ),
|
||||
m_value( value )
|
||||
{}
|
||||
|
||||
Approx( Approx const& other )
|
||||
: m_epsilon( other.m_epsilon ),
|
||||
m_margin( other.m_margin ),
|
||||
m_scale( other.m_scale ),
|
||||
m_value( other.m_value )
|
||||
{}
|
||||
@ -34,16 +40,104 @@ namespace Detail {
|
||||
return Approx( 0 );
|
||||
}
|
||||
|
||||
Approx operator()( double value ) {
|
||||
Approx approx( value );
|
||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx operator()( T value ) {
|
||||
Approx approx( static_cast<double>(value) );
|
||||
approx.epsilon( m_epsilon );
|
||||
approx.margin( m_margin );
|
||||
approx.scale( m_scale );
|
||||
return approx;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
explicit Approx( T value ): Approx(static_cast<double>(value))
|
||||
{}
|
||||
|
||||
|
||||
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 = double(lhs);
|
||||
bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::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;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
||||
return operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( T lhs, Approx const& rhs ) {
|
||||
return !operator==( lhs, rhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator != ( Approx const& lhs, T rhs ) {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator <= ( T lhs, Approx const& rhs ) {
|
||||
return double(lhs) < rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator <= ( Approx const& lhs, T rhs ) {
|
||||
return lhs.m_value < double(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator >= ( T lhs, Approx const& rhs ) {
|
||||
return double(lhs) > rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
friend bool operator >= ( Approx const& lhs, T rhs ) {
|
||||
return lhs.m_value > double(rhs) || lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& epsilon( T newEpsilon ) {
|
||||
m_epsilon = double(newEpsilon);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& margin( T newMargin ) {
|
||||
m_margin = double(newMargin);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
||||
Approx& scale( T newScale ) {
|
||||
m_scale = double(newScale);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Approx operator()( double value ) {
|
||||
Approx approx( value );
|
||||
approx.epsilon( m_epsilon );
|
||||
approx.margin( m_margin );
|
||||
approx.scale( m_scale );
|
||||
return approx;
|
||||
}
|
||||
|
||||
|
||||
friend bool operator == ( double lhs, Approx const& rhs ) {
|
||||
// Thanks to Richard Harris for his help refining this formula
|
||||
return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
|
||||
bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
|
||||
if (relativeOK) {
|
||||
return true;
|
||||
}
|
||||
return std::fabs(lhs - rhs.m_value) < rhs.m_margin;
|
||||
}
|
||||
|
||||
friend bool operator == ( Approx const& lhs, double rhs ) {
|
||||
@ -58,15 +152,37 @@ namespace Detail {
|
||||
return !operator==( rhs, lhs );
|
||||
}
|
||||
|
||||
friend bool operator <= ( double lhs, Approx const& rhs ) {
|
||||
return lhs < rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
friend bool operator <= ( Approx const& lhs, double rhs ) {
|
||||
return lhs.m_value < rhs || lhs == rhs;
|
||||
}
|
||||
|
||||
friend bool operator >= ( double lhs, Approx const& rhs ) {
|
||||
return lhs > rhs.m_value || lhs == rhs;
|
||||
}
|
||||
|
||||
friend bool operator >= ( Approx const& lhs, double rhs ) {
|
||||
return lhs.m_value > rhs || lhs == rhs;
|
||||
}
|
||||
|
||||
Approx& epsilon( double newEpsilon ) {
|
||||
m_epsilon = newEpsilon;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Approx& margin( double newMargin ) {
|
||||
m_margin = newMargin;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Approx& scale( double newScale ) {
|
||||
m_scale = newScale;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
@ -76,6 +192,7 @@ namespace Detail {
|
||||
|
||||
private:
|
||||
double m_epsilon;
|
||||
double m_margin;
|
||||
double m_scale;
|
||||
double m_value;
|
||||
};
|
||||
|
@ -13,6 +13,30 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
||||
|
||||
struct DecomposedExpression
|
||||
{
|
||||
virtual ~DecomposedExpression() {}
|
||||
virtual bool isBinaryExpression() const {
|
||||
return false;
|
||||
}
|
||||
virtual void reconstructExpression( std::string& dest ) const = 0;
|
||||
|
||||
// Only simple binary comparisons can be decomposed.
|
||||
// If more complex check is required then wrap sub-expressions in parentheses.
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
|
||||
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
|
||||
|
||||
private:
|
||||
DecomposedExpression& operator = (DecomposedExpression const&);
|
||||
};
|
||||
|
||||
struct AssertionInfo
|
||||
{
|
||||
AssertionInfo() {}
|
||||
@ -29,11 +53,41 @@ namespace Catch {
|
||||
|
||||
struct AssertionResultData
|
||||
{
|
||||
AssertionResultData() : resultType( ResultWas::Unknown ) {}
|
||||
AssertionResultData() : decomposedExpression( CATCH_NULL )
|
||||
, resultType( ResultWas::Unknown )
|
||||
, negated( false )
|
||||
, parenthesized( false ) {}
|
||||
|
||||
std::string reconstructedExpression;
|
||||
void negate( bool parenthesize ) {
|
||||
negated = !negated;
|
||||
parenthesized = parenthesize;
|
||||
if( resultType == ResultWas::Ok )
|
||||
resultType = ResultWas::ExpressionFailed;
|
||||
else if( resultType == ResultWas::ExpressionFailed )
|
||||
resultType = ResultWas::Ok;
|
||||
}
|
||||
|
||||
std::string const& reconstructExpression() const {
|
||||
if( decomposedExpression != CATCH_NULL ) {
|
||||
decomposedExpression->reconstructExpression( reconstructedExpression );
|
||||
if( parenthesized ) {
|
||||
reconstructedExpression.insert( 0, 1, '(' );
|
||||
reconstructedExpression.append( 1, ')' );
|
||||
}
|
||||
if( negated ) {
|
||||
reconstructedExpression.insert( 0, 1, '!' );
|
||||
}
|
||||
decomposedExpression = CATCH_NULL;
|
||||
}
|
||||
return reconstructedExpression;
|
||||
}
|
||||
|
||||
mutable DecomposedExpression const* decomposedExpression;
|
||||
mutable std::string reconstructedExpression;
|
||||
std::string message;
|
||||
ResultWas::OfType resultType;
|
||||
bool negated;
|
||||
bool parenthesized;
|
||||
};
|
||||
|
||||
class AssertionResult {
|
||||
@ -60,6 +114,8 @@ namespace Catch {
|
||||
std::string getMessage() const;
|
||||
SourceLineInfo getSourceInfo() const;
|
||||
std::string getTestMacroName() const;
|
||||
void discardDecomposedExpression() const;
|
||||
void expandDecomposedExpression() const;
|
||||
|
||||
protected:
|
||||
AssertionInfo m_info;
|
||||
|
@ -56,7 +56,7 @@ namespace Catch {
|
||||
|
||||
std::string AssertionResult::getExpression() const {
|
||||
if( isFalseTest( m_info.resultDisposition ) )
|
||||
return "!" + m_info.capturedExpression;
|
||||
return '!' + m_info.capturedExpression;
|
||||
else
|
||||
return m_info.capturedExpression;
|
||||
}
|
||||
@ -72,7 +72,7 @@ namespace Catch {
|
||||
}
|
||||
|
||||
std::string AssertionResult::getExpandedExpression() const {
|
||||
return m_resultData.reconstructedExpression;
|
||||
return m_resultData.reconstructExpression();
|
||||
}
|
||||
|
||||
std::string AssertionResult::getMessage() const {
|
||||
@ -86,6 +86,14 @@ namespace Catch {
|
||||
return m_info.macroName;
|
||||
}
|
||||
|
||||
void AssertionResult::discardDecomposedExpression() const {
|
||||
m_resultData.decomposedExpression = CATCH_NULL;
|
||||
}
|
||||
|
||||
void AssertionResult::expandDecomposedExpression() const {
|
||||
m_resultData.reconstructExpression();
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
||||
|
@ -18,6 +18,41 @@
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
|
||||
#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( resultBuilder ) \
|
||||
resultBuilder.react();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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_TEST_NO_TRY( macroName, resultDisposition, expr ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
__catchResult.setExceptionGuard(); \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
( __catchResult <= expr ).endExpression(); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
__catchResult.unsetExceptionGuard(); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr 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 &&.
|
||||
|
||||
#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||
__catchResult.setExceptionGuard(); \
|
||||
__catchResult.captureMatch( arg, matcher, #matcher ); \
|
||||
__catchResult.unsetExceptionGuard(); \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
#else
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// In the event of a failure works out if the debugger needs to be invoked
|
||||
// and/or an exception thrown and takes appropriate action.
|
||||
@ -26,37 +61,41 @@
|
||||
#define INTERNAL_CATCH_REACT( resultBuilder ) \
|
||||
if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
|
||||
resultBuilder.react();
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
|
||||
#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
try { \
|
||||
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
( __catchResult <= expr ).endExpression(); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
||||
__catchResult.useActiveException( resultDisposition ); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr 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 &&.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
||||
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
||||
#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
|
||||
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
|
||||
if( Catch::getResultCapture().getLastResult()->succeeded() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
|
||||
INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
|
||||
#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
|
||||
INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
|
||||
if( !Catch::getResultCapture().getLastResult()->succeeded() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
|
||||
#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::Ok ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
@ -66,12 +105,12 @@
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
|
||||
#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( ... ) { \
|
||||
@ -83,12 +122,12 @@
|
||||
} while( Catch::alwaysFalse() )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
|
||||
#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
|
||||
if( __catchResult.allowThrows() ) \
|
||||
try { \
|
||||
expr; \
|
||||
static_cast<void>(expr); \
|
||||
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
|
||||
} \
|
||||
catch( exceptionType ) { \
|
||||
@ -105,7 +144,7 @@
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
__catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
|
||||
@ -113,7 +152,7 @@
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::alwaysFalse() )
|
||||
#else
|
||||
#define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
|
||||
#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
|
||||
__catchResult << log + ::Catch::StreamEndStop(); \
|
||||
@ -123,21 +162,15 @@
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_INFO( log, macroName ) \
|
||||
#define INTERNAL_CATCH_INFO( macroName, log ) \
|
||||
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
|
||||
#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
|
||||
do { \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
|
||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||
try { \
|
||||
std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
|
||||
__catchResult \
|
||||
.setLhs( Catch::toString( arg ) ) \
|
||||
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
|
||||
.setOp( "matches" ) \
|
||||
.setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
|
||||
__catchResult.captureExpression(); \
|
||||
__catchResult.captureMatch( arg, matcher, #matcher ); \
|
||||
} catch( ... ) { \
|
||||
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
||||
} \
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "catch_clara.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -23,13 +24,14 @@ namespace Catch {
|
||||
config.abortAfter = x;
|
||||
}
|
||||
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
||||
inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
|
||||
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
|
||||
|
||||
inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
||||
if( _warning == "NoAssertions" )
|
||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
|
||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
|
||||
}
|
||||
inline void setOrder( ConfigData& config, std::string const& order ) {
|
||||
if( startsWith( "declared", order ) )
|
||||
@ -39,7 +41,7 @@ namespace Catch {
|
||||
else if( startsWith( "random", order ) )
|
||||
config.runOrder = RunTests::InRandomOrder;
|
||||
else
|
||||
throw std::runtime_error( "Unrecognised ordering: '" + order + "'" );
|
||||
throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
|
||||
}
|
||||
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
|
||||
if( seed == "time" ) {
|
||||
@ -50,7 +52,7 @@ namespace Catch {
|
||||
ss << seed;
|
||||
ss >> config.rngSeed;
|
||||
if( ss.fail() )
|
||||
throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" );
|
||||
throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
|
||||
}
|
||||
}
|
||||
inline void setVerbosity( ConfigData& config, int level ) {
|
||||
@ -62,6 +64,21 @@ namespace Catch {
|
||||
? ShowDurations::Always
|
||||
: ShowDurations::Never;
|
||||
}
|
||||
inline void setUseColour( ConfigData& config, std::string const& value ) {
|
||||
std::string mode = toLower( value );
|
||||
|
||||
if( mode == "yes" )
|
||||
config.useColour = UseColour::Yes;
|
||||
else if( mode == "no" )
|
||||
config.useColour = UseColour::No;
|
||||
else if( mode == "auto" )
|
||||
config.useColour = UseColour::Auto;
|
||||
else
|
||||
throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
|
||||
}
|
||||
inline void forceColour( ConfigData& config ) {
|
||||
config.useColour = UseColour::Yes;
|
||||
}
|
||||
inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
|
||||
std::ifstream f( _filename.c_str() );
|
||||
if( !f.is_open() )
|
||||
@ -70,8 +87,11 @@ namespace Catch {
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, "#" ) )
|
||||
addTestOrTags( config, "\"" + line + "\"," );
|
||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||
if( !startsWith( line, '"' ) )
|
||||
line = '"' + line + '"';
|
||||
addTestOrTags( config, line + ',' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +168,7 @@ namespace Catch {
|
||||
|
||||
cli["-d"]["--durations"]
|
||||
.describe( "show test durations" )
|
||||
.bind( &setShowDurations, "yes/no" );
|
||||
.bind( &setShowDurations, "yes|no" );
|
||||
|
||||
cli["-f"]["--input-file"]
|
||||
.describe( "load test names to run from a file" )
|
||||
@ -158,12 +178,16 @@ namespace Catch {
|
||||
.describe( "adds a tag for the filename" )
|
||||
.bind( &ConfigData::filenamesAsTags );
|
||||
|
||||
cli["-c"]["--section"]
|
||||
.describe( "specify section to run" )
|
||||
.bind( &addSectionToRun, "section name" );
|
||||
|
||||
// Less common commands which don't have a short form
|
||||
cli["--list-test-names-only"]
|
||||
.describe( "list all/matching test cases names only" )
|
||||
.bind( &ConfigData::listTestNamesOnly );
|
||||
|
||||
cli["--list-reporters"]
|
||||
cli["--list-reporters"]
|
||||
.describe( "list all reporters" )
|
||||
.bind( &ConfigData::listReporters );
|
||||
|
||||
@ -176,9 +200,13 @@ namespace Catch {
|
||||
.bind( &setRngSeed, "'time'|number" );
|
||||
|
||||
cli["--force-colour"]
|
||||
.describe( "force colourised output" )
|
||||
.bind( &ConfigData::forceColour );
|
||||
|
||||
.describe( "force colourised output (deprecated)" )
|
||||
.bind( &forceColour );
|
||||
|
||||
cli["--use-colour"]
|
||||
.describe( "should output be colourised" )
|
||||
.bind( &setUseColour, "yes|no" );
|
||||
|
||||
return cli;
|
||||
}
|
||||
|
||||
|
@ -8,28 +8,31 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
|
||||
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
|
||||
#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
|
||||
#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
||||
#ifdef CATCH_CONFIG_COUNTER
|
||||
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
|
||||
#else
|
||||
# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
|
||||
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
#include "catch_compiler_capabilities.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
||||
struct IConfig;
|
||||
|
||||
struct CaseSensitive { enum Choice {
|
||||
Yes,
|
||||
No
|
||||
}; };
|
||||
|
||||
|
||||
class NonCopyable {
|
||||
#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
NonCopyable( NonCopyable const& ) = delete;
|
||||
@ -73,7 +76,9 @@ namespace Catch {
|
||||
}
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix );
|
||||
bool startsWith( std::string const& s, char prefix );
|
||||
bool endsWith( std::string const& s, std::string const& suffix );
|
||||
bool endsWith( std::string const& s, char suffix );
|
||||
bool contains( std::string const& s, std::string const& infix );
|
||||
void toLowerInPlace( std::string& s );
|
||||
std::string toLower( std::string const& s );
|
||||
@ -93,8 +98,8 @@ namespace Catch {
|
||||
|
||||
SourceLineInfo();
|
||||
SourceLineInfo( char const* _file, std::size_t _line );
|
||||
SourceLineInfo( SourceLineInfo const& other );
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
SourceLineInfo(SourceLineInfo const& other) = default;
|
||||
SourceLineInfo( SourceLineInfo && ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
|
||||
SourceLineInfo& operator = ( SourceLineInfo && ) = default;
|
||||
@ -103,7 +108,7 @@ namespace Catch {
|
||||
bool operator == ( SourceLineInfo const& other ) const;
|
||||
bool operator < ( SourceLineInfo const& other ) const;
|
||||
|
||||
std::string file;
|
||||
char const* file;
|
||||
std::size_t line;
|
||||
};
|
||||
|
||||
@ -118,7 +123,7 @@ namespace Catch {
|
||||
|
||||
void seedRng( IConfig const& config );
|
||||
unsigned int rngSeed();
|
||||
|
||||
|
||||
// Use this in variadic streaming macros to allow
|
||||
// >> +StreamEndStop
|
||||
// as well as
|
||||
|
@ -10,19 +10,31 @@
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
|
||||
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
||||
}
|
||||
bool startsWith( std::string const& s, char prefix ) {
|
||||
return !s.empty() && s[0] == prefix;
|
||||
}
|
||||
bool endsWith( std::string const& s, std::string const& suffix ) {
|
||||
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
|
||||
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
|
||||
}
|
||||
bool endsWith( std::string const& s, char suffix ) {
|
||||
return !s.empty() && s[s.size()-1] == suffix;
|
||||
}
|
||||
bool contains( std::string const& s, std::string const& infix ) {
|
||||
return s.find( infix ) != std::string::npos;
|
||||
}
|
||||
char toLowerCh(char c) {
|
||||
return static_cast<char>( std::tolower( c ) );
|
||||
}
|
||||
void toLowerInPlace( std::string& s ) {
|
||||
std::transform( s.begin(), s.end(), s.begin(), ::tolower );
|
||||
std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
|
||||
}
|
||||
std::string toLower( std::string const& s ) {
|
||||
std::string lc = s;
|
||||
@ -34,9 +46,9 @@ namespace Catch {
|
||||
std::string::size_type start = str.find_first_not_of( whitespaceChars );
|
||||
std::string::size_type end = str.find_last_not_of( whitespaceChars );
|
||||
|
||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
|
||||
}
|
||||
|
||||
|
||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
||||
bool replaced = false;
|
||||
std::size_t i = str.find( replaceThis );
|
||||
@ -50,36 +62,32 @@ namespace Catch {
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
|
||||
|
||||
pluralise::pluralise( std::size_t count, std::string const& label )
|
||||
: m_count( count ),
|
||||
m_label( label )
|
||||
{}
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
|
||||
os << pluraliser.m_count << " " << pluraliser.m_label;
|
||||
os << pluraliser.m_count << ' ' << pluraliser.m_label;
|
||||
if( pluraliser.m_count != 1 )
|
||||
os << "s";
|
||||
os << 's';
|
||||
return os;
|
||||
}
|
||||
|
||||
SourceLineInfo::SourceLineInfo() : line( 0 ){}
|
||||
SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){}
|
||||
SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
|
||||
: file( _file ),
|
||||
line( _line )
|
||||
{}
|
||||
SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
|
||||
: file( other.file ),
|
||||
line( other.line )
|
||||
{}
|
||||
bool SourceLineInfo::empty() const {
|
||||
return file.empty();
|
||||
return file[0] == '\0';
|
||||
}
|
||||
bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
|
||||
return line == other.line && file == other.file;
|
||||
return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
|
||||
}
|
||||
bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const {
|
||||
return line < other.line || ( line == other.line && file < other.file );
|
||||
return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
|
||||
}
|
||||
|
||||
void seedRng( IConfig const& config ) {
|
||||
@ -92,16 +100,16 @@ namespace Catch {
|
||||
|
||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||
#ifndef __GNUG__
|
||||
os << info.file << "(" << info.line << ")";
|
||||
os << info.file << '(' << info.line << ')';
|
||||
#else
|
||||
os << info.file << ":" << info.line;
|
||||
os << info.file << ':' << info.line;
|
||||
#endif
|
||||
return os;
|
||||
}
|
||||
|
||||
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
|
||||
std::ostringstream oss;
|
||||
oss << locationInfo << ": Internal Catch error: '" << message << "'";
|
||||
oss << locationInfo << ": Internal Catch error: '" << message << '\'';
|
||||
if( alwaysTrue() )
|
||||
throw std::logic_error( oss.str() );
|
||||
}
|
||||
|
@ -19,11 +19,15 @@
|
||||
// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported?
|
||||
// CATCH_CONFIG_CPP11_OVERRIDE : is override supported?
|
||||
// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr)
|
||||
// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported?
|
||||
// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported?
|
||||
|
||||
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
||||
|
||||
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
|
||||
|
||||
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
||||
// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
|
||||
// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
|
||||
// ****************
|
||||
// Note to maintainers: if new toggles are added please document them
|
||||
// in configuration.md, too
|
||||
@ -36,6 +40,18 @@
|
||||
|
||||
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# if __cplusplus >= 201103L
|
||||
# define CATCH_CPP11_OR_GREATER
|
||||
# endif
|
||||
|
||||
# if __cplusplus >= 201402L
|
||||
# define CATCH_CPP14_OR_GREATER
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
|
||||
# if __has_feature(cxx_nullptr)
|
||||
@ -46,8 +62,44 @@
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
# endif
|
||||
|
||||
# if defined(CATCH_CPP11_OR_GREATER)
|
||||
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
|
||||
_Pragma( "clang diagnostic push" ) \
|
||||
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
|
||||
_Pragma( "clang diagnostic pop" )
|
||||
# endif
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Cygwin
|
||||
#ifdef __CYGWIN__
|
||||
|
||||
// Required for some versions of Cygwin to declare gettimeofday
|
||||
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
|
||||
# define _BSD_SOURCE
|
||||
|
||||
#endif // __CYGWIN__
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Borland
|
||||
#ifdef __BORLANDC__
|
||||
@ -73,9 +125,10 @@
|
||||
// GCC
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
#endif
|
||||
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# endif
|
||||
|
||||
|
||||
// - otherwise more recent versions define __cplusplus >= 201103L
|
||||
// and will get picked up below
|
||||
@ -87,6 +140,8 @@
|
||||
// Visual C++
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
|
||||
|
||||
#if (_MSC_VER >= 1600)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
||||
@ -95,6 +150,8 @@
|
||||
#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015))
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
|
||||
#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
|
||||
#endif
|
||||
|
||||
#endif // _MSC_VER
|
||||
@ -111,13 +168,20 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Use __COUNTER__ if the compiler supports it
|
||||
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
|
||||
( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
|
||||
( defined __clang__ && __clang_major__ >= 3 )
|
||||
|
||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// C++ language feature support
|
||||
|
||||
// catch all support for C++11
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
|
||||
# define CATCH_CPP11_OR_GREATER
|
||||
#if defined(CATCH_CPP11_OR_GREATER)
|
||||
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
|
||||
@ -153,7 +217,12 @@
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR
|
||||
# endif
|
||||
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE
|
||||
# endif
|
||||
# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS)
|
||||
# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS
|
||||
# endif
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
@ -176,16 +245,43 @@
|
||||
#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS)
|
||||
# define CATCH_CONFIG_VARIADIC_MACROS
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_LONG_LONG
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_OVERRIDE
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_UNIQUE_PTR
|
||||
#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__)
|
||||
# define CATCH_CONFIG_COUNTER
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_SHUFFLE
|
||||
#endif
|
||||
# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_TYPE_TRAITS
|
||||
# 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)
|
||||
# define CATCH_CONFIG_POSIX_SIGNALS
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
|
||||
#endif
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
|
||||
# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
#endif
|
||||
|
||||
// noexcept support:
|
||||
#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
|
||||
|
@ -16,8 +16,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef CATCH_CONFIG_CONSOLE_WIDTH
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH 80
|
||||
@ -37,14 +36,14 @@ namespace Catch {
|
||||
noThrow( false ),
|
||||
showHelp( false ),
|
||||
showInvisibles( false ),
|
||||
forceColour( false ),
|
||||
filenamesAsTags( false ),
|
||||
abortAfter( -1 ),
|
||||
rngSeed( 0 ),
|
||||
verbosity( Verbosity::Normal ),
|
||||
warnings( WarnAbout::Nothing ),
|
||||
showDurations( ShowDurations::DefaultForReporter ),
|
||||
runOrder( RunTests::InDeclarationOrder )
|
||||
runOrder( RunTests::InDeclarationOrder ),
|
||||
useColour( UseColour::Auto )
|
||||
{}
|
||||
|
||||
bool listTests;
|
||||
@ -57,7 +56,6 @@ namespace Catch {
|
||||
bool noThrow;
|
||||
bool showHelp;
|
||||
bool showInvisibles;
|
||||
bool forceColour;
|
||||
bool filenamesAsTags;
|
||||
|
||||
int abortAfter;
|
||||
@ -67,6 +65,7 @@ namespace Catch {
|
||||
WarnAbout::What warnings;
|
||||
ShowDurations::OrNot showDurations;
|
||||
RunTests::InWhatOrder runOrder;
|
||||
UseColour::YesOrNo useColour;
|
||||
|
||||
std::string outputFilename;
|
||||
std::string name;
|
||||
@ -74,6 +73,7 @@ namespace Catch {
|
||||
|
||||
std::vector<std::string> reporterNames;
|
||||
std::vector<std::string> testsOrTags;
|
||||
std::vector<std::string> sectionsToRun;
|
||||
};
|
||||
|
||||
|
||||
@ -99,8 +99,7 @@ namespace Catch {
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Config() {
|
||||
}
|
||||
virtual ~Config() {}
|
||||
|
||||
std::string const& getFilename() const {
|
||||
return m_data.outputFilename ;
|
||||
@ -113,30 +112,29 @@ namespace Catch {
|
||||
|
||||
std::string getProcessName() const { return m_data.processName; }
|
||||
|
||||
bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
|
||||
std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; }
|
||||
std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; }
|
||||
|
||||
std::vector<std::string> getReporterNames() const { return m_data.reporterNames; }
|
||||
|
||||
int abortAfter() const { return m_data.abortAfter; }
|
||||
|
||||
TestSpec const& testSpec() const { return m_testSpec; }
|
||||
virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; }
|
||||
|
||||
bool showHelp() const { return m_data.showHelp; }
|
||||
bool showInvisibles() const { return m_data.showInvisibles; }
|
||||
|
||||
// IConfig interface
|
||||
virtual bool allowThrows() const { return !m_data.noThrow; }
|
||||
virtual std::ostream& stream() const { return m_stream->stream(); }
|
||||
virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
|
||||
virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
|
||||
virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; }
|
||||
virtual unsigned int rngSeed() const { return m_data.rngSeed; }
|
||||
virtual bool forceColour() const { return m_data.forceColour; }
|
||||
virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; }
|
||||
virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); }
|
||||
virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; }
|
||||
virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; }
|
||||
virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; }
|
||||
virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; }
|
||||
virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; }
|
||||
virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; }
|
||||
virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; }
|
||||
virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; }
|
||||
virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; }
|
||||
virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
IStream const* openStream() {
|
||||
if( m_data.outputFilename.empty() )
|
||||
return new CoutStream();
|
||||
@ -151,7 +149,7 @@ namespace Catch {
|
||||
}
|
||||
ConfigData m_data;
|
||||
|
||||
std::auto_ptr<IStream const> m_stream;
|
||||
CATCH_AUTO_PTR( IStream const ) m_stream;
|
||||
TestSpec m_testSpec;
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
|
||||
|
||||
#include "catch_console_colour.hpp"
|
||||
#include "catch_errno_guard.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace {
|
||||
@ -41,15 +42,7 @@ namespace Catch {
|
||||
|
||||
#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#ifdef __AFXDLL
|
||||
#include <AfxWin.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
namespace Catch {
|
||||
namespace {
|
||||
@ -95,7 +88,18 @@ namespace {
|
||||
|
||||
IColourImpl* platformColourInstance() {
|
||||
static Win32ColourImpl s_instance;
|
||||
return &s_instance;
|
||||
|
||||
Ptr<IConfig const> config = getCurrentContext().getConfig();
|
||||
UseColour::YesOrNo colourMode = config
|
||||
? config->useColour()
|
||||
: UseColour::Auto;
|
||||
if( colourMode == UseColour::Auto )
|
||||
colourMode = !isDebuggerActive()
|
||||
? UseColour::Yes
|
||||
: UseColour::No;
|
||||
return colourMode == UseColour::Yes
|
||||
? &s_instance
|
||||
: NoColourImpl::instance();
|
||||
}
|
||||
|
||||
} // end anon namespace
|
||||
@ -120,7 +124,7 @@ namespace {
|
||||
case Colour::White: return setColour( "[0m" );
|
||||
case Colour::Red: return setColour( "[0;31m" );
|
||||
case Colour::Green: return setColour( "[0;32m" );
|
||||
case Colour::Blue: return setColour( "[0:34m" );
|
||||
case Colour::Blue: return setColour( "[0;34m" );
|
||||
case Colour::Cyan: return setColour( "[0;36m" );
|
||||
case Colour::Yellow: return setColour( "[0;33m" );
|
||||
case Colour::Grey: return setColour( "[1;30m" );
|
||||
@ -145,8 +149,16 @@ namespace {
|
||||
};
|
||||
|
||||
IColourImpl* platformColourInstance() {
|
||||
ErrnoGuard guard;
|
||||
Ptr<IConfig const> config = getCurrentContext().getConfig();
|
||||
return (config && config->forceColour()) || isatty(STDOUT_FILENO)
|
||||
UseColour::YesOrNo colourMode = config
|
||||
? config->useColour()
|
||||
: UseColour::Auto;
|
||||
if( colourMode == UseColour::Auto )
|
||||
colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) )
|
||||
? UseColour::Yes
|
||||
: UseColour::No;
|
||||
return colourMode == UseColour::Yes
|
||||
? PosixColourImpl::instance()
|
||||
: NoColourImpl::instance();
|
||||
}
|
||||
@ -171,9 +183,7 @@ namespace Catch {
|
||||
Colour::~Colour(){ if( !m_moved ) use( None ); }
|
||||
|
||||
void Colour::use( Code _colourCode ) {
|
||||
static IColourImpl* impl = isDebuggerActive()
|
||||
? NoColourImpl::instance()
|
||||
: platformColourInstance();
|
||||
static IColourImpl* impl = platformColourInstance();
|
||||
impl->use( _colourCode );
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,6 @@
|
||||
#include "catch_interfaces_generators.h"
|
||||
#include "catch_ptr.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "catch_context.h"
|
||||
#include "catch_stream.hpp"
|
||||
#include "catch_common.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -21,6 +22,11 @@ namespace Catch {
|
||||
Context( Context const& );
|
||||
void operator=( Context const& );
|
||||
|
||||
public:
|
||||
virtual ~Context() {
|
||||
deleteAllValues( m_generatorsByTestName );
|
||||
}
|
||||
|
||||
public: // IContext
|
||||
virtual IResultCapture* getResultCapture() {
|
||||
return m_resultCapture;
|
||||
|
@ -23,27 +23,36 @@ namespace Catch{
|
||||
|
||||
// The following code snippet based on:
|
||||
// http://cocoawithlove.com/2008/03/break-into-debugger.html
|
||||
#ifdef DEBUG
|
||||
#if defined(__ppc64__) || defined(__ppc__)
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() \
|
||||
if( Catch::isDebuggerActive() ) { \
|
||||
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
||||
: : : "memory","r0","r3","r4" ); \
|
||||
}
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
|
||||
#endif
|
||||
#if defined(__ppc64__) || defined(__ppc__)
|
||||
#define CATCH_TRAP() \
|
||||
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
||||
: : : "memory","r0","r3","r4" )
|
||||
#else
|
||||
#define CATCH_TRAP() __asm__("int $3\n" : : )
|
||||
#endif
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
// If we can use inline assembler, do it because this allows us to break
|
||||
// directly at the location of the failing check instead of breaking inside
|
||||
// raise() called from it, i.e. one stack frame below.
|
||||
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
|
||||
#define CATCH_TRAP() asm volatile ("int $3")
|
||||
#else // Fall back to the generic way.
|
||||
#include <signal.h>
|
||||
|
||||
#define CATCH_TRAP() raise(SIGTRAP)
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
|
||||
#define CATCH_TRAP() __debugbreak()
|
||||
#elif defined(__MINGW32__)
|
||||
extern "C" __declspec(dllimport) void __stdcall DebugBreak();
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
|
||||
#define CATCH_TRAP() DebugBreak()
|
||||
#endif
|
||||
|
||||
#ifndef CATCH_BREAK_INTO_DEBUGGER
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
|
||||
#ifdef CATCH_TRAP
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
|
||||
#else
|
||||
#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
|
||||
|
@ -10,8 +10,7 @@
|
||||
#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
|
||||
|
||||
#include "catch_debugger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "catch_errno_guard.hpp"
|
||||
|
||||
#ifdef CATCH_PLATFORM_MAC
|
||||
|
||||
@ -61,6 +60,36 @@
|
||||
}
|
||||
} // namespace Catch
|
||||
|
||||
#elif defined(CATCH_PLATFORM_LINUX)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace Catch{
|
||||
// The standard POSIX way of detecting a debugger is to attempt to
|
||||
// ptrace() the process, but this needs to be done from a child and not
|
||||
// this process itself to still allow attaching to this process later
|
||||
// if wanted, so is rather heavy. Under Linux we have the PID of the
|
||||
// "debugger" (which doesn't need to be gdb, of course, it could also
|
||||
// be strace, for example) in /proc/$PID/status, so just get it from
|
||||
// there instead.
|
||||
bool isDebuggerActive(){
|
||||
// Libstdc++ has a bug, where std::ifstream sets errno to 0
|
||||
// This way our users can properly assert over errno values
|
||||
ErrnoGuard guard;
|
||||
std::ifstream in("/proc/self/status");
|
||||
for( std::string line; std::getline(in, line); ) {
|
||||
static const int PREFIX_LEN = 11;
|
||||
if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
|
||||
// We're traced if the PID is not 0 and no other PID starts
|
||||
// with 0 digit, so it's enough to check for just a single
|
||||
// character.
|
||||
return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace Catch
|
||||
#elif defined(_MSC_VER)
|
||||
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
|
||||
namespace Catch {
|
||||
@ -82,7 +111,9 @@
|
||||
#endif // Platform
|
||||
|
||||
#ifdef CATCH_PLATFORM_WINDOWS
|
||||
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
|
||||
|
||||
#include "catch_windows_h_proxy.h"
|
||||
|
||||
namespace Catch {
|
||||
void writeToDebugConsole( std::string const& text ) {
|
||||
::OutputDebugStringA( text.c_str() );
|
||||
|
@ -10,9 +10,16 @@
|
||||
|
||||
#ifndef __OBJC__
|
||||
|
||||
#if 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
|
||||
// Standard C/C++ main entry point
|
||||
int main (int argc, char * const argv[]) {
|
||||
return Catch::Session().run( argc, argv );
|
||||
int main (int argc, char * argv[]) {
|
||||
#endif
|
||||
|
||||
int result = Catch::Session().run( argc, argv );
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
|
||||
#else // __OBJC__
|
||||
@ -30,7 +37,7 @@ int main (int argc, char * const argv[]) {
|
||||
[pool drain];
|
||||
#endif
|
||||
|
||||
return result;
|
||||
return ( result < 0xff ? result : 0xff );
|
||||
}
|
||||
|
||||
#endif // __OBJC__
|
||||
|
25
include/internal/catch_errno_guard.hpp
Normal file
25
include/internal/catch_errno_guard.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Created by Martin on 06/03/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_ERRNO_GUARD_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
class ErrnoGuard {
|
||||
public:
|
||||
ErrnoGuard():m_oldErrno(errno){}
|
||||
~ErrnoGuard() { errno = m_oldErrno; }
|
||||
private:
|
||||
int m_oldErrno;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
|
@ -11,6 +11,7 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
||||
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
@ -52,37 +53,37 @@ namespace Internal {
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsEqualTo> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs) {
|
||||
return opCast( lhs ) == opCast( rhs );
|
||||
return bool( opCast( lhs ) == opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsNotEqualTo> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
||||
return opCast( lhs ) != opCast( rhs );
|
||||
return bool( opCast( lhs ) != opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsLessThan> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
||||
return opCast( lhs ) < opCast( rhs );
|
||||
return bool( opCast( lhs ) < opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsGreaterThan> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
||||
return opCast( lhs ) > opCast( rhs );
|
||||
return bool( opCast( lhs ) > opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
||||
return opCast( lhs ) >= opCast( rhs );
|
||||
return bool( opCast( lhs ) >= opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
|
||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
||||
return opCast( lhs ) <= opCast( rhs );
|
||||
return bool( opCast( lhs ) <= opCast( rhs ) );
|
||||
}
|
||||
};
|
||||
|
||||
@ -174,7 +175,7 @@ namespace Internal {
|
||||
template<Operator Op> bool compare( long long lhs, unsigned char rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
|
||||
}
|
||||
|
||||
|
||||
// unsigned long long to X
|
||||
template<Operator Op> bool compare( unsigned long long lhs, int rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
||||
@ -188,7 +189,7 @@ namespace Internal {
|
||||
template<Operator Op> bool compare( unsigned long long lhs, char rhs ) {
|
||||
return applyEvaluator<Op>( static_cast<long>( lhs ), rhs );
|
||||
}
|
||||
|
||||
|
||||
// pointer to long long (when comparing against NULL)
|
||||
template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) {
|
||||
return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
|
||||
@ -197,7 +198,7 @@ namespace Internal {
|
||||
return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
|
||||
}
|
||||
#endif // CATCH_CONFIG_CPP11_LONG_LONG
|
||||
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
||||
// pointer to nullptr_t (when comparing against nullptr)
|
||||
template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
|
||||
|
@ -32,13 +32,13 @@ namespace Catch {
|
||||
#ifdef __OBJC__
|
||||
// In Objective-C try objective-c exceptions first
|
||||
@try {
|
||||
throw;
|
||||
return tryTranslators();
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
return Catch::toString( [exception description] );
|
||||
}
|
||||
#else
|
||||
throw;
|
||||
return tryTranslators();
|
||||
#endif
|
||||
}
|
||||
catch( TestFailureException& ) {
|
||||
@ -54,20 +54,15 @@ namespace Catch {
|
||||
return msg;
|
||||
}
|
||||
catch(...) {
|
||||
return tryTranslators( m_translators.begin() );
|
||||
return "Unknown exception";
|
||||
}
|
||||
}
|
||||
|
||||
std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
|
||||
if( it == m_translators.end() )
|
||||
return "Unknown exception";
|
||||
|
||||
try {
|
||||
return (*it)->translate();
|
||||
}
|
||||
catch(...) {
|
||||
return tryTranslators( it+1 );
|
||||
}
|
||||
std::string tryTranslators() const {
|
||||
if( m_translators.empty() )
|
||||
throw;
|
||||
else
|
||||
return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -14,90 +14,159 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Wraps the LHS of an expression and captures the operator and RHS (if any) -
|
||||
// wrapping them all in a ResultBuilder object
|
||||
template<typename T>
|
||||
class ExpressionLhs {
|
||||
ExpressionLhs& operator = ( ExpressionLhs const& );
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
|
||||
# endif
|
||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
||||
class BinaryExpression;
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpression;
|
||||
|
||||
// Wraps the LHS of an expression and overloads comparison operators
|
||||
// for also capturing those and RHS (if any)
|
||||
template<typename T>
|
||||
class ExpressionLhs : public DecomposedExpression {
|
||||
public:
|
||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
|
||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
||||
ExpressionLhs( ExpressionLhs const& ) = default;
|
||||
ExpressionLhs( ExpressionLhs && ) = default;
|
||||
# endif
|
||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
|
||||
|
||||
ExpressionLhs& operator = ( const ExpressionLhs& );
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator == ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
|
||||
operator == ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator != ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
|
||||
operator != ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator < ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsLessThan, RhsT const&>
|
||||
operator < ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsLessThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator > ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
|
||||
operator > ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsGreaterThan>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator <= ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
|
||||
operator <= ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
template<typename RhsT>
|
||||
ResultBuilder& operator >= ( RhsT const& rhs ) {
|
||||
BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
|
||||
operator >= ( RhsT const& rhs ) {
|
||||
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator == ( bool rhs ) {
|
||||
BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
|
||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||
}
|
||||
|
||||
ResultBuilder& operator != ( bool rhs ) {
|
||||
BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
|
||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||
}
|
||||
|
||||
void endExpression() {
|
||||
bool value = m_lhs ? true : false;
|
||||
m_truthy = m_lhs ? true : false;
|
||||
m_rb
|
||||
.setLhs( Catch::toString( value ) )
|
||||
.setResultType( value )
|
||||
.endExpression();
|
||||
.setResultType( m_truthy )
|
||||
.endExpression( *this );
|
||||
}
|
||||
|
||||
// Only simple binary expressions are allowed on the LHS.
|
||||
// If more complex compositions are required then place the sub expression in parentheses
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
dest = Catch::toString( m_lhs );
|
||||
}
|
||||
|
||||
private:
|
||||
template<Internal::Operator Op, typename RhsT>
|
||||
ResultBuilder& captureExpression( RhsT const& rhs ) {
|
||||
return m_rb
|
||||
.setResultType( Internal::compare<Op>( m_lhs, rhs ) )
|
||||
.setLhs( Catch::toString( m_lhs ) )
|
||||
.setRhs( Catch::toString( rhs ) )
|
||||
.setOp( Internal::OperatorTraits<Op>::getName() );
|
||||
BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
|
||||
return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
|
||||
}
|
||||
|
||||
template<Internal::Operator Op>
|
||||
BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
|
||||
return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
|
||||
}
|
||||
|
||||
private:
|
||||
ResultBuilder& m_rb;
|
||||
T m_lhs;
|
||||
bool m_truthy;
|
||||
};
|
||||
|
||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
||||
class BinaryExpression : public DecomposedExpression {
|
||||
public:
|
||||
BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
|
||||
: m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
|
||||
|
||||
BinaryExpression& operator = ( BinaryExpression& );
|
||||
|
||||
void endExpression() const {
|
||||
m_rb
|
||||
.setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
|
||||
.endExpression( *this );
|
||||
}
|
||||
|
||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
std::string lhs = Catch::toString( m_lhs );
|
||||
std::string rhs = Catch::toString( m_rhs );
|
||||
char delim = lhs.size() + rhs.size() < 40 &&
|
||||
lhs.find('\n') == std::string::npos &&
|
||||
rhs.find('\n') == std::string::npos ? ' ' : '\n';
|
||||
dest.reserve( 7 + lhs.size() + rhs.size() );
|
||||
// 2 for spaces around operator
|
||||
// 2 for operator
|
||||
// 2 for parentheses (conditionally added later)
|
||||
// 1 for negation (conditionally added later)
|
||||
dest = lhs;
|
||||
dest += delim;
|
||||
dest += Internal::OperatorTraits<Op>::getName();
|
||||
dest += delim;
|
||||
dest += rhs;
|
||||
}
|
||||
|
||||
private:
|
||||
ResultBuilder& m_rb;
|
||||
LhsT m_lhs;
|
||||
RhsT m_rhs;
|
||||
};
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
class MatchExpression : public DecomposedExpression {
|
||||
public:
|
||||
MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
|
||||
: m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
|
||||
|
||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||
std::string matcherAsString = m_matcher.toString();
|
||||
dest = Catch::toString( m_arg );
|
||||
dest += ' ';
|
||||
if( matcherAsString == Detail::unprintableString )
|
||||
dest += m_matcherString;
|
||||
else
|
||||
dest += matcherAsString;
|
||||
}
|
||||
|
||||
private:
|
||||
ArgT m_arg;
|
||||
MatcherT m_matcher;
|
||||
char const* m_matcherString;
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@ -12,35 +12,115 @@
|
||||
|
||||
namespace Catch {
|
||||
|
||||
// Report the error condition then exit the process
|
||||
inline void fatal( std::string const& message, int exitCode ) {
|
||||
// Report the error condition
|
||||
inline void reportFatal( std::string const& message ) {
|
||||
IContext& context = Catch::getCurrentContext();
|
||||
IResultCapture* resultCapture = context.getResultCapture();
|
||||
resultCapture->handleFatalErrorCondition( message );
|
||||
|
||||
if( Catch::alwaysTrue() ) // avoids "no return" warnings
|
||||
exit( exitCode );
|
||||
}
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#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
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { DWORD id; const char* name; };
|
||||
extern SignalDefs signalDefs[];
|
||||
// There is no 1-1 mapping between signals and windows exceptions.
|
||||
// Windows can easily distinguish between SO and SigSegV,
|
||||
// but SigInt, SigTerm, etc are handled differently.
|
||||
SignalDefs signalDefs[] = {
|
||||
{ EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
|
||||
{ EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
|
||||
{ EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
|
||||
{ EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
|
||||
};
|
||||
|
||||
struct FatalConditionHandler {
|
||||
void reset() {}
|
||||
};
|
||||
|
||||
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
|
||||
if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
|
||||
reportFatal(signalDefs[i].name);
|
||||
}
|
||||
}
|
||||
// If its not an exception we care about, pass it along.
|
||||
// This stops us from eating debugger breaks etc.
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
FatalConditionHandler() {
|
||||
isSet = true;
|
||||
// 32k seems enough for Catch to handle stack overflow,
|
||||
// but the value was found experimentally, so there is no strong guarantee
|
||||
guaranteeSize = 32 * 1024;
|
||||
exceptionHandlerHandle = CATCH_NULL;
|
||||
// Register as first handler in current chain
|
||||
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
|
||||
// Pass in guarantee size to be filled
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
if (isSet) {
|
||||
// Unregister handler and restore the old guarantee
|
||||
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
|
||||
SetThreadStackGuarantee(&guaranteeSize);
|
||||
exceptionHandlerHandle = CATCH_NULL;
|
||||
isSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
private:
|
||||
static bool isSet;
|
||||
static ULONG guaranteeSize;
|
||||
static PVOID exceptionHandlerHandle;
|
||||
};
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
ULONG FatalConditionHandler::guaranteeSize = 0;
|
||||
PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
|
||||
|
||||
} // 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
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SignalDefs { int id; const char* name; };
|
||||
struct SignalDefs {
|
||||
int id;
|
||||
const char* name;
|
||||
};
|
||||
extern SignalDefs signalDefs[];
|
||||
SignalDefs signalDefs[] = {
|
||||
{ SIGINT, "SIGINT - Terminal interrupt signal" },
|
||||
@ -49,37 +129,72 @@ namespace Catch {
|
||||
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
|
||||
{ SIGTERM, "SIGTERM - Termination request signal" },
|
||||
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
|
||||
};
|
||||
};
|
||||
|
||||
struct FatalConditionHandler {
|
||||
|
||||
static bool isSet;
|
||||
static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
|
||||
static stack_t oldSigStack;
|
||||
static char altStackMem[SIGSTKSZ];
|
||||
|
||||
static void handleSignal( int sig ) {
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
||||
if( sig == signalDefs[i].id )
|
||||
fatal( signalDefs[i].name, -sig );
|
||||
fatal( "<unknown signal>", -sig );
|
||||
std::string name = "<unknown signal>";
|
||||
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
|
||||
SignalDefs &def = signalDefs[i];
|
||||
if (sig == def.id) {
|
||||
name = def.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
reportFatal(name);
|
||||
raise( sig );
|
||||
}
|
||||
|
||||
FatalConditionHandler() : m_isSet( true ) {
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
||||
signal( signalDefs[i].id, handleSignal );
|
||||
}
|
||||
~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
void reset() {
|
||||
if( m_isSet ) {
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
|
||||
signal( signalDefs[i].id, SIG_DFL );
|
||||
m_isSet = false;
|
||||
FatalConditionHandler() {
|
||||
isSet = true;
|
||||
stack_t sigStack;
|
||||
sigStack.ss_sp = altStackMem;
|
||||
sigStack.ss_size = SIGSTKSZ;
|
||||
sigStack.ss_flags = 0;
|
||||
sigaltstack(&sigStack, &oldSigStack);
|
||||
struct sigaction sa = { 0 };
|
||||
|
||||
sa.sa_handler = handleSignal;
|
||||
sa.sa_flags = SA_ONSTACK;
|
||||
for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
|
||||
sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool m_isSet;
|
||||
|
||||
~FatalConditionHandler() {
|
||||
reset();
|
||||
}
|
||||
static void reset() {
|
||||
if( isSet ) {
|
||||
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
|
||||
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
|
||||
sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
|
||||
}
|
||||
// Return the old stack
|
||||
sigaltstack(&oldSigStack, CATCH_NULL);
|
||||
isSet = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool FatalConditionHandler::isSet = false;
|
||||
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
|
||||
stack_t FatalConditionHandler::oldSigStack = {};
|
||||
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
||||
|
||||
#endif // not Windows
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "catch_context.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
@ -124,7 +123,7 @@ public:
|
||||
private:
|
||||
|
||||
void move( CompositeGenerator& other ) {
|
||||
std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
|
||||
m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
|
||||
m_totalSize += other.m_totalSize;
|
||||
other.m_composed.clear();
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "catch_result_builder.hpp"
|
||||
#include "catch_tag_alias_registry.hpp"
|
||||
#include "catch_test_case_tracker.hpp"
|
||||
#include "catch_matchers_string.hpp"
|
||||
|
||||
#include "../reporters/catch_reporter_multi.hpp"
|
||||
#include "../reporters/catch_reporter_xml.hpp"
|
||||
@ -49,6 +50,9 @@ namespace Catch {
|
||||
NonCopyable::~NonCopyable() {}
|
||||
IShared::~IShared() {}
|
||||
IStream::~IStream() CATCH_NOEXCEPT {}
|
||||
FileStream::~FileStream() CATCH_NOEXCEPT {}
|
||||
CoutStream::~CoutStream() CATCH_NOEXCEPT {}
|
||||
DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {}
|
||||
StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
|
||||
IContext::~IContext() {}
|
||||
IResultCapture::~IResultCapture() {}
|
||||
@ -87,14 +91,10 @@ namespace Catch {
|
||||
TestSpec::NamePattern::~NamePattern() {}
|
||||
TestSpec::TagPattern::~TagPattern() {}
|
||||
TestSpec::ExcludedPattern::~ExcludedPattern() {}
|
||||
|
||||
Matchers::Impl::StdString::Equals::~Equals() {}
|
||||
Matchers::Impl::StdString::Contains::~Contains() {}
|
||||
Matchers::Impl::StdString::StartsWith::~StartsWith() {}
|
||||
Matchers::Impl::StdString::EndsWith::~EndsWith() {}
|
||||
Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
|
||||
|
||||
void Config::dummy() {}
|
||||
|
||||
|
||||
namespace TestCaseTracking {
|
||||
ITracker::~ITracker() {}
|
||||
TrackerBase::~TrackerBase() {}
|
||||
|
@ -38,6 +38,8 @@ namespace Catch {
|
||||
virtual std::string getCurrentTestName() const = 0;
|
||||
virtual const AssertionResult* getLastResult() const = 0;
|
||||
|
||||
virtual void exceptionEarlyReported() = 0;
|
||||
|
||||
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -37,6 +37,11 @@ namespace Catch {
|
||||
InLexicographicalOrder,
|
||||
InRandomOrder
|
||||
}; };
|
||||
struct UseColour { enum YesOrNo {
|
||||
Auto,
|
||||
Yes,
|
||||
No
|
||||
}; };
|
||||
|
||||
class TestSpec;
|
||||
|
||||
@ -56,7 +61,9 @@ namespace Catch {
|
||||
virtual TestSpec const& testSpec() const = 0;
|
||||
virtual RunTests::InWhatOrder runOrder() const = 0;
|
||||
virtual unsigned int rngSeed() const = 0;
|
||||
virtual bool forceColour() const = 0;
|
||||
virtual UseColour::YesOrNo useColour() const = 0;
|
||||
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -9,15 +9,20 @@
|
||||
#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
typedef std::string(*exceptionTranslateFunction)();
|
||||
|
||||
struct IExceptionTranslator;
|
||||
typedef std::vector<const IExceptionTranslator*> ExceptionTranslators;
|
||||
|
||||
struct IExceptionTranslator {
|
||||
virtual ~IExceptionTranslator();
|
||||
virtual std::string translate() const = 0;
|
||||
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
|
||||
};
|
||||
|
||||
struct IExceptionTranslatorRegistry {
|
||||
@ -35,9 +40,12 @@ namespace Catch {
|
||||
: m_translateFunction( translateFunction )
|
||||
{}
|
||||
|
||||
virtual std::string translate() const {
|
||||
virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE {
|
||||
try {
|
||||
throw;
|
||||
if( it == itEnd )
|
||||
throw;
|
||||
else
|
||||
return (*it)->translate( it+1, itEnd );
|
||||
}
|
||||
catch( T& ex ) {
|
||||
return m_translateFunction( ex );
|
||||
@ -58,9 +66,11 @@ namespace Catch {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
|
||||
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
|
||||
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||
static std::string translatorName( signature ); \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
|
||||
static std::string translatorName( signature )
|
||||
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
|
||||
|
@ -20,12 +20,15 @@ namespace Catch {
|
||||
struct IExceptionTranslator;
|
||||
struct IReporterRegistry;
|
||||
struct IReporterFactory;
|
||||
struct ITagAliasRegistry;
|
||||
|
||||
struct IRegistryHub {
|
||||
virtual ~IRegistryHub();
|
||||
|
||||
virtual IReporterRegistry const& getReporterRegistry() const = 0;
|
||||
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
|
||||
virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
|
||||
|
||||
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
|
||||
};
|
||||
|
||||
@ -35,6 +38,7 @@ namespace Catch {
|
||||
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
|
||||
virtual void registerTest( TestCase const& testInfo ) = 0;
|
||||
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
|
||||
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
|
||||
};
|
||||
|
||||
IRegistryHub& getRegistryHub();
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Catch
|
||||
{
|
||||
@ -219,6 +218,7 @@ namespace Catch
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
class MultipleReporters;
|
||||
|
||||
struct IStreamingReporter : IShared {
|
||||
virtual ~IStreamingReporter();
|
||||
@ -240,13 +240,15 @@ namespace Catch
|
||||
|
||||
// The return value indicates if the messages buffer should be cleared:
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
|
||||
|
||||
|
||||
virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
|
||||
virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
|
||||
virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
||||
|
||||
|
||||
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||
|
||||
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
|
||||
};
|
||||
|
||||
|
||||
@ -267,7 +269,7 @@ namespace Catch
|
||||
};
|
||||
|
||||
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter );
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
|
||||
|
@ -34,7 +34,7 @@ namespace Catch {
|
||||
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
|
||||
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
|
||||
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
|
||||
|
@ -51,9 +51,9 @@ namespace Catch {
|
||||
}
|
||||
|
||||
if( !config.testSpec().hasFilters() )
|
||||
Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
|
||||
else
|
||||
Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
|
||||
return matchedTests;
|
||||
}
|
||||
|
||||
@ -68,7 +68,10 @@ namespace Catch {
|
||||
++it ) {
|
||||
matchedTests++;
|
||||
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
if( startsWith( testCaseInfo.name, '#' ) )
|
||||
Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
|
||||
else
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
}
|
||||
return matchedTests;
|
||||
}
|
||||
@ -129,9 +132,9 @@ namespace Catch {
|
||||
.setInitialIndent( 0 )
|
||||
.setIndent( oss.str().size() )
|
||||
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
|
||||
Catch::cout() << oss.str() << wrapper << "\n";
|
||||
Catch::cout() << oss.str() << wrapper << '\n';
|
||||
}
|
||||
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
|
||||
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
|
||||
return tagCounts.size();
|
||||
}
|
||||
|
||||
@ -150,9 +153,9 @@ namespace Catch {
|
||||
.setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
|
||||
Catch::cout() << " "
|
||||
<< it->first
|
||||
<< ":"
|
||||
<< ':'
|
||||
<< std::string( maxNameLen - it->first.size() + 2, ' ' )
|
||||
<< wrapper << "\n";
|
||||
<< wrapper << '\n';
|
||||
}
|
||||
Catch::cout() << std::endl;
|
||||
return factories.size();
|
||||
|
@ -8,272 +8,169 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
namespace Impl {
|
||||
|
||||
template<typename ExpressionT>
|
||||
struct Matcher : SharedImpl<IShared>
|
||||
{
|
||||
typedef ExpressionT ExpressionType;
|
||||
template<typename ArgT> struct MatchAllOf;
|
||||
template<typename ArgT> struct MatchAnyOf;
|
||||
template<typename ArgT> struct MatchNotOf;
|
||||
|
||||
virtual ~Matcher() {}
|
||||
virtual Ptr<Matcher> clone() const = 0;
|
||||
virtual bool match( ExpressionT const& expr ) const = 0;
|
||||
virtual std::string toString() const = 0;
|
||||
};
|
||||
|
||||
template<typename DerivedT, typename ExpressionT>
|
||||
struct MatcherImpl : Matcher<ExpressionT> {
|
||||
|
||||
virtual Ptr<Matcher<ExpressionT> > clone() const {
|
||||
return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
|
||||
}
|
||||
};
|
||||
|
||||
namespace Generic {
|
||||
template<typename ExpressionT>
|
||||
struct Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
|
||||
Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {}
|
||||
Not( Not const& other ) : m_matcher( other.m_matcher ) {}
|
||||
|
||||
virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE {
|
||||
return !m_matcher->match( expr );
|
||||
class MatcherUntypedBase {
|
||||
public:
|
||||
std::string toString() const {
|
||||
if( m_cachedToString.empty() )
|
||||
m_cachedToString = describe();
|
||||
return m_cachedToString;
|
||||
}
|
||||
|
||||
virtual std::string toString() const CATCH_OVERRIDE {
|
||||
return "not " + m_matcher->toString();
|
||||
}
|
||||
|
||||
Ptr< Matcher<ExpressionT> > m_matcher;
|
||||
protected:
|
||||
virtual ~MatcherUntypedBase();
|
||||
virtual std::string describe() const = 0;
|
||||
mutable std::string m_cachedToString;
|
||||
private:
|
||||
MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
|
||||
};
|
||||
|
||||
template<typename ExpressionT>
|
||||
class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
|
||||
public:
|
||||
template<typename ObjectT>
|
||||
struct MatcherMethod {
|
||||
virtual bool match( ObjectT const& arg ) const = 0;
|
||||
};
|
||||
template<typename PtrT>
|
||||
struct MatcherMethod<PtrT*> {
|
||||
virtual bool match( PtrT* arg ) const = 0;
|
||||
};
|
||||
|
||||
AllOf() {}
|
||||
AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
|
||||
template<typename ObjectT, typename ComparatorT = ObjectT>
|
||||
struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
|
||||
|
||||
AllOf& add( Matcher<ExpressionT> const& matcher ) {
|
||||
m_matchers.push_back( matcher.clone() );
|
||||
return *this;
|
||||
}
|
||||
virtual bool match( ExpressionT const& expr ) const
|
||||
{
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
||||
if( !m_matchers[i]->match( expr ) )
|
||||
|
||||
MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
|
||||
MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
|
||||
MatchNotOf<ComparatorT> operator ! () const;
|
||||
};
|
||||
|
||||
template<typename ArgT>
|
||||
struct MatchAllOf : MatcherBase<ArgT> {
|
||||
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||
if (!m_matchers[i]->match(arg))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "( ";
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
std::string description;
|
||||
description.reserve( 4 + m_matchers.size()*32 );
|
||||
description += "( ";
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||
if( i != 0 )
|
||||
oss << " and ";
|
||||
oss << m_matchers[i]->toString();
|
||||
description += " and ";
|
||||
description += m_matchers[i]->toString();
|
||||
}
|
||||
oss << " )";
|
||||
return oss.str();
|
||||
description += " )";
|
||||
return description;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
||||
};
|
||||
|
||||
template<typename ExpressionT>
|
||||
class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
|
||||
public:
|
||||
|
||||
AnyOf() {}
|
||||
AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
|
||||
|
||||
AnyOf& add( Matcher<ExpressionT> const& matcher ) {
|
||||
m_matchers.push_back( matcher.clone() );
|
||||
MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
|
||||
m_matchers.push_back( &other );
|
||||
return *this;
|
||||
}
|
||||
virtual bool match( ExpressionT const& expr ) const
|
||||
{
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
||||
if( m_matchers[i]->match( expr ) )
|
||||
|
||||
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||
};
|
||||
template<typename ArgT>
|
||||
struct MatchAnyOf : MatcherBase<ArgT> {
|
||||
|
||||
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||
if (m_matchers[i]->match(arg))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "( ";
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
std::string description;
|
||||
description.reserve( 4 + m_matchers.size()*32 );
|
||||
description += "( ";
|
||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||
if( i != 0 )
|
||||
oss << " or ";
|
||||
oss << m_matchers[i]->toString();
|
||||
description += " or ";
|
||||
description += m_matchers[i]->toString();
|
||||
}
|
||||
oss << " )";
|
||||
return oss.str();
|
||||
description += " )";
|
||||
return description;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
||||
};
|
||||
}
|
||||
|
||||
namespace StdString {
|
||||
|
||||
inline std::string makeString( std::string const& str ) { return str; }
|
||||
inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
|
||||
|
||||
struct CasedString
|
||||
{
|
||||
CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
|
||||
: m_caseSensitivity( caseSensitivity ),
|
||||
m_str( adjustString( str ) )
|
||||
{}
|
||||
std::string adjustString( std::string const& str ) const {
|
||||
return m_caseSensitivity == CaseSensitive::No
|
||||
? toLower( str )
|
||||
: str;
|
||||
|
||||
}
|
||||
std::string toStringSuffix() const
|
||||
{
|
||||
return m_caseSensitivity == CaseSensitive::No
|
||||
? " (case insensitive)"
|
||||
: "";
|
||||
}
|
||||
CaseSensitive::Choice m_caseSensitivity;
|
||||
std::string m_str;
|
||||
};
|
||||
|
||||
struct Equals : MatcherImpl<Equals, std::string> {
|
||||
Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
||||
: m_data( str, caseSensitivity )
|
||||
{}
|
||||
Equals( Equals const& other ) : m_data( other.m_data ){}
|
||||
|
||||
virtual ~Equals();
|
||||
|
||||
virtual bool match( std::string const& expr ) const {
|
||||
return m_data.m_str == m_data.adjustString( expr );;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
|
||||
m_matchers.push_back( &other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||
};
|
||||
|
||||
struct Contains : MatcherImpl<Contains, std::string> {
|
||||
Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
||||
: m_data( substr, caseSensitivity ){}
|
||||
Contains( Contains const& other ) : m_data( other.m_data ){}
|
||||
template<typename ArgT>
|
||||
struct MatchNotOf : MatcherBase<ArgT> {
|
||||
|
||||
virtual ~Contains();
|
||||
MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
|
||||
|
||||
virtual bool match( std::string const& expr ) const {
|
||||
return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||
return !m_underlyingMatcher.match( arg );
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "not " + m_underlyingMatcher.toString();
|
||||
}
|
||||
MatcherBase<ArgT> const& m_underlyingMatcher;
|
||||
};
|
||||
|
||||
struct StartsWith : MatcherImpl<StartsWith, std::string> {
|
||||
StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
||||
: m_data( substr, caseSensitivity ){}
|
||||
|
||||
StartsWith( StartsWith const& other ) : m_data( other.m_data ){}
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const {
|
||||
return MatchAllOf<ComparatorT>() && *this && other;
|
||||
}
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const {
|
||||
return MatchAnyOf<ComparatorT>() || *this || other;
|
||||
}
|
||||
template<typename ObjectT, typename ComparatorT>
|
||||
MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const {
|
||||
return MatchNotOf<ComparatorT>( *this );
|
||||
}
|
||||
|
||||
virtual ~StartsWith();
|
||||
|
||||
virtual bool match( std::string const& expr ) const {
|
||||
return m_data.adjustString( expr ).find( m_data.m_str ) == 0;
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
};
|
||||
|
||||
struct EndsWith : MatcherImpl<EndsWith, std::string> {
|
||||
EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
||||
: m_data( substr, caseSensitivity ){}
|
||||
EndsWith( EndsWith const& other ) : m_data( other.m_data ){}
|
||||
|
||||
virtual ~EndsWith();
|
||||
|
||||
virtual bool match( std::string const& expr ) const {
|
||||
return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size();
|
||||
}
|
||||
virtual std::string toString() const {
|
||||
return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix();
|
||||
}
|
||||
|
||||
CasedString m_data;
|
||||
};
|
||||
} // namespace StdString
|
||||
} // namespace Impl
|
||||
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// This allows the types to be inferred
|
||||
template<typename ExpressionT>
|
||||
inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
|
||||
return Impl::Generic::Not<ExpressionT>( m );
|
||||
// - deprecated: prefer ||, && and !
|
||||
template<typename T>
|
||||
inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
|
||||
return Impl::MatchNotOf<T>( underlyingMatcher );
|
||||
}
|
||||
|
||||
template<typename ExpressionT>
|
||||
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
||||
Impl::Matcher<ExpressionT> const& m2 ) {
|
||||
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
|
||||
template<typename T>
|
||||
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
|
||||
return Impl::MatchAllOf<T>() && m1 && m2;
|
||||
}
|
||||
template<typename ExpressionT>
|
||||
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
||||
Impl::Matcher<ExpressionT> const& m2,
|
||||
Impl::Matcher<ExpressionT> const& m3 ) {
|
||||
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
||||
template<typename T>
|
||||
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
|
||||
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
|
||||
}
|
||||
template<typename ExpressionT>
|
||||
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
||||
Impl::Matcher<ExpressionT> const& m2 ) {
|
||||
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
|
||||
template<typename T>
|
||||
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
|
||||
return Impl::MatchAnyOf<T>() || m1 || m2;
|
||||
}
|
||||
template<typename ExpressionT>
|
||||
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
||||
Impl::Matcher<ExpressionT> const& m2,
|
||||
Impl::Matcher<ExpressionT> const& m3 ) {
|
||||
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
||||
}
|
||||
|
||||
inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||
return Impl::StdString::Equals( str, caseSensitivity );
|
||||
}
|
||||
inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||
return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity );
|
||||
}
|
||||
inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||
return Impl::StdString::Contains( substr, caseSensitivity );
|
||||
}
|
||||
inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||
return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity );
|
||||
}
|
||||
inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
|
||||
return Impl::StdString::StartsWith( substr );
|
||||
}
|
||||
inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
|
||||
return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
|
||||
}
|
||||
inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
|
||||
return Impl::StdString::EndsWith( substr );
|
||||
}
|
||||
inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
|
||||
return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
|
||||
template<typename T>
|
||||
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
|
||||
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
|
||||
using namespace Matchers;
|
||||
using Matchers::Impl::MatcherBase;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
|
67
include/internal/catch_matchers_string.h
Normal file
67
include/internal/catch_matchers_string.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Created by Phil Nash on 08/02/2017.
|
||||
* Copyright (c) 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
|
||||
|
||||
#include "catch_matchers.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
namespace StdString {
|
||||
|
||||
struct CasedString
|
||||
{
|
||||
CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
|
||||
std::string adjustString( std::string const& str ) const;
|
||||
std::string caseSensitivitySuffix() const;
|
||||
|
||||
CaseSensitive::Choice m_caseSensitivity;
|
||||
std::string m_str;
|
||||
};
|
||||
|
||||
struct StringMatcherBase : MatcherBase<std::string> {
|
||||
StringMatcherBase( std::string const& operation, CasedString const& comparator );
|
||||
virtual std::string describe() const CATCH_OVERRIDE;
|
||||
|
||||
CasedString m_comparator;
|
||||
std::string m_operation;
|
||||
};
|
||||
|
||||
struct EqualsMatcher : StringMatcherBase {
|
||||
EqualsMatcher( CasedString const& comparator );
|
||||
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
|
||||
};
|
||||
struct ContainsMatcher : StringMatcherBase {
|
||||
ContainsMatcher( CasedString const& comparator );
|
||||
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
|
||||
};
|
||||
struct StartsWithMatcher : StringMatcherBase {
|
||||
StartsWithMatcher( CasedString const& comparator );
|
||||
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
|
||||
};
|
||||
struct EndsWithMatcher : StringMatcherBase {
|
||||
EndsWithMatcher( CasedString const& comparator );
|
||||
virtual bool match( std::string const& source ) const CATCH_OVERRIDE;
|
||||
};
|
||||
|
||||
} // namespace StdString
|
||||
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// This allows the types to be inferred
|
||||
|
||||
StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
|
||||
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 );
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED
|
93
include/internal/catch_matchers_string.hpp
Normal file
93
include/internal/catch_matchers_string.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Created by Phil Nash on 08/02/2017.
|
||||
* Copyright (c) 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)
|
||||
*/
|
||||
|
||||
#include "catch_matchers.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
namespace StdString {
|
||||
|
||||
CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
|
||||
: m_caseSensitivity( caseSensitivity ),
|
||||
m_str( adjustString( str ) )
|
||||
{}
|
||||
std::string CasedString::adjustString( std::string const& str ) const {
|
||||
return m_caseSensitivity == CaseSensitive::No
|
||||
? toLower( str )
|
||||
: str;
|
||||
}
|
||||
std::string CasedString::caseSensitivitySuffix() const {
|
||||
return m_caseSensitivity == CaseSensitive::No
|
||||
? " (case insensitive)"
|
||||
: std::string();
|
||||
}
|
||||
|
||||
|
||||
StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
|
||||
: m_comparator( comparator ),
|
||||
m_operation( operation ) {
|
||||
}
|
||||
|
||||
std::string StringMatcherBase::describe() const {
|
||||
std::string description;
|
||||
description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
|
||||
m_comparator.caseSensitivitySuffix().size());
|
||||
description += m_operation;
|
||||
description += ": \"";
|
||||
description += m_comparator.m_str;
|
||||
description += "\"";
|
||||
description += m_comparator.caseSensitivitySuffix();
|
||||
return description;
|
||||
}
|
||||
|
||||
EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
|
||||
|
||||
bool EqualsMatcher::match( std::string const& source ) const {
|
||||
return m_comparator.adjustString( source ) == m_comparator.m_str;
|
||||
}
|
||||
|
||||
|
||||
ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
|
||||
|
||||
bool ContainsMatcher::match( std::string const& source ) const {
|
||||
return contains( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||
}
|
||||
|
||||
|
||||
StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
|
||||
|
||||
bool StartsWithMatcher::match( std::string const& source ) const {
|
||||
return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||
}
|
||||
|
||||
|
||||
EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
|
||||
|
||||
bool EndsWithMatcher::match( std::string const& source ) const {
|
||||
return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||
}
|
||||
|
||||
} // namespace StdString
|
||||
|
||||
|
||||
StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
|
||||
return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||
}
|
||||
StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
|
||||
return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||
}
|
||||
StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
|
||||
return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||
}
|
||||
StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
|
||||
return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
101
include/internal/catch_matchers_vector.h
Normal file
101
include/internal/catch_matchers_vector.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Created by Phil Nash on 21/02/2017.
|
||||
* Copyright (c) 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)
|
||||
*/
|
||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
||||
|
||||
#include "catch_matchers.hpp"
|
||||
|
||||
namespace Catch {
|
||||
namespace Matchers {
|
||||
|
||||
namespace Vector {
|
||||
|
||||
template<typename T>
|
||||
struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> {
|
||||
|
||||
ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
|
||||
|
||||
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
|
||||
return std::find(v.begin(), v.end(), m_comparator) != v.end();
|
||||
}
|
||||
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "Contains: " + Catch::toString( m_comparator );
|
||||
}
|
||||
|
||||
T const& m_comparator;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
|
||||
|
||||
ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
|
||||
// !TBD: see note in EqualsMatcher
|
||||
if (m_comparator.size() > v.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < m_comparator.size(); ++i)
|
||||
if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "Contains: " + Catch::toString( m_comparator );
|
||||
}
|
||||
|
||||
std::vector<T> const& m_comparator;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > {
|
||||
|
||||
EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
|
||||
|
||||
bool match(std::vector<T> const &v) const CATCH_OVERRIDE {
|
||||
// !TBD: This currently works if all elements can be compared using !=
|
||||
// - a more general approach would be via a compare template that defaults
|
||||
// to using !=. but could be specialised for, e.g. std::vector<T> etc
|
||||
// - then just call that directly
|
||||
if (m_comparator.size() != v.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
if (m_comparator[i] != v[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "Equals: " + Catch::toString( m_comparator );
|
||||
}
|
||||
std::vector<T> const& m_comparator;
|
||||
};
|
||||
|
||||
} // namespace Vector
|
||||
|
||||
// The following functions create the actual matcher objects.
|
||||
// This allows the types to be inferred
|
||||
|
||||
template<typename T>
|
||||
Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
|
||||
return Vector::ContainsMatcher<T>( comparator );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
|
||||
return Vector::ContainsElementMatcher<T>( comparator );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
|
||||
return Vector::EqualsMatcher<T>( comparator );
|
||||
}
|
||||
|
||||
} // namespace Matchers
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED
|
@ -38,7 +38,9 @@ namespace Catch {
|
||||
{}
|
||||
|
||||
ScopedMessage::~ScopedMessage() {
|
||||
getResultCapture().popScopedMessage( m_info );
|
||||
if ( !std::uncaught_exception() ){
|
||||
getResultCapture().popScopedMessage(m_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
|
||||
|
||||
#include "catch_notimplemented_exception.h"
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@ -105,64 +105,67 @@ namespace Catch {
|
||||
namespace Impl {
|
||||
namespace NSStringMatchers {
|
||||
|
||||
template<typename MatcherT>
|
||||
struct StringHolder : MatcherImpl<MatcherT, NSString*>{
|
||||
struct StringHolder : MatcherBase<NSString*>{
|
||||
StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
|
||||
StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
|
||||
StringHolder() {
|
||||
arcSafeRelease( m_substr );
|
||||
}
|
||||
|
||||
virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* m_substr;
|
||||
};
|
||||
|
||||
struct Equals : StringHolder<Equals> {
|
||||
struct Equals : StringHolder {
|
||||
Equals( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
virtual bool match( ExpressionType const& str ) const {
|
||||
virtual bool match( NSString* str ) const CATCH_OVERRIDE {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str isEqualToString:m_substr];
|
||||
}
|
||||
|
||||
virtual std::string toString() const {
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "equals string: " + Catch::toString( m_substr );
|
||||
}
|
||||
};
|
||||
|
||||
struct Contains : StringHolder<Contains> {
|
||||
struct Contains : StringHolder {
|
||||
Contains( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
virtual bool match( ExpressionType const& str ) const {
|
||||
virtual bool match( NSString* str ) const {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location != NSNotFound;
|
||||
}
|
||||
|
||||
virtual std::string toString() const {
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "contains string: " + Catch::toString( m_substr );
|
||||
}
|
||||
};
|
||||
|
||||
struct StartsWith : StringHolder<StartsWith> {
|
||||
struct StartsWith : StringHolder {
|
||||
StartsWith( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
virtual bool match( ExpressionType const& str ) const {
|
||||
virtual bool match( NSString* str ) const {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location == 0;
|
||||
}
|
||||
|
||||
virtual std::string toString() const {
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "starts with: " + Catch::toString( m_substr );
|
||||
}
|
||||
};
|
||||
struct EndsWith : StringHolder<EndsWith> {
|
||||
struct EndsWith : StringHolder {
|
||||
EndsWith( NSString* substr ) : StringHolder( substr ){}
|
||||
|
||||
virtual bool match( ExpressionType const& str ) const {
|
||||
virtual bool match( NSString* str ) const {
|
||||
return (str != nil || m_substr == nil ) &&
|
||||
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
|
||||
}
|
||||
|
||||
virtual std::string toString() const {
|
||||
virtual std::string describe() const CATCH_OVERRIDE {
|
||||
return "ends with: " + Catch::toString( m_substr );
|
||||
}
|
||||
};
|
||||
|
@ -66,8 +66,18 @@ namespace Catch {
|
||||
}
|
||||
|
||||
private:
|
||||
T* nullableValue;
|
||||
char storage[sizeof(T)];
|
||||
T *nullableValue;
|
||||
union {
|
||||
char storage[sizeof(T)];
|
||||
|
||||
// These are here to force alignment for the storage
|
||||
long double dummy1;
|
||||
void (*dummy2)();
|
||||
long double dummy3;
|
||||
#ifdef CATCH_CONFIG_CPP11_LONG_LONG
|
||||
long long dummy4;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace Catch
|
||||
|
@ -10,11 +10,19 @@
|
||||
#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
|
||||
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
|
||||
#define CATCH_PLATFORM_MAC
|
||||
# define CATCH_PLATFORM_MAC
|
||||
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#define CATCH_PLATFORM_IPHONE
|
||||
# define CATCH_PLATFORM_IPHONE
|
||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define CATCH_PLATFORM_LINUX
|
||||
#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define CATCH_PLATFORM_WINDOWS
|
||||
# define CATCH_PLATFORM_WINDOWS
|
||||
# if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
|
||||
# define CATCH_DEFINES_NOMINMAX
|
||||
# endif
|
||||
# if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
|
||||
# define CATCH_DEFINES_WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "catch_test_case_registry_impl.hpp"
|
||||
#include "catch_reporter_registry.hpp"
|
||||
#include "catch_exception_translator_registry.hpp"
|
||||
#include "catch_tag_alias_registry.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -35,6 +36,10 @@ namespace Catch {
|
||||
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
|
||||
return m_exceptionTranslatorRegistry;
|
||||
}
|
||||
virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
|
||||
return m_tagAliasRegistry;
|
||||
}
|
||||
|
||||
|
||||
public: // IMutableRegistryHub
|
||||
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
|
||||
@ -49,11 +54,15 @@ namespace Catch {
|
||||
virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
|
||||
m_exceptionTranslatorRegistry.registerTranslator( translator );
|
||||
}
|
||||
virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
|
||||
m_tagAliasRegistry.add( alias, tag, lineInfo );
|
||||
}
|
||||
|
||||
private:
|
||||
TestRegistry m_testCaseRegistry;
|
||||
ReporterRegistry m_reporterRegistry;
|
||||
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
|
||||
TagAliasRegistry m_tagAliasRegistry;
|
||||
};
|
||||
|
||||
// Single, global, instance
|
||||
|
@ -64,22 +64,22 @@ namespace Catch {
|
||||
getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class ListenerRegistrar {
|
||||
|
||||
|
||||
class ListenerFactory : public SharedImpl<IReporterFactory> {
|
||||
|
||||
|
||||
virtual IStreamingReporter* create( ReporterConfig const& config ) const {
|
||||
return new T( config );
|
||||
}
|
||||
virtual std::string getDescription() const {
|
||||
return "";
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
ListenerRegistrar() {
|
||||
getMutableRegistryHub().registerListener( new ListenerFactory() );
|
||||
}
|
||||
@ -92,7 +92,11 @@ namespace Catch {
|
||||
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
|
||||
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
|
||||
|
||||
// Deprecated - use the form without INTERNAL_
|
||||
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
|
||||
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
|
||||
|
||||
#define CATCH_REGISTER_LISTENER( listenerType ) \
|
||||
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
|
||||
|
@ -19,28 +19,27 @@ namespace Catch {
|
||||
|
||||
template<typename T> class ExpressionLhs;
|
||||
|
||||
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
||||
|
||||
struct CopyableStream {
|
||||
CopyableStream() {}
|
||||
CopyableStream( CopyableStream const& other ) {
|
||||
oss << other.oss.str();
|
||||
}
|
||||
CopyableStream& operator=( CopyableStream const& other ) {
|
||||
oss.str("");
|
||||
oss.str(std::string());
|
||||
oss << other.oss.str();
|
||||
return *this;
|
||||
}
|
||||
std::ostringstream oss;
|
||||
};
|
||||
|
||||
class ResultBuilder {
|
||||
class ResultBuilder : public DecomposedExpression {
|
||||
public:
|
||||
ResultBuilder( char const* macroName,
|
||||
SourceLineInfo const& lineInfo,
|
||||
char const* capturedExpression,
|
||||
ResultDisposition::Flags resultDisposition,
|
||||
char const* secondArg = "" );
|
||||
~ResultBuilder();
|
||||
|
||||
template<typename T>
|
||||
ExpressionLhs<T const&> operator <= ( T const& operand );
|
||||
@ -52,42 +51,40 @@ namespace Catch {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
||||
|
||||
ResultBuilder& setResultType( ResultWas::OfType result );
|
||||
ResultBuilder& setResultType( bool result );
|
||||
ResultBuilder& setLhs( std::string const& lhs );
|
||||
ResultBuilder& setRhs( std::string const& rhs );
|
||||
ResultBuilder& setOp( std::string const& op );
|
||||
|
||||
void endExpression();
|
||||
void endExpression( DecomposedExpression const& expr );
|
||||
|
||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
|
||||
|
||||
std::string reconstructExpression() const;
|
||||
AssertionResult build() const;
|
||||
AssertionResult build( DecomposedExpression const& expr ) const;
|
||||
|
||||
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
||||
void captureResult( ResultWas::OfType resultType );
|
||||
void captureExpression();
|
||||
void captureExpectedException( std::string const& expectedMessage );
|
||||
void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher );
|
||||
void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
|
||||
void handleResult( AssertionResult const& result );
|
||||
void react();
|
||||
bool shouldDebugBreak() const;
|
||||
bool allowThrows() const;
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
|
||||
|
||||
void setExceptionGuard();
|
||||
void unsetExceptionGuard();
|
||||
|
||||
private:
|
||||
AssertionInfo m_assertionInfo;
|
||||
AssertionResultData m_data;
|
||||
struct ExprComponents {
|
||||
ExprComponents() : testFalse( false ) {}
|
||||
bool testFalse;
|
||||
std::string lhs, rhs, op;
|
||||
} m_exprComponents;
|
||||
CopyableStream m_stream;
|
||||
|
||||
|
||||
bool m_shouldDebugBreak;
|
||||
bool m_shouldThrow;
|
||||
bool m_guardException;
|
||||
};
|
||||
|
||||
} // namespace Catch
|
||||
@ -106,6 +103,15 @@ namespace Catch {
|
||||
return ExpressionLhs<bool>( *this, value );
|
||||
}
|
||||
|
||||
template<typename ArgT, typename MatcherT>
|
||||
inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
|
||||
char const* matcherString ) {
|
||||
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
|
||||
setResultType( matcher.match( arg ) );
|
||||
endExpression( expr );
|
||||
}
|
||||
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||
|
@ -30,9 +30,20 @@ namespace Catch {
|
||||
char const* secondArg )
|
||||
: m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
|
||||
m_shouldDebugBreak( false ),
|
||||
m_shouldThrow( false )
|
||||
m_shouldThrow( false ),
|
||||
m_guardException( false )
|
||||
{}
|
||||
|
||||
ResultBuilder::~ResultBuilder() {
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
if ( m_guardException ) {
|
||||
m_stream.oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
|
||||
captureResult( ResultWas::ThrewException );
|
||||
getCurrentContext().getResultCapture()->exceptionEarlyReported();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
|
||||
m_data.resultType = result;
|
||||
return *this;
|
||||
@ -41,22 +52,10 @@ namespace Catch {
|
||||
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
|
||||
m_exprComponents.lhs = lhs;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
|
||||
m_exprComponents.rhs = rhs;
|
||||
return *this;
|
||||
}
|
||||
ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
|
||||
m_exprComponents.op = op;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ResultBuilder::endExpression() {
|
||||
m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
|
||||
captureExpression();
|
||||
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
|
||||
AssertionResult result = build( expr );
|
||||
handleResult( result );
|
||||
}
|
||||
|
||||
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
||||
@ -69,20 +68,22 @@ namespace Catch {
|
||||
setResultType( resultType );
|
||||
captureExpression();
|
||||
}
|
||||
|
||||
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
||||
if( expectedMessage.empty() )
|
||||
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
|
||||
captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() );
|
||||
else
|
||||
captureExpectedException( Matchers::Equals( expectedMessage ) );
|
||||
}
|
||||
|
||||
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
||||
|
||||
assert( m_exprComponents.testFalse == false );
|
||||
|
||||
void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
|
||||
|
||||
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
||||
AssertionResultData data = m_data;
|
||||
data.resultType = ResultWas::Ok;
|
||||
data.reconstructedExpression = m_assertionInfo.capturedExpression;
|
||||
|
||||
|
||||
std::string actualMessage = Catch::translateActiveException();
|
||||
if( !matcher.match( actualMessage ) ) {
|
||||
data.resultType = ResultWas::ExpressionFailed;
|
||||
@ -96,10 +97,11 @@ namespace Catch {
|
||||
AssertionResult result = build();
|
||||
handleResult( result );
|
||||
}
|
||||
|
||||
void ResultBuilder::handleResult( AssertionResult const& result )
|
||||
{
|
||||
getResultCapture().assertionEnded( result );
|
||||
|
||||
|
||||
if( !result.isOk() ) {
|
||||
if( getCurrentContext().getConfig()->shouldDebugBreak() )
|
||||
m_shouldDebugBreak = true;
|
||||
@ -107,7 +109,17 @@ namespace Catch {
|
||||
m_shouldThrow = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ResultBuilder::react() {
|
||||
#if defined(CATCH_CONFIG_FAST_COMPILE)
|
||||
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 throw statement
|
||||
///////////////////////////////////////////////////////////////////
|
||||
CATCH_BREAK_INTO_DEBUGGER();
|
||||
}
|
||||
#endif
|
||||
if( m_shouldThrow )
|
||||
throw Catch::TestFailureException();
|
||||
}
|
||||
@ -117,43 +129,39 @@ namespace Catch {
|
||||
|
||||
AssertionResult ResultBuilder::build() const
|
||||
{
|
||||
assert( m_data.resultType != ResultWas::Unknown );
|
||||
return build( *this );
|
||||
}
|
||||
|
||||
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
|
||||
// a temporary DecomposedExpression, which in turn holds references to
|
||||
// operands, possibly temporary as well.
|
||||
// It should immediately be passed to handleResult; if the expression
|
||||
// needs to be reported, its string expansion must be composed before
|
||||
// the temporaries are destroyed.
|
||||
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
|
||||
{
|
||||
assert( m_data.resultType != ResultWas::Unknown );
|
||||
AssertionResultData data = m_data;
|
||||
|
||||
// Flip bool results if testFalse is set
|
||||
if( m_exprComponents.testFalse ) {
|
||||
if( data.resultType == ResultWas::Ok )
|
||||
data.resultType = ResultWas::ExpressionFailed;
|
||||
else if( data.resultType == ResultWas::ExpressionFailed )
|
||||
data.resultType = ResultWas::Ok;
|
||||
// Flip bool results if FalseTest flag is set
|
||||
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
|
||||
data.negate( expr.isBinaryExpression() );
|
||||
}
|
||||
|
||||
data.message = m_stream.oss.str();
|
||||
data.reconstructedExpression = reconstructExpression();
|
||||
if( m_exprComponents.testFalse ) {
|
||||
if( m_exprComponents.op == "" )
|
||||
data.reconstructedExpression = "!" + data.reconstructedExpression;
|
||||
else
|
||||
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
|
||||
}
|
||||
data.decomposedExpression = &expr; // for lazy reconstruction
|
||||
return AssertionResult( m_assertionInfo, data );
|
||||
}
|
||||
std::string ResultBuilder::reconstructExpression() const {
|
||||
if( m_exprComponents.op == "" )
|
||||
return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
|
||||
else if( m_exprComponents.op == "matches" )
|
||||
return m_exprComponents.lhs + " " + m_exprComponents.rhs;
|
||||
else if( m_exprComponents.op != "!" ) {
|
||||
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
|
||||
m_exprComponents.lhs.find("\n") == std::string::npos &&
|
||||
m_exprComponents.rhs.find("\n") == std::string::npos )
|
||||
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
|
||||
else
|
||||
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
|
||||
}
|
||||
else
|
||||
return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
|
||||
|
||||
void ResultBuilder::reconstructExpression( std::string& dest ) const {
|
||||
dest = m_assertionInfo.capturedExpression;
|
||||
}
|
||||
|
||||
void ResultBuilder::setExceptionGuard() {
|
||||
m_guardException = true;
|
||||
}
|
||||
void ResultBuilder::unsetExceptionGuard() {
|
||||
m_guardException = false;
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@ -55,7 +55,7 @@ namespace Catch {
|
||||
inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
|
||||
inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
|
||||
inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
|
||||
|
@ -64,7 +64,8 @@ namespace Catch {
|
||||
m_context( getCurrentMutableContext() ),
|
||||
m_activeTestCase( CATCH_NULL ),
|
||||
m_config( _config ),
|
||||
m_reporter( reporter )
|
||||
m_reporter( reporter ),
|
||||
m_shouldReportUnexpected ( true )
|
||||
{
|
||||
m_context.setRunner( this );
|
||||
m_context.setConfig( m_config );
|
||||
@ -94,13 +95,15 @@ namespace Catch {
|
||||
m_reporter->testCaseStarting( testInfo );
|
||||
|
||||
m_activeTestCase = &testCase;
|
||||
|
||||
|
||||
|
||||
do {
|
||||
m_trackerContext.startRun();
|
||||
ITracker& rootTracker = m_trackerContext.startRun();
|
||||
assert( rootTracker.isSectionTracker() );
|
||||
static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
|
||||
do {
|
||||
m_trackerContext.startCycle();
|
||||
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name );
|
||||
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
|
||||
runCurrentTest( redirectedCout, redirectedCerr );
|
||||
}
|
||||
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
|
||||
@ -109,6 +112,11 @@ namespace Catch {
|
||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
||||
|
||||
Totals deltaTotals = m_totals.delta( prevTotals );
|
||||
if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
|
||||
deltaTotals.assertions.failed++;
|
||||
deltaTotals.testCases.passed--;
|
||||
deltaTotals.testCases.failed++;
|
||||
}
|
||||
m_totals.testCases += deltaTotals.testCases;
|
||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
@ -137,11 +145,12 @@ namespace Catch {
|
||||
m_totals.assertions.failed++;
|
||||
}
|
||||
|
||||
if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
|
||||
m_messages.clear();
|
||||
// We have no use for the return value (whether messages should be cleared), because messages were made scoped
|
||||
// and should be let to clear themselves out.
|
||||
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
|
||||
|
||||
// Reset working state
|
||||
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
||||
m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
||||
m_lastResult = result;
|
||||
}
|
||||
|
||||
@ -150,14 +159,11 @@ namespace Catch {
|
||||
Counts& assertions
|
||||
)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
|
||||
|
||||
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() );
|
||||
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
|
||||
if( !sectionTracker.isOpen() )
|
||||
return false;
|
||||
m_activeSections.push_back( §ionTracker );
|
||||
|
||||
|
||||
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
||||
|
||||
m_reporter->sectionStarting( sectionInfo );
|
||||
@ -177,16 +183,16 @@ namespace Catch {
|
||||
assertions.failed++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) {
|
||||
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
|
||||
bool missingAssertions = testForMissingAssertions( assertions );
|
||||
|
||||
|
||||
if( !m_activeSections.empty() ) {
|
||||
m_activeSections.back()->close();
|
||||
m_activeSections.pop_back();
|
||||
}
|
||||
|
||||
|
||||
m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
|
||||
m_messages.clear();
|
||||
}
|
||||
@ -197,10 +203,10 @@ namespace Catch {
|
||||
else
|
||||
m_activeSections.back()->close();
|
||||
m_activeSections.pop_back();
|
||||
|
||||
|
||||
m_unfinishedSections.push_back( endInfo );
|
||||
}
|
||||
|
||||
|
||||
virtual void pushScopedMessage( MessageInfo const& message ) {
|
||||
m_messages.push_back( message );
|
||||
}
|
||||
@ -212,18 +218,26 @@ namespace Catch {
|
||||
virtual std::string getCurrentTestName() const {
|
||||
return m_activeTestCase
|
||||
? m_activeTestCase->getTestCaseInfo().name
|
||||
: "";
|
||||
: std::string();
|
||||
}
|
||||
|
||||
virtual const AssertionResult* getLastResult() const {
|
||||
return &m_lastResult;
|
||||
}
|
||||
|
||||
virtual void exceptionEarlyReported() {
|
||||
m_shouldReportUnexpected = false;
|
||||
}
|
||||
|
||||
virtual void handleFatalErrorCondition( std::string const& message ) {
|
||||
ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
|
||||
resultBuilder.setResultType( ResultWas::FatalErrorCondition );
|
||||
resultBuilder << message;
|
||||
resultBuilder.captureExpression();
|
||||
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
||||
// Instead, fake a result data.
|
||||
AssertionResultData tempResult;
|
||||
tempResult.resultType = ResultWas::FatalErrorCondition;
|
||||
tempResult.message = message;
|
||||
AssertionResult result(m_lastAssertionInfo, tempResult);
|
||||
|
||||
getResultCapture().assertionEnded(result);
|
||||
|
||||
handleUnfinishedSections();
|
||||
|
||||
@ -242,11 +256,11 @@ namespace Catch {
|
||||
deltaTotals.testCases.failed = 1;
|
||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
"",
|
||||
"",
|
||||
std::string(),
|
||||
std::string(),
|
||||
false ) );
|
||||
m_totals.testCases.failed++;
|
||||
testGroupEnded( "", m_totals, 1, 1 );
|
||||
testGroupEnded( std::string(), m_totals, 1, 1 );
|
||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
||||
}
|
||||
|
||||
@ -264,11 +278,12 @@ namespace Catch {
|
||||
m_reporter->sectionStarting( testCaseSection );
|
||||
Counts prevAssertions = m_totals.assertions;
|
||||
double duration = 0;
|
||||
m_shouldReportUnexpected = true;
|
||||
try {
|
||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
|
||||
|
||||
seedRng( *m_config );
|
||||
|
||||
|
||||
Timer timer;
|
||||
timer.start();
|
||||
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
|
||||
@ -285,7 +300,11 @@ namespace Catch {
|
||||
// This just means the test was aborted due to failure
|
||||
}
|
||||
catch(...) {
|
||||
makeUnexpectedResultBuilder().useActiveException();
|
||||
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
|
||||
// are reported without translation at the point of origin.
|
||||
if (m_shouldReportUnexpected) {
|
||||
makeUnexpectedResultBuilder().useActiveException();
|
||||
}
|
||||
}
|
||||
m_testCaseTracker->close();
|
||||
handleUnfinishedSections();
|
||||
@ -318,7 +337,7 @@ namespace Catch {
|
||||
m_lastAssertionInfo.capturedExpression.c_str(),
|
||||
m_lastAssertionInfo.resultDisposition );
|
||||
}
|
||||
|
||||
|
||||
void handleUnfinishedSections() {
|
||||
// If sections ended prematurely due to an exception we stored their
|
||||
// infos here so we can tear them down outside the unwind process.
|
||||
@ -345,6 +364,7 @@ namespace Catch {
|
||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||
std::vector<ITracker*> m_activeSections;
|
||||
TrackerContext m_trackerContext;
|
||||
bool m_shouldReportUnexpected;
|
||||
};
|
||||
|
||||
IResultCapture& getResultCapture() {
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "catch_section.h"
|
||||
#include "catch_capture.hpp"
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_timer.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -31,6 +30,10 @@ namespace Catch {
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
|
||||
#endif
|
||||
Section::~Section() {
|
||||
if( m_sectionIncluded ) {
|
||||
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
|
||||
@ -40,6 +43,9 @@ namespace Catch {
|
||||
getResultCapture().sectionEnded( endInfo );
|
||||
}
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// This indicates whether the section should be executed or not
|
||||
Section::operator bool() const {
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "catch_common.h"
|
||||
#include "catch_totals.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SectionInfo {
|
||||
@ -23,17 +25,17 @@ namespace Catch {
|
||||
std::string description;
|
||||
SourceLineInfo lineInfo;
|
||||
};
|
||||
|
||||
|
||||
struct SectionEndInfo {
|
||||
SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
|
||||
: sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
|
||||
{}
|
||||
|
||||
|
||||
SectionInfo sectionInfo;
|
||||
Counts prevAssertions;
|
||||
double durationInSeconds;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
|
||||
|
@ -8,10 +8,7 @@
|
||||
#ifndef TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
#define TWOBLUECUBES_CATCH_SECTION_INFO_HPP_INCLUDED
|
||||
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "catch_section_info.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
@ -15,13 +15,14 @@
|
||||
#include <streambuf>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
std::ostream& cout();
|
||||
std::ostream& cerr();
|
||||
|
||||
|
||||
|
||||
struct IStream {
|
||||
virtual ~IStream() CATCH_NOEXCEPT;
|
||||
virtual std::ostream& stream() const = 0;
|
||||
@ -31,26 +32,29 @@ namespace Catch {
|
||||
mutable std::ofstream m_ofs;
|
||||
public:
|
||||
FileStream( std::string const& filename );
|
||||
virtual ~FileStream() CATCH_NOEXCEPT;
|
||||
public: // IStream
|
||||
virtual std::ostream& stream() const CATCH_OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CoutStream : public IStream {
|
||||
mutable std::ostream m_os;
|
||||
public:
|
||||
CoutStream();
|
||||
virtual ~CoutStream() CATCH_NOEXCEPT;
|
||||
|
||||
public: // IStream
|
||||
virtual std::ostream& stream() const CATCH_OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DebugOutStream : public IStream {
|
||||
std::auto_ptr<StreamBufBase> m_streamBuf;
|
||||
CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
|
||||
mutable std::ostream m_os;
|
||||
public:
|
||||
DebugOutStream();
|
||||
virtual ~DebugOutStream() CATCH_NOEXCEPT;
|
||||
|
||||
public: // IStream
|
||||
virtual std::ostream& stream() const CATCH_OVERRIDE;
|
||||
|
@ -61,31 +61,31 @@ namespace Catch {
|
||||
m_ofs.open( filename.c_str() );
|
||||
if( m_ofs.fail() ) {
|
||||
std::ostringstream oss;
|
||||
oss << "Unable to open file: '" << filename << "'";
|
||||
oss << "Unable to open file: '" << filename << '\'';
|
||||
throw std::domain_error( oss.str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::ostream& FileStream::stream() const {
|
||||
return m_ofs;
|
||||
}
|
||||
|
||||
|
||||
struct OutputDebugWriter {
|
||||
|
||||
|
||||
void operator()( std::string const&str ) {
|
||||
writeToDebugConsole( str );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DebugOutStream::DebugOutStream()
|
||||
: m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
|
||||
m_os( m_streamBuf.get() )
|
||||
{}
|
||||
|
||||
|
||||
std::ostream& DebugOutStream::stream() const {
|
||||
return m_os;
|
||||
}
|
||||
|
||||
|
||||
// Store the streambuf from cout up-front because
|
||||
// cout may get redirected when running tests
|
||||
CoutStream::CoutStream()
|
||||
@ -95,9 +95,8 @@ namespace Catch {
|
||||
std::ostream& CoutStream::stream() const {
|
||||
return m_os;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions
|
||||
|
||||
#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
|
||||
std::ostream& cout() {
|
||||
return std::cout;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#elif defined __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wparentheses"
|
||||
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wpadded"
|
||||
#endif
|
||||
|
@ -15,7 +15,7 @@
|
||||
namespace Catch {
|
||||
|
||||
struct TagAlias {
|
||||
TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
|
||||
TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
|
||||
|
||||
std::string tag;
|
||||
SourceLineInfo lineInfo;
|
||||
|
@ -19,8 +19,7 @@ namespace Catch {
|
||||
virtual ~TagAliasRegistry();
|
||||
virtual Option<TagAlias> find( std::string const& alias ) const;
|
||||
virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
|
||||
void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
|
||||
static TagAliasRegistry& get();
|
||||
void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
|
||||
|
||||
private:
|
||||
std::map<std::string, TagAlias> m_registry;
|
||||
|
@ -10,9 +10,8 @@
|
||||
|
||||
#include "catch_tag_alias_registry.h"
|
||||
#include "catch_console_colour.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include "catch_interfaces_registry_hub.h"
|
||||
#include "catch_stream.h"
|
||||
|
||||
namespace Catch {
|
||||
|
||||
@ -41,41 +40,36 @@ namespace Catch {
|
||||
return expandedTestSpec;
|
||||
}
|
||||
|
||||
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
||||
void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
|
||||
|
||||
if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
|
||||
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
|
||||
std::ostringstream oss;
|
||||
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
|
||||
oss << Colour( Colour::Red )
|
||||
<< "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
|
||||
<< Colour( Colour::FileName )
|
||||
<< lineInfo << '\n';
|
||||
throw std::domain_error( oss.str().c_str() );
|
||||
}
|
||||
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
|
||||
std::ostringstream oss;
|
||||
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
|
||||
<< "\tFirst seen at " << find(alias)->lineInfo << "\n"
|
||||
<< "\tRedefined at " << lineInfo;
|
||||
oss << Colour( Colour::Red )
|
||||
<< "error: tag alias, \"" << alias << "\" already registered.\n"
|
||||
<< "\tFirst seen at "
|
||||
<< Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
|
||||
<< Colour( Colour::Red ) << "\tRedefined at "
|
||||
<< Colour( Colour::FileName) << lineInfo << '\n';
|
||||
throw std::domain_error( oss.str().c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
TagAliasRegistry& TagAliasRegistry::get() {
|
||||
static TagAliasRegistry instance;
|
||||
return instance;
|
||||
ITagAliasRegistry::~ITagAliasRegistry() {}
|
||||
|
||||
ITagAliasRegistry const& ITagAliasRegistry::get() {
|
||||
return getRegistryHub().getTagAliasRegistry();
|
||||
}
|
||||
|
||||
ITagAliasRegistry::~ITagAliasRegistry() {}
|
||||
ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
|
||||
|
||||
|
||||
RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
||||
try {
|
||||
TagAliasRegistry::get().add( alias, tag, lineInfo );
|
||||
}
|
||||
catch( std::exception& ex ) {
|
||||
Colour colourGuard( Colour::Red );
|
||||
Catch::cerr() << ex.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
|
||||
}
|
||||
|
||||
} // end namespace Catch
|
||||
|
@ -29,9 +29,10 @@ namespace Catch {
|
||||
IsHidden = 1 << 1,
|
||||
ShouldFail = 1 << 2,
|
||||
MayFail = 1 << 3,
|
||||
Throws = 1 << 4
|
||||
Throws = 1 << 4,
|
||||
NonPortable = 1 << 5
|
||||
};
|
||||
|
||||
|
||||
TestCaseInfo( std::string const& _name,
|
||||
std::string const& _className,
|
||||
std::string const& _description,
|
||||
@ -41,7 +42,7 @@ namespace Catch {
|
||||
TestCaseInfo( TestCaseInfo const& other );
|
||||
|
||||
friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags );
|
||||
|
||||
|
||||
bool isHidden() const;
|
||||
bool throws() const;
|
||||
bool okToFail() const;
|
||||
|
@ -13,10 +13,12 @@
|
||||
#include "catch_interfaces_testcase.h"
|
||||
#include "catch_common.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
||||
if( startsWith( tag, "." ) ||
|
||||
if( startsWith( tag, '.' ) ||
|
||||
tag == "hide" ||
|
||||
tag == "!hide" )
|
||||
return TestCaseInfo::IsHidden;
|
||||
@ -26,25 +28,23 @@ namespace Catch {
|
||||
return TestCaseInfo::ShouldFail;
|
||||
else if( tag == "!mayfail" )
|
||||
return TestCaseInfo::MayFail;
|
||||
else if( tag == "!nonportable" )
|
||||
return TestCaseInfo::NonPortable;
|
||||
else
|
||||
return TestCaseInfo::None;
|
||||
}
|
||||
inline bool isReservedTag( std::string const& tag ) {
|
||||
return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
|
||||
return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
|
||||
}
|
||||
inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
|
||||
if( isReservedTag( tag ) ) {
|
||||
{
|
||||
Colour colourGuard( Colour::Red );
|
||||
Catch::cerr()
|
||||
<< "Tag name [" << tag << "] not allowed.\n"
|
||||
<< "Tag names starting with non alpha-numeric characters are reserved\n";
|
||||
}
|
||||
{
|
||||
Colour colourGuard( Colour::FileName );
|
||||
Catch::cerr() << _lineInfo << std::endl;
|
||||
}
|
||||
exit(1);
|
||||
std::ostringstream ss;
|
||||
ss << Colour(Colour::Red)
|
||||
<< "Tag name [" << tag << "] not allowed.\n"
|
||||
<< "Tag names starting with non alpha-numeric characters are reserved\n"
|
||||
<< Colour(Colour::FileName)
|
||||
<< _lineInfo << '\n';
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ namespace Catch {
|
||||
tags.insert( "hide" );
|
||||
tags.insert( "." );
|
||||
}
|
||||
|
||||
|
||||
TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
|
||||
return TestCase( _testCase, info );
|
||||
}
|
||||
@ -97,17 +97,17 @@ namespace Catch {
|
||||
{
|
||||
testCaseInfo.tags = tags;
|
||||
testCaseInfo.lcaseTags.clear();
|
||||
|
||||
|
||||
std::ostringstream oss;
|
||||
for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) {
|
||||
oss << "[" << *it << "]";
|
||||
oss << '[' << *it << ']';
|
||||
std::string lcaseTag = toLower( *it );
|
||||
testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
|
||||
testCaseInfo.lcaseTags.insert( lcaseTag );
|
||||
}
|
||||
testCaseInfo.tagsAsString = oss.str();
|
||||
}
|
||||
|
||||
|
||||
TestCaseInfo::TestCaseInfo( std::string const& _name,
|
||||
std::string const& _className,
|
||||
std::string const& _description,
|
||||
|
@ -16,32 +16,44 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct LexSort {
|
||||
bool operator() (TestCase i,TestCase j) const { return (i<j);}
|
||||
};
|
||||
struct RandomNumberGenerator {
|
||||
int operator()( int n ) const { return std::rand() % n; }
|
||||
typedef std::ptrdiff_t result_type;
|
||||
|
||||
result_type operator()( result_type n ) const { return std::rand() % n; }
|
||||
|
||||
#ifdef CATCH_CONFIG_CPP11_SHUFFLE
|
||||
static constexpr result_type min() { return 0; }
|
||||
static constexpr result_type max() { return 1000000; }
|
||||
result_type operator()() const { return std::rand() % max(); }
|
||||
#endif
|
||||
template<typename V>
|
||||
static void shuffle( V& vector ) {
|
||||
RandomNumberGenerator rng;
|
||||
#ifdef CATCH_CONFIG_CPP11_SHUFFLE
|
||||
std::shuffle( vector.begin(), vector.end(), rng );
|
||||
#else
|
||||
std::random_shuffle( vector.begin(), vector.end(), rng );
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
||||
|
||||
|
||||
std::vector<TestCase> sorted = unsortedTestCases;
|
||||
|
||||
|
||||
switch( config.runOrder() ) {
|
||||
case RunTests::InLexicographicalOrder:
|
||||
std::sort( sorted.begin(), sorted.end(), LexSort() );
|
||||
std::sort( sorted.begin(), sorted.end() );
|
||||
break;
|
||||
case RunTests::InRandomOrder:
|
||||
{
|
||||
seedRng( config );
|
||||
|
||||
RandomNumberGenerator rng;
|
||||
std::random_shuffle( sorted.begin(), sorted.end(), rng );
|
||||
RandomNumberGenerator::shuffle( sorted );
|
||||
}
|
||||
break;
|
||||
case RunTests::InDeclarationOrder:
|
||||
@ -60,17 +72,19 @@ namespace Catch {
|
||||
it != itEnd;
|
||||
++it ) {
|
||||
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
|
||||
if( !prev.second ){
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||
exit(1);
|
||||
if( !prev.second ) {
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << Colour( Colour::Red )
|
||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
|
||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
|
||||
std::vector<TestCase> filtered;
|
||||
filtered.reserve( testCases.size() );
|
||||
@ -87,12 +101,15 @@ namespace Catch {
|
||||
|
||||
class TestRegistry : public ITestCaseRegistry {
|
||||
public:
|
||||
TestRegistry() : m_unnamedCount( 0 ) {}
|
||||
TestRegistry()
|
||||
: m_currentSortOrder( RunTests::InDeclarationOrder ),
|
||||
m_unnamedCount( 0 )
|
||||
{}
|
||||
virtual ~TestRegistry();
|
||||
|
||||
virtual void registerTest( TestCase const& testCase ) {
|
||||
std::string name = testCase.getTestCaseInfo().name;
|
||||
if( name == "" ) {
|
||||
if( name.empty() ) {
|
||||
std::ostringstream oss;
|
||||
oss << "Anonymous test case " << ++m_unnamedCount;
|
||||
return registerTest( testCase.withName( oss.str() ) );
|
||||
@ -141,7 +158,7 @@ namespace Catch {
|
||||
|
||||
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
||||
std::string className = classOrQualifiedMethodName;
|
||||
if( startsWith( className, "&" ) )
|
||||
if( startsWith( className, '&' ) )
|
||||
{
|
||||
std::size_t lastColons = className.rfind( "::" );
|
||||
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
||||
@ -152,29 +169,38 @@ namespace Catch {
|
||||
return className;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void registerTestCase
|
||||
( ITestCase* testCase,
|
||||
char const* classOrQualifiedMethodName,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
|
||||
AutoReg::AutoReg( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc ) {
|
||||
getMutableRegistryHub().registerTest
|
||||
( makeTestCase
|
||||
( testCase,
|
||||
extractClassName( classOrQualifiedMethodName ),
|
||||
nameAndDesc.name,
|
||||
nameAndDesc.description,
|
||||
lineInfo ) );
|
||||
}
|
||||
void registerTestCaseFunction
|
||||
( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc ) {
|
||||
registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
|
||||
}
|
||||
|
||||
AutoReg::~AutoReg() {}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AutoReg::registerTestCase( ITestCase* testCase,
|
||||
char const* classOrQualifiedMethodName,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
|
||||
getMutableRegistryHub().registerTest
|
||||
( makeTestCase( testCase,
|
||||
extractClassName( classOrQualifiedMethodName ),
|
||||
nameAndDesc.name,
|
||||
nameAndDesc.description,
|
||||
lineInfo ) );
|
||||
AutoReg::AutoReg
|
||||
( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc ) {
|
||||
registerTestCaseFunction( function, lineInfo, nameAndDesc );
|
||||
}
|
||||
|
||||
AutoReg::~AutoReg() {}
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
|
||||
|
@ -11,71 +11,88 @@
|
||||
#include "catch_compiler_capabilities.h"
|
||||
#include "catch_ptr.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
|
||||
|
||||
namespace Catch {
|
||||
namespace TestCaseTracking {
|
||||
|
||||
struct NameAndLocation {
|
||||
std::string name;
|
||||
SourceLineInfo location;
|
||||
|
||||
NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
|
||||
: name( _name ),
|
||||
location( _location )
|
||||
{}
|
||||
};
|
||||
|
||||
struct ITracker : SharedImpl<> {
|
||||
virtual ~ITracker();
|
||||
|
||||
|
||||
// static queries
|
||||
virtual std::string name() const = 0;
|
||||
|
||||
virtual NameAndLocation const& nameAndLocation() const = 0;
|
||||
|
||||
// dynamic queries
|
||||
virtual bool isComplete() const = 0; // Successfully completed or failed
|
||||
virtual bool isSuccessfullyCompleted() const = 0;
|
||||
virtual bool isOpen() const = 0; // Started but not complete
|
||||
virtual bool hasChildren() const = 0;
|
||||
|
||||
|
||||
virtual ITracker& parent() = 0;
|
||||
|
||||
|
||||
// actions
|
||||
virtual void close() = 0; // Successfully complete
|
||||
virtual void fail() = 0;
|
||||
virtual void markAsNeedingAnotherRun() = 0;
|
||||
|
||||
|
||||
virtual void addChild( Ptr<ITracker> const& child ) = 0;
|
||||
virtual ITracker* findChild( std::string const& name ) = 0;
|
||||
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0;
|
||||
virtual void openChild() = 0;
|
||||
|
||||
// Debug/ checking
|
||||
virtual bool isSectionTracker() const = 0;
|
||||
virtual bool isIndexTracker() const = 0;
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
|
||||
|
||||
class TrackerContext {
|
||||
|
||||
enum RunState {
|
||||
NotStarted,
|
||||
Executing,
|
||||
CompletedCycle
|
||||
};
|
||||
|
||||
|
||||
Ptr<ITracker> m_rootTracker;
|
||||
ITracker* m_currentTracker;
|
||||
RunState m_runState;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static TrackerContext& instance() {
|
||||
static TrackerContext s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
||||
TrackerContext()
|
||||
: m_currentTracker( CATCH_NULL ),
|
||||
m_runState( NotStarted )
|
||||
{}
|
||||
|
||||
|
||||
|
||||
|
||||
ITracker& startRun();
|
||||
|
||||
|
||||
void endRun() {
|
||||
m_rootTracker.reset();
|
||||
m_currentTracker = CATCH_NULL;
|
||||
m_runState = NotStarted;
|
||||
}
|
||||
|
||||
|
||||
void startCycle() {
|
||||
m_currentTracker = m_rootTracker.get();
|
||||
m_runState = Executing;
|
||||
@ -83,7 +100,7 @@ namespace TestCaseTracking {
|
||||
void completeCycle() {
|
||||
m_runState = CompletedCycle;
|
||||
}
|
||||
|
||||
|
||||
bool completedCycle() const {
|
||||
return m_runState == CompletedCycle;
|
||||
}
|
||||
@ -94,7 +111,7 @@ namespace TestCaseTracking {
|
||||
m_currentTracker = tracker;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TrackerBase : public ITracker {
|
||||
protected:
|
||||
enum CycleState {
|
||||
@ -106,30 +123,32 @@ namespace TestCaseTracking {
|
||||
Failed
|
||||
};
|
||||
class TrackerHasName {
|
||||
std::string m_name;
|
||||
NameAndLocation m_nameAndLocation;
|
||||
public:
|
||||
TrackerHasName( std::string const& name ) : m_name( name ) {}
|
||||
TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
|
||||
bool operator ()( Ptr<ITracker> const& tracker ) {
|
||||
return tracker->name() == m_name;
|
||||
return
|
||||
tracker->nameAndLocation().name == m_nameAndLocation.name &&
|
||||
tracker->nameAndLocation().location == m_nameAndLocation.location;
|
||||
}
|
||||
};
|
||||
typedef std::vector<Ptr<ITracker> > Children;
|
||||
std::string m_name;
|
||||
NameAndLocation m_nameAndLocation;
|
||||
TrackerContext& m_ctx;
|
||||
ITracker* m_parent;
|
||||
Children m_children;
|
||||
CycleState m_runState;
|
||||
public:
|
||||
TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
||||
: m_name( name ),
|
||||
TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: m_nameAndLocation( nameAndLocation ),
|
||||
m_ctx( ctx ),
|
||||
m_parent( parent ),
|
||||
m_runState( NotStarted )
|
||||
{}
|
||||
virtual ~TrackerBase();
|
||||
|
||||
virtual std::string name() const CATCH_OVERRIDE {
|
||||
return m_name;
|
||||
|
||||
virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE {
|
||||
return m_nameAndLocation;
|
||||
}
|
||||
virtual bool isComplete() const CATCH_OVERRIDE {
|
||||
return m_runState == CompletedSuccessfully || m_runState == Failed;
|
||||
@ -143,14 +162,14 @@ namespace TestCaseTracking {
|
||||
virtual bool hasChildren() const CATCH_OVERRIDE {
|
||||
return !m_children.empty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE {
|
||||
m_children.push_back( child );
|
||||
}
|
||||
|
||||
virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE {
|
||||
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) );
|
||||
|
||||
virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE {
|
||||
Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
|
||||
return( it != m_children.end() )
|
||||
? it->get()
|
||||
: CATCH_NULL;
|
||||
@ -159,7 +178,7 @@ namespace TestCaseTracking {
|
||||
assert( m_parent ); // Should always be non-null except for root
|
||||
return *m_parent;
|
||||
}
|
||||
|
||||
|
||||
virtual void openChild() CATCH_OVERRIDE {
|
||||
if( m_runState != ExecutingChildren ) {
|
||||
m_runState = ExecutingChildren;
|
||||
@ -167,28 +186,32 @@ namespace TestCaseTracking {
|
||||
m_parent->openChild();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
|
||||
|
||||
void open() {
|
||||
m_runState = Executing;
|
||||
moveToThis();
|
||||
if( m_parent )
|
||||
m_parent->openChild();
|
||||
}
|
||||
|
||||
|
||||
virtual void close() CATCH_OVERRIDE {
|
||||
|
||||
|
||||
// Close any still open children (e.g. generators)
|
||||
while( &m_ctx.currentTracker() != this )
|
||||
m_ctx.currentTracker().close();
|
||||
|
||||
|
||||
switch( m_runState ) {
|
||||
case NotStarted:
|
||||
case CompletedSuccessfully:
|
||||
case Failed:
|
||||
throw std::logic_error( "Illogical state" );
|
||||
|
||||
|
||||
case NeedsAnotherRun:
|
||||
break;;
|
||||
|
||||
|
||||
case Executing:
|
||||
m_runState = CompletedSuccessfully;
|
||||
break;
|
||||
@ -196,7 +219,7 @@ namespace TestCaseTracking {
|
||||
if( m_children.empty() || m_children.back()->isComplete() )
|
||||
m_runState = CompletedSuccessfully;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw std::logic_error( "Unexpected state" );
|
||||
}
|
||||
@ -222,90 +245,120 @@ namespace TestCaseTracking {
|
||||
m_ctx.setCurrentTracker( this );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SectionTracker : public TrackerBase {
|
||||
std::vector<std::string> m_filters;
|
||||
public:
|
||||
SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( name, ctx, parent )
|
||||
{}
|
||||
SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||
: TrackerBase( nameAndLocation, ctx, parent )
|
||||
{
|
||||
if( parent ) {
|
||||
while( !parent->isSectionTracker() )
|
||||
parent = &parent->parent();
|
||||
|
||||
SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
|
||||
addNextFilters( parentSection.m_filters );
|
||||
}
|
||||
}
|
||||
virtual ~SectionTracker();
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
|
||||
SectionTracker* section = CATCH_NULL;
|
||||
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
section = dynamic_cast<SectionTracker*>( childTracker );
|
||||
assert( section );
|
||||
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isSectionTracker() );
|
||||
section = static_cast<SectionTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
section = new SectionTracker( name, ctx, ¤tTracker );
|
||||
section = new SectionTracker( nameAndLocation, ctx, ¤tTracker );
|
||||
currentTracker.addChild( section );
|
||||
}
|
||||
if( !ctx.completedCycle() && !section->isComplete() ) {
|
||||
|
||||
section->open();
|
||||
}
|
||||
if( !ctx.completedCycle() )
|
||||
section->tryOpen();
|
||||
return *section;
|
||||
}
|
||||
|
||||
void tryOpen() {
|
||||
if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
|
||||
open();
|
||||
}
|
||||
|
||||
void addInitialFilters( std::vector<std::string> const& filters ) {
|
||||
if( !filters.empty() ) {
|
||||
m_filters.push_back(""); // Root - should never be consulted
|
||||
m_filters.push_back(""); // Test Case - not a section filter
|
||||
m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
|
||||
}
|
||||
}
|
||||
void addNextFilters( std::vector<std::string> const& filters ) {
|
||||
if( filters.size() > 1 )
|
||||
m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class IndexTracker : public TrackerBase {
|
||||
int m_size;
|
||||
int m_index;
|
||||
public:
|
||||
IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( name, ctx, parent ),
|
||||
IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
|
||||
: TrackerBase( nameAndLocation, ctx, parent ),
|
||||
m_size( size ),
|
||||
m_index( -1 )
|
||||
{}
|
||||
virtual ~IndexTracker();
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
|
||||
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
|
||||
IndexTracker* tracker = CATCH_NULL;
|
||||
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
tracker = dynamic_cast<IndexTracker*>( childTracker );
|
||||
assert( tracker );
|
||||
if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
tracker = static_cast<IndexTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
tracker = new IndexTracker( name, ctx, ¤tTracker, size );
|
||||
tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size );
|
||||
currentTracker.addChild( tracker );
|
||||
}
|
||||
|
||||
|
||||
if( !ctx.completedCycle() && !tracker->isComplete() ) {
|
||||
if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun )
|
||||
tracker->moveNext();
|
||||
tracker->open();
|
||||
}
|
||||
|
||||
|
||||
return *tracker;
|
||||
}
|
||||
|
||||
|
||||
int index() const { return m_index; }
|
||||
|
||||
|
||||
void moveNext() {
|
||||
m_index++;
|
||||
m_children.clear();
|
||||
}
|
||||
|
||||
|
||||
virtual void close() CATCH_OVERRIDE {
|
||||
TrackerBase::close();
|
||||
if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
|
||||
m_runState = Executing;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline ITracker& TrackerContext::startRun() {
|
||||
m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL );
|
||||
m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL );
|
||||
m_currentTracker = CATCH_NULL;
|
||||
m_runState = Executing;
|
||||
return *m_rootTracker;
|
||||
}
|
||||
|
||||
|
||||
} // namespace TestCaseTracking
|
||||
|
||||
|
||||
using TestCaseTracking::ITracker;
|
||||
using TestCaseTracking::TrackerContext;
|
||||
using TestCaseTracking::SectionTracker;
|
||||
@ -313,4 +366,6 @@ using TestCaseTracking::IndexTracker;
|
||||
|
||||
} // namespace Catch
|
||||
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
|
||||
|
@ -42,27 +42,32 @@ struct NameAndDesc {
|
||||
const char* description;
|
||||
};
|
||||
|
||||
void registerTestCase
|
||||
( ITestCase* testCase,
|
||||
char const* className,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo );
|
||||
|
||||
struct AutoReg {
|
||||
|
||||
AutoReg( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc );
|
||||
AutoReg
|
||||
( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc );
|
||||
|
||||
template<typename C>
|
||||
AutoReg( void (C::*method)(),
|
||||
char const* className,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
registerTestCase( new MethodTestCase<C>( method ),
|
||||
className,
|
||||
nameAndDesc,
|
||||
lineInfo );
|
||||
}
|
||||
AutoReg
|
||||
( void (C::*method)(),
|
||||
char const* className,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo ) {
|
||||
|
||||
void registerTestCase( ITestCase* testCase,
|
||||
char const* className,
|
||||
NameAndDesc const& nameAndDesc,
|
||||
SourceLineInfo const& lineInfo );
|
||||
registerTestCase
|
||||
( new MethodTestCase<C>( method ),
|
||||
className,
|
||||
nameAndDesc,
|
||||
lineInfo );
|
||||
}
|
||||
|
||||
~AutoReg();
|
||||
|
||||
@ -71,49 +76,86 @@ private:
|
||||
void operator= ( AutoReg const& );
|
||||
};
|
||||
|
||||
void registerTestCaseFunction
|
||||
( TestFunction function,
|
||||
SourceLineInfo const& lineInfo,
|
||||
NameAndDesc const& nameAndDesc );
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
|
||||
static void TestName(); \
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( ... ) \
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ \
|
||||
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
||||
struct TestName : ClassName{ \
|
||||
void test(); \
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
||||
} \
|
||||
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
|
||||
void TestName::test()
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
|
||||
#else
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
|
||||
static void TestName(); \
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
namespace{ \
|
||||
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
||||
struct TestCaseName : ClassName{ \
|
||||
void test(); \
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
||||
} \
|
||||
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
|
||||
void TestCaseName::test()
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
|
||||
CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
|
||||
Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \
|
||||
CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
|
||||
class TestSpec {
|
||||
struct Pattern : SharedImpl<> {
|
||||
virtual ~Pattern();
|
||||
@ -38,7 +38,7 @@ namespace Catch {
|
||||
private:
|
||||
WildcardPattern m_wildcardPattern;
|
||||
};
|
||||
|
||||
|
||||
class TagPattern : public Pattern {
|
||||
public:
|
||||
TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
|
||||
@ -49,7 +49,7 @@ namespace Catch {
|
||||
private:
|
||||
std::string m_tag;
|
||||
};
|
||||
|
||||
|
||||
class ExcludedPattern : public Pattern {
|
||||
public:
|
||||
ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
|
||||
@ -64,10 +64,11 @@ namespace Catch {
|
||||
|
||||
bool matches( TestCaseInfo const& testCase ) const {
|
||||
// All patterns in a filter must match for the filter to be a match
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
|
||||
if( !(*it)->matches( testCase ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user